diff options
| -rw-r--r-- | .gitignore | 4 | ||||
| -rw-r--r-- | HACKING | 18 | ||||
| -rw-r--r-- | MAINTAINERS | 56 | ||||
| -rw-r--r-- | Makefile | 9 | ||||
| -rw-r--r-- | Makefile.objs | 11 | ||||
| -rw-r--r-- | Makefile.target | 5 | ||||
| -rw-r--r-- | VERSION | 2 | ||||
| -rw-r--r-- | aio-posix.c | 308 | ||||
| -rw-r--r-- | aio-win32.c | 32 | ||||
| -rw-r--r-- | async.c | 21 | ||||
| -rw-r--r-- | backends/cryptodev-builtin.c | 65 | ||||
| -rw-r--r-- | block/Makefile.objs | 6 | ||||
| -rw-r--r-- | block/blkdebug.c | 86 | ||||
| -rw-r--r-- | block/blkverify.c | 201 | ||||
| -rw-r--r-- | block/curl.c | 8 | ||||
| -rw-r--r-- | block/file-posix.c (renamed from block/raw-posix.c) | 0 | ||||
| -rw-r--r-- | block/file-win32.c (renamed from block/raw-win32.c) | 0 | ||||
| -rw-r--r-- | block/gluster.c | 4 | ||||
| -rw-r--r-- | block/iscsi.c | 3 | ||||
| -rw-r--r-- | block/linux-aio.c | 19 | ||||
| -rw-r--r-- | block/nbd-client.c | 8 | ||||
| -rw-r--r-- | block/nfs.c | 7 | ||||
| -rw-r--r-- | block/quorum.c | 410 | ||||
| -rw-r--r-- | block/raw-format.c (renamed from block/raw_bsd.c) | 2 | ||||
| -rw-r--r-- | block/sheepdog.c | 26 | ||||
| -rw-r--r-- | block/ssh.c | 4 | ||||
| -rw-r--r-- | block/trace-events | 4 | ||||
| -rw-r--r-- | block/win32-aio.c | 4 | ||||
| -rwxr-xr-x | configure | 21 | ||||
| -rw-r--r-- | crypto/Makefile.objs | 4 | ||||
| -rw-r--r-- | crypto/cipher-gcrypt.c | 6 | ||||
| -rw-r--r-- | crypto/cipher-nettle.c | 42 | ||||
| -rw-r--r-- | crypto/cipher.c | 7 | ||||
| -rw-r--r-- | crypto/hmac-gcrypt.c | 152 | ||||
| -rw-r--r-- | crypto/hmac-glib.c | 166 | ||||
| -rw-r--r-- | crypto/hmac-nettle.c | 175 | ||||
| -rw-r--r-- | crypto/hmac.c | 72 | ||||
| -rw-r--r-- | crypto/hmac.h | 166 | ||||
| -rw-r--r-- | disas/cris.c | 4 | ||||
| -rw-r--r-- | disas/m68k.c | 8 | ||||
| -rw-r--r-- | docs/replay.txt | 14 | ||||
| -rw-r--r-- | exec.c | 687 | ||||
| -rw-r--r-- | hw/9pfs/9p.c | 78 | ||||
| -rw-r--r-- | hw/9pfs/9p.h | 26 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-device.c | 46 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p.h | 10 | ||||
| -rw-r--r-- | hw/alpha/alpha_sys.h | 2 | ||||
| -rw-r--r-- | hw/arm/aspeed.c | 70 | ||||
| -rw-r--r-- | hw/arm/aspeed_soc.c | 95 | ||||
| -rw-r--r-- | hw/arm/pxa2xx.c | 13 | ||||
| -rw-r--r-- | hw/arm/strongarm.h | 2 | ||||
| -rw-r--r-- | hw/arm/tosa.c | 11 | ||||
| -rw-r--r-- | hw/arm/virt-acpi-build.c | 136 | ||||
| -rw-r--r-- | hw/arm/virt.c | 710 | ||||
| -rw-r--r-- | hw/arm/z2.c | 11 | ||||
| -rw-r--r-- | hw/audio/wm8750.c | 4 | ||||
| -rw-r--r-- | hw/block/m25p80.c | 30 | ||||
| -rw-r--r-- | hw/block/pflash_cfi01.c | 13 | ||||
| -rw-r--r-- | hw/block/pflash_cfi02.c | 13 | ||||
| -rw-r--r-- | hw/block/virtio-blk.c | 18 | ||||
| -rw-r--r-- | hw/char/cadence_uart.c | 14 | ||||
| -rw-r--r-- | hw/char/exynos4210_uart.c | 16 | ||||
| -rw-r--r-- | hw/display/ssd0303.c | 4 | ||||
| -rw-r--r-- | hw/display/virtio-gpu-3d.c | 13 | ||||
| -rw-r--r-- | hw/display/virtio-gpu.c | 24 | ||||
| -rw-r--r-- | hw/gpio/max7310.c | 4 | ||||
| -rw-r--r-- | hw/i2c/core.c | 37 | ||||
| -rw-r--r-- | hw/i2c/i2c-ddc.c | 4 | ||||
| -rw-r--r-- | hw/i2c/smbus.c | 13 | ||||
| -rw-r--r-- | hw/i386/acpi-build.c | 2 | ||||
| -rw-r--r-- | hw/i386/kvm/apic.c | 2 | ||||
| -rw-r--r-- | hw/i386/kvm/clock.c | 142 | ||||
| -rw-r--r-- | hw/i386/multiboot.c | 20 | ||||
| -rw-r--r-- | hw/i386/pc.c | 68 | ||||
| -rw-r--r-- | hw/i386/pc_piix.c | 2 | ||||
| -rw-r--r-- | hw/i386/pc_q35.c | 39 | ||||
| -rw-r--r-- | hw/input/lm832x.c | 4 | ||||
| -rw-r--r-- | hw/intc/arm_gicv3.c | 5 | ||||
| -rw-r--r-- | hw/intc/arm_gicv3_common.c | 3 | ||||
| -rw-r--r-- | hw/intc/arm_gicv3_cpuif.c | 13 | ||||
| -rw-r--r-- | hw/intc/ioapic.c | 2 | ||||
| -rw-r--r-- | hw/misc/aspeed_scu.c | 4 | ||||
| -rw-r--r-- | hw/misc/aspeed_sdmc.c | 3 | ||||
| -rw-r--r-- | hw/misc/hyperv_testdev.c | 2 | ||||
| -rw-r--r-- | hw/misc/tmp105.c | 3 | ||||
| -rw-r--r-- | hw/net/fsl_etsec/rings.c | 19 | ||||
| -rw-r--r-- | hw/net/rtl8139.c | 34 | ||||
| -rw-r--r-- | hw/ppc/fdt.c | 2 | ||||
| -rw-r--r-- | hw/ppc/pnv.c | 2 | ||||
| -rw-r--r-- | hw/ppc/pnv_core.c | 2 | ||||
| -rw-r--r-- | hw/ppc/pnv_lpc.c | 2 | ||||
| -rw-r--r-- | hw/ppc/pnv_xscom.c | 2 | ||||
| -rw-r--r-- | hw/ppc/spapr_cpu_core.c | 6 | ||||
| -rw-r--r-- | hw/scsi/scsi-disk.c | 9 | ||||
| -rw-r--r-- | hw/scsi/virtio-scsi.c | 63 | ||||
| -rw-r--r-- | hw/sh4/shix.c | 2 | ||||
| -rw-r--r-- | hw/ssi/aspeed_smc.c | 17 | ||||
| -rw-r--r-- | hw/ssi/imx_spi.c | 11 | ||||
| -rw-r--r-- | hw/timer/ds1338.c | 10 | ||||
| -rw-r--r-- | hw/timer/twl92230.c | 4 | ||||
| -rw-r--r-- | hw/virtio/virtio.c | 54 | ||||
| -rw-r--r-- | hw/watchdog/wdt_i6300esb.c | 9 | ||||
| -rw-r--r-- | include/block/aio.h | 57 | ||||
| -rw-r--r-- | include/block/block_int.h | 2 | ||||
| -rw-r--r-- | include/exec/cpu-all.h | 23 | ||||
| -rw-r--r-- | include/exec/cpu-common.h | 15 | ||||
| -rw-r--r-- | include/exec/memory.h | 166 | ||||
| -rw-r--r-- | include/hw/acpi/acpi-defs.h | 33 | ||||
| -rw-r--r-- | include/hw/arm/arm.h | 2 | ||||
| -rw-r--r-- | include/hw/arm/aspeed_soc.h | 4 | ||||
| -rw-r--r-- | include/hw/arm/exynos4210.h | 2 | ||||
| -rw-r--r-- | include/hw/arm/omap.h | 2 | ||||
| -rw-r--r-- | include/hw/arm/pxa.h | 2 | ||||
| -rw-r--r-- | include/hw/arm/virt-acpi-build.h | 47 | ||||
| -rw-r--r-- | include/hw/arm/virt.h | 41 | ||||
| -rw-r--r-- | include/hw/compat.h | 3 | ||||
| -rw-r--r-- | include/hw/i2c/i2c.h | 16 | ||||
| -rw-r--r-- | include/hw/i386/pc.h | 12 | ||||
| -rw-r--r-- | include/hw/m68k/mcf.h | 2 | ||||
| -rw-r--r-- | include/hw/mips/cpudevs.h | 2 | ||||
| -rw-r--r-- | include/hw/misc/aspeed_scu.h | 1 | ||||
| -rw-r--r-- | include/hw/ppc/fdt.h | 2 | ||||
| -rw-r--r-- | include/hw/ppc/ppc.h | 2 | ||||
| -rw-r--r-- | include/hw/ppc/spapr_cpu_core.h | 2 | ||||
| -rw-r--r-- | include/hw/sh4/sh.h | 2 | ||||
| -rw-r--r-- | include/hw/virtio/virtio-gpu.h | 3 | ||||
| -rw-r--r-- | include/qemu/coroutine.h | 6 | ||||
| -rw-r--r-- | include/qemu/main-loop.h | 4 | ||||
| -rw-r--r-- | include/qemu/timer.h | 2 | ||||
| -rw-r--r-- | include/qemu/typedefs.h | 1 | ||||
| -rw-r--r-- | include/standard-headers/linux/input.h | 1 | ||||
| -rw-r--r-- | include/standard-headers/linux/pci_regs.h | 15 | ||||
| -rw-r--r-- | include/sysemu/iothread.h | 5 | ||||
| -rw-r--r-- | include/sysemu/replay.h | 12 | ||||
| -rw-r--r-- | iohandler.c | 2 | ||||
| -rw-r--r-- | iothread.c | 84 | ||||
| -rw-r--r-- | linux-headers/asm-arm/kvm.h | 7 | ||||
| -rw-r--r-- | linux-headers/asm-x86/unistd_32.h | 3 | ||||
| -rw-r--r-- | linux-headers/asm-x86/unistd_64.h | 3 | ||||
| -rw-r--r-- | linux-headers/asm-x86/unistd_x32.h | 3 | ||||
| -rw-r--r-- | linux-headers/linux/kvm.h | 7 | ||||
| -rw-r--r-- | linux-user/main.c | 7 | ||||
| -rw-r--r-- | memory_ldst.inc.c | 709 | ||||
| -rw-r--r-- | nbd/server.c | 9 | ||||
| -rw-r--r-- | net/Makefile.objs | 1 | ||||
| -rw-r--r-- | net/filter-replay.c | 92 | ||||
| -rw-r--r-- | qapi/crypto.json | 3 | ||||
| -rw-r--r-- | qemu-img.c | 17 | ||||
| -rw-r--r-- | qemu-timer.c | 20 | ||||
| -rw-r--r-- | replay/Makefile.objs | 1 | ||||
| -rw-r--r-- | replay/replay-events.c | 11 | ||||
| -rw-r--r-- | replay/replay-internal.h | 10 | ||||
| -rw-r--r-- | replay/replay-net.c | 102 | ||||
| -rw-r--r-- | replay/replay.c | 2 | ||||
| -rw-r--r-- | rules.mak | 26 | ||||
| -rw-r--r-- | scripts/analyze-inclusions | 8 | ||||
| -rw-r--r-- | slirp/dhcpv6.c | 2 | ||||
| -rw-r--r-- | slirp/ip6_icmp.c | 2 | ||||
| -rw-r--r-- | slirp/slirp.c | 2 | ||||
| -rw-r--r-- | slirp/slirp.h | 5 | ||||
| -rw-r--r-- | slirp/tcp_input.c | 16 | ||||
| -rw-r--r-- | slirp/tcp_output.c | 6 | ||||
| -rw-r--r-- | slirp/tcp_timer.c | 2 | ||||
| -rw-r--r-- | slirp/tcpip.h | 2 | ||||
| -rw-r--r-- | slirp/tftp.c | 26 | ||||
| -rw-r--r-- | slirp/tftp.h | 8 | ||||
| -rw-r--r-- | stubs/set-fd-handler.c | 1 | ||||
| -rw-r--r-- | target-m68k/op_helper.c | 229 | ||||
| -rw-r--r-- | target/alpha/Makefile.objs (renamed from target-alpha/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/alpha/STATUS (renamed from target-alpha/STATUS) | 0 | ||||
| -rw-r--r-- | target/alpha/cpu-qom.h (renamed from target-alpha/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/alpha/cpu.c (renamed from target-alpha/cpu.c) | 0 | ||||
| -rw-r--r-- | target/alpha/cpu.h (renamed from target-alpha/cpu.h) | 0 | ||||
| -rw-r--r-- | target/alpha/fpu_helper.c (renamed from target-alpha/fpu_helper.c) | 0 | ||||
| -rw-r--r-- | target/alpha/gdbstub.c (renamed from target-alpha/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/alpha/helper.c (renamed from target-alpha/helper.c) | 0 | ||||
| -rw-r--r-- | target/alpha/helper.h (renamed from target-alpha/helper.h) | 0 | ||||
| -rw-r--r-- | target/alpha/int_helper.c (renamed from target-alpha/int_helper.c) | 0 | ||||
| -rw-r--r-- | target/alpha/machine.c (renamed from target-alpha/machine.c) | 0 | ||||
| -rw-r--r-- | target/alpha/mem_helper.c (renamed from target-alpha/mem_helper.c) | 0 | ||||
| -rw-r--r-- | target/alpha/sys_helper.c (renamed from target-alpha/sys_helper.c) | 0 | ||||
| -rw-r--r-- | target/alpha/translate.c (renamed from target-alpha/translate.c) | 0 | ||||
| -rw-r--r-- | target/alpha/vax_helper.c (renamed from target-alpha/vax_helper.c) | 0 | ||||
| -rw-r--r-- | target/arm/Makefile.objs (renamed from target-arm/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/arm/arch_dump.c (renamed from target-arm/arch_dump.c) | 0 | ||||
| -rw-r--r-- | target/arm/arm-powerctl.c (renamed from target-arm/arm-powerctl.c) | 0 | ||||
| -rw-r--r-- | target/arm/arm-powerctl.h (renamed from target-arm/arm-powerctl.h) | 0 | ||||
| -rw-r--r-- | target/arm/arm-semi.c (renamed from target-arm/arm-semi.c) | 0 | ||||
| -rw-r--r-- | target/arm/arm_ldst.h (renamed from target-arm/arm_ldst.h) | 0 | ||||
| -rw-r--r-- | target/arm/cpu-qom.h (renamed from target-arm/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/arm/cpu.c (renamed from target-arm/cpu.c) | 11 | ||||
| -rw-r--r-- | target/arm/cpu.h (renamed from target-arm/cpu.h) | 1 | ||||
| -rw-r--r-- | target/arm/cpu64.c (renamed from target-arm/cpu64.c) | 0 | ||||
| -rw-r--r-- | target/arm/crypto_helper.c (renamed from target-arm/crypto_helper.c) | 0 | ||||
| -rw-r--r-- | target/arm/gdbstub.c (renamed from target-arm/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/arm/gdbstub64.c (renamed from target-arm/gdbstub64.c) | 0 | ||||
| -rw-r--r-- | target/arm/helper-a64.c (renamed from target-arm/helper-a64.c) | 0 | ||||
| -rw-r--r-- | target/arm/helper-a64.h (renamed from target-arm/helper-a64.h) | 0 | ||||
| -rw-r--r-- | target/arm/helper.c (renamed from target-arm/helper.c) | 19 | ||||
| -rw-r--r-- | target/arm/helper.h (renamed from target-arm/helper.h) | 0 | ||||
| -rw-r--r-- | target/arm/internals.h (renamed from target-arm/internals.h) | 2 | ||||
| -rw-r--r-- | target/arm/iwmmxt_helper.c (renamed from target-arm/iwmmxt_helper.c) | 0 | ||||
| -rw-r--r-- | target/arm/kvm-consts.h (renamed from target-arm/kvm-consts.h) | 0 | ||||
| -rw-r--r-- | target/arm/kvm-stub.c (renamed from target-arm/kvm-stub.c) | 0 | ||||
| -rw-r--r-- | target/arm/kvm.c (renamed from target-arm/kvm.c) | 0 | ||||
| -rw-r--r-- | target/arm/kvm32.c (renamed from target-arm/kvm32.c) | 0 | ||||
| -rw-r--r-- | target/arm/kvm64.c (renamed from target-arm/kvm64.c) | 0 | ||||
| -rw-r--r-- | target/arm/kvm_arm.h (renamed from target-arm/kvm_arm.h) | 0 | ||||
| -rw-r--r-- | target/arm/machine.c (renamed from target-arm/machine.c) | 0 | ||||
| -rw-r--r-- | target/arm/monitor.c (renamed from target-arm/monitor.c) | 0 | ||||
| -rw-r--r-- | target/arm/neon_helper.c (renamed from target-arm/neon_helper.c) | 0 | ||||
| -rw-r--r-- | target/arm/op_addsub.h (renamed from target-arm/op_addsub.h) | 0 | ||||
| -rw-r--r-- | target/arm/op_helper.c (renamed from target-arm/op_helper.c) | 9 | ||||
| -rw-r--r-- | target/arm/psci.c (renamed from target-arm/psci.c) | 0 | ||||
| -rw-r--r-- | target/arm/trace-events (renamed from target-arm/trace-events) | 2 | ||||
| -rw-r--r-- | target/arm/translate-a64.c (renamed from target-arm/translate-a64.c) | 7 | ||||
| -rw-r--r-- | target/arm/translate.c (renamed from target-arm/translate.c) | 0 | ||||
| -rw-r--r-- | target/arm/translate.h (renamed from target-arm/translate.h) | 0 | ||||
| -rw-r--r-- | target/cris/Makefile.objs (renamed from target-cris/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/cris/cpu-qom.h (renamed from target-cris/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/cris/cpu.c (renamed from target-cris/cpu.c) | 0 | ||||
| -rw-r--r-- | target/cris/cpu.h (renamed from target-cris/cpu.h) | 0 | ||||
| -rw-r--r-- | target/cris/crisv10-decode.h (renamed from target-cris/crisv10-decode.h) | 0 | ||||
| -rw-r--r-- | target/cris/crisv32-decode.h (renamed from target-cris/crisv32-decode.h) | 0 | ||||
| -rw-r--r-- | target/cris/gdbstub.c (renamed from target-cris/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/cris/helper.c (renamed from target-cris/helper.c) | 0 | ||||
| -rw-r--r-- | target/cris/helper.h (renamed from target-cris/helper.h) | 0 | ||||
| -rw-r--r-- | target/cris/machine.c (renamed from target-cris/machine.c) | 0 | ||||
| -rw-r--r-- | target/cris/mmu.c (renamed from target-cris/mmu.c) | 0 | ||||
| -rw-r--r-- | target/cris/mmu.h (renamed from target-cris/mmu.h) | 0 | ||||
| -rw-r--r-- | target/cris/op_helper.c (renamed from target-cris/op_helper.c) | 0 | ||||
| -rw-r--r-- | target/cris/opcode-cris.h (renamed from target-cris/opcode-cris.h) | 0 | ||||
| -rw-r--r-- | target/cris/translate.c (renamed from target-cris/translate.c) | 0 | ||||
| -rw-r--r-- | target/cris/translate_v10.c (renamed from target-cris/translate_v10.c) | 0 | ||||
| -rw-r--r-- | target/i386/Makefile.objs (renamed from target-i386/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/i386/TODO (renamed from target-i386/TODO) | 0 | ||||
| -rw-r--r-- | target/i386/arch_dump.c (renamed from target-i386/arch_dump.c) | 0 | ||||
| -rw-r--r-- | target/i386/arch_memory_mapping.c (renamed from target-i386/arch_memory_mapping.c) | 42 | ||||
| -rw-r--r-- | target/i386/bpt_helper.c (renamed from target-i386/bpt_helper.c) | 7 | ||||
| -rw-r--r-- | target/i386/cc_helper.c (renamed from target-i386/cc_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/cc_helper_template.h (renamed from target-i386/cc_helper_template.h) | 0 | ||||
| -rw-r--r-- | target/i386/cpu-qom.h (renamed from target-i386/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/i386/cpu.c (renamed from target-i386/cpu.c) | 18 | ||||
| -rw-r--r-- | target/i386/cpu.h (renamed from target-i386/cpu.h) | 3 | ||||
| -rw-r--r-- | target/i386/excp_helper.c (renamed from target-i386/excp_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/fpu_helper.c (renamed from target-i386/fpu_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/gdbstub.c (renamed from target-i386/gdbstub.c) | 52 | ||||
| -rw-r--r-- | target/i386/helper.c (renamed from target-i386/helper.c) | 54 | ||||
| -rw-r--r-- | target/i386/helper.h (renamed from target-i386/helper.h) | 1 | ||||
| -rw-r--r-- | target/i386/hyperv.c (renamed from target-i386/hyperv.c) | 0 | ||||
| -rw-r--r-- | target/i386/hyperv.h (renamed from target-i386/hyperv.h) | 0 | ||||
| -rw-r--r-- | target/i386/int_helper.c (renamed from target-i386/int_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/kvm-stub.c (renamed from target-i386/kvm-stub.c) | 0 | ||||
| -rw-r--r-- | target/i386/kvm.c (renamed from target-i386/kvm.c) | 7 | ||||
| -rw-r--r-- | target/i386/kvm_i386.h (renamed from target-i386/kvm_i386.h) | 1 | ||||
| -rw-r--r-- | target/i386/machine.c (renamed from target-i386/machine.c) | 0 | ||||
| -rw-r--r-- | target/i386/mem_helper.c (renamed from target-i386/mem_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/misc_helper.c (renamed from target-i386/misc_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/monitor.c (renamed from target-i386/monitor.c) | 234 | ||||
| -rw-r--r-- | target/i386/mpx_helper.c (renamed from target-i386/mpx_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/ops_sse.h (renamed from target-i386/ops_sse.h) | 0 | ||||
| -rw-r--r-- | target/i386/ops_sse_header.h (renamed from target-i386/ops_sse_header.h) | 0 | ||||
| -rw-r--r-- | target/i386/seg_helper.c (renamed from target-i386/seg_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/shift_helper_template.h (renamed from target-i386/shift_helper_template.h) | 0 | ||||
| -rw-r--r-- | target/i386/smm_helper.c (renamed from target-i386/smm_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/svm.h (renamed from target-i386/svm.h) | 0 | ||||
| -rw-r--r-- | target/i386/svm_helper.c (renamed from target-i386/svm_helper.c) | 0 | ||||
| -rw-r--r-- | target/i386/trace-events (renamed from target-i386/trace-events) | 2 | ||||
| -rw-r--r-- | target/i386/translate.c (renamed from target-i386/translate.c) | 29 | ||||
| -rw-r--r-- | target/lm32/Makefile.objs (renamed from target-lm32/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/lm32/README (renamed from target-lm32/README) | 0 | ||||
| -rw-r--r-- | target/lm32/TODO (renamed from target-lm32/TODO) | 0 | ||||
| -rw-r--r-- | target/lm32/cpu-qom.h (renamed from target-lm32/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/lm32/cpu.c (renamed from target-lm32/cpu.c) | 0 | ||||
| -rw-r--r-- | target/lm32/cpu.h (renamed from target-lm32/cpu.h) | 0 | ||||
| -rw-r--r-- | target/lm32/gdbstub.c (renamed from target-lm32/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/lm32/helper.c (renamed from target-lm32/helper.c) | 0 | ||||
| -rw-r--r-- | target/lm32/helper.h (renamed from target-lm32/helper.h) | 0 | ||||
| -rw-r--r-- | target/lm32/lm32-semi.c (renamed from target-lm32/lm32-semi.c) | 2 | ||||
| -rw-r--r-- | target/lm32/machine.c (renamed from target-lm32/machine.c) | 0 | ||||
| -rw-r--r-- | target/lm32/op_helper.c (renamed from target-lm32/op_helper.c) | 0 | ||||
| -rw-r--r-- | target/lm32/translate.c (renamed from target-lm32/translate.c) | 0 | ||||
| -rw-r--r-- | target/m68k/Makefile.objs (renamed from target-m68k/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/m68k/cpu-qom.h (renamed from target-m68k/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/m68k/cpu.c (renamed from target-m68k/cpu.c) | 0 | ||||
| -rw-r--r-- | target/m68k/cpu.h (renamed from target-m68k/cpu.h) | 4 | ||||
| -rw-r--r-- | target/m68k/gdbstub.c (renamed from target-m68k/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/m68k/helper.c (renamed from target-m68k/helper.c) | 52 | ||||
| -rw-r--r-- | target/m68k/helper.h (renamed from target-m68k/helper.h) | 13 | ||||
| -rw-r--r-- | target/m68k/m68k-semi.c (renamed from target-m68k/m68k-semi.c) | 0 | ||||
| -rw-r--r-- | target/m68k/op_helper.c | 471 | ||||
| -rw-r--r-- | target/m68k/qregs.def (renamed from target-m68k/qregs.def) | 2 | ||||
| -rw-r--r-- | target/m68k/translate.c (renamed from target-m68k/translate.c) | 1518 | ||||
| -rw-r--r-- | target/microblaze/Makefile.objs (renamed from target-microblaze/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/microblaze/cpu-qom.h (renamed from target-microblaze/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/microblaze/cpu.c (renamed from target-microblaze/cpu.c) | 0 | ||||
| -rw-r--r-- | target/microblaze/cpu.h (renamed from target-microblaze/cpu.h) | 0 | ||||
| -rw-r--r-- | target/microblaze/gdbstub.c (renamed from target-microblaze/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/microblaze/helper.c (renamed from target-microblaze/helper.c) | 0 | ||||
| -rw-r--r-- | target/microblaze/helper.h (renamed from target-microblaze/helper.h) | 0 | ||||
| -rw-r--r-- | target/microblaze/microblaze-decode.h (renamed from target-microblaze/microblaze-decode.h) | 0 | ||||
| -rw-r--r-- | target/microblaze/mmu.c (renamed from target-microblaze/mmu.c) | 0 | ||||
| -rw-r--r-- | target/microblaze/mmu.h (renamed from target-microblaze/mmu.h) | 0 | ||||
| -rw-r--r-- | target/microblaze/op_helper.c (renamed from target-microblaze/op_helper.c) | 0 | ||||
| -rw-r--r-- | target/microblaze/translate.c (renamed from target-microblaze/translate.c) | 0 | ||||
| -rw-r--r-- | target/mips/Makefile.objs (renamed from target-mips/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/mips/TODO (renamed from target-mips/TODO) | 0 | ||||
| -rw-r--r-- | target/mips/cpu-qom.h (renamed from target-mips/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/mips/cpu.c (renamed from target-mips/cpu.c) | 0 | ||||
| -rw-r--r-- | target/mips/cpu.h (renamed from target-mips/cpu.h) | 0 | ||||
| -rw-r--r-- | target/mips/dsp_helper.c (renamed from target-mips/dsp_helper.c) | 0 | ||||
| -rw-r--r-- | target/mips/gdbstub.c (renamed from target-mips/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/mips/helper.c (renamed from target-mips/helper.c) | 0 | ||||
| -rw-r--r-- | target/mips/helper.h (renamed from target-mips/helper.h) | 0 | ||||
| -rw-r--r-- | target/mips/kvm.c (renamed from target-mips/kvm.c) | 0 | ||||
| -rw-r--r-- | target/mips/kvm_mips.h (renamed from target-mips/kvm_mips.h) | 0 | ||||
| -rw-r--r-- | target/mips/lmi_helper.c (renamed from target-mips/lmi_helper.c) | 0 | ||||
| -rw-r--r-- | target/mips/machine.c (renamed from target-mips/machine.c) | 0 | ||||
| -rw-r--r-- | target/mips/mips-defs.h (renamed from target-mips/mips-defs.h) | 0 | ||||
| -rw-r--r-- | target/mips/mips-semi.c (renamed from target-mips/mips-semi.c) | 0 | ||||
| -rw-r--r-- | target/mips/msa_helper.c (renamed from target-mips/msa_helper.c) | 0 | ||||
| -rw-r--r-- | target/mips/op_helper.c (renamed from target-mips/op_helper.c) | 0 | ||||
| -rw-r--r-- | target/mips/translate.c (renamed from target-mips/translate.c) | 0 | ||||
| -rw-r--r-- | target/mips/translate_init.c (renamed from target-mips/translate_init.c) | 0 | ||||
| -rw-r--r-- | target/moxie/Makefile.objs (renamed from target-moxie/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/moxie/cpu.c (renamed from target-moxie/cpu.c) | 0 | ||||
| -rw-r--r-- | target/moxie/cpu.h (renamed from target-moxie/cpu.h) | 0 | ||||
| -rw-r--r-- | target/moxie/helper.c (renamed from target-moxie/helper.c) | 0 | ||||
| -rw-r--r-- | target/moxie/helper.h (renamed from target-moxie/helper.h) | 0 | ||||
| -rw-r--r-- | target/moxie/machine.c (renamed from target-moxie/machine.c) | 0 | ||||
| -rw-r--r-- | target/moxie/machine.h (renamed from target-moxie/machine.h) | 0 | ||||
| -rw-r--r-- | target/moxie/mmu.c (renamed from target-moxie/mmu.c) | 0 | ||||
| -rw-r--r-- | target/moxie/mmu.h (renamed from target-moxie/mmu.h) | 0 | ||||
| -rw-r--r-- | target/moxie/translate.c (renamed from target-moxie/translate.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/Makefile.objs (renamed from target-openrisc/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/openrisc/cpu.c (renamed from target-openrisc/cpu.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/cpu.h (renamed from target-openrisc/cpu.h) | 0 | ||||
| -rw-r--r-- | target/openrisc/exception.c (renamed from target-openrisc/exception.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/exception.h (renamed from target-openrisc/exception.h) | 0 | ||||
| -rw-r--r-- | target/openrisc/exception_helper.c (renamed from target-openrisc/exception_helper.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/fpu_helper.c (renamed from target-openrisc/fpu_helper.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/gdbstub.c (renamed from target-openrisc/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/helper.h (renamed from target-openrisc/helper.h) | 0 | ||||
| -rw-r--r-- | target/openrisc/int_helper.c (renamed from target-openrisc/int_helper.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/interrupt.c (renamed from target-openrisc/interrupt.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/interrupt_helper.c (renamed from target-openrisc/interrupt_helper.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/machine.c (renamed from target-openrisc/machine.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/mmu.c (renamed from target-openrisc/mmu.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/mmu_helper.c (renamed from target-openrisc/mmu_helper.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/sys_helper.c (renamed from target-openrisc/sys_helper.c) | 0 | ||||
| -rw-r--r-- | target/openrisc/translate.c (renamed from target-openrisc/translate.c) | 0 | ||||
| -rw-r--r-- | target/ppc/Makefile.objs (renamed from target-ppc/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/ppc/STATUS (renamed from target-ppc/STATUS) | 0 | ||||
| -rw-r--r-- | target/ppc/arch_dump.c (renamed from target-ppc/arch_dump.c) | 0 | ||||
| -rw-r--r-- | target/ppc/cpu-models.c (renamed from target-ppc/cpu-models.c) | 0 | ||||
| -rw-r--r-- | target/ppc/cpu-models.h (renamed from target-ppc/cpu-models.h) | 0 | ||||
| -rw-r--r-- | target/ppc/cpu-qom.h (renamed from target-ppc/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/ppc/cpu.h (renamed from target-ppc/cpu.h) | 0 | ||||
| -rw-r--r-- | target/ppc/dfp_helper.c (renamed from target-ppc/dfp_helper.c) | 0 | ||||
| -rw-r--r-- | target/ppc/excp_helper.c (renamed from target-ppc/excp_helper.c) | 0 | ||||
| -rw-r--r-- | target/ppc/fpu_helper.c (renamed from target-ppc/fpu_helper.c) | 0 | ||||
| -rw-r--r-- | target/ppc/gdbstub.c (renamed from target-ppc/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/ppc/helper.h (renamed from target-ppc/helper.h) | 0 | ||||
| -rw-r--r-- | target/ppc/helper_regs.h (renamed from target-ppc/helper_regs.h) | 0 | ||||
| -rw-r--r-- | target/ppc/int_helper.c (renamed from target-ppc/int_helper.c) | 0 | ||||
| -rw-r--r-- | target/ppc/internal.h (renamed from target-ppc/internal.h) | 0 | ||||
| -rw-r--r-- | target/ppc/kvm-stub.c (renamed from target-ppc/kvm-stub.c) | 0 | ||||
| -rw-r--r-- | target/ppc/kvm.c (renamed from target-ppc/kvm.c) | 0 | ||||
| -rw-r--r-- | target/ppc/kvm_ppc.h (renamed from target-ppc/kvm_ppc.h) | 0 | ||||
| -rw-r--r-- | target/ppc/machine.c (renamed from target-ppc/machine.c) | 0 | ||||
| -rw-r--r-- | target/ppc/mem_helper.c (renamed from target-ppc/mem_helper.c) | 0 | ||||
| -rw-r--r-- | target/ppc/mfrom_table.c (renamed from target-ppc/mfrom_table.c) | 0 | ||||
| -rw-r--r-- | target/ppc/mfrom_table_gen.c (renamed from target-ppc/mfrom_table_gen.c) | 0 | ||||
| -rw-r--r-- | target/ppc/misc_helper.c (renamed from target-ppc/misc_helper.c) | 0 | ||||
| -rw-r--r-- | target/ppc/mmu-hash32.c (renamed from target-ppc/mmu-hash32.c) | 0 | ||||
| -rw-r--r-- | target/ppc/mmu-hash32.h (renamed from target-ppc/mmu-hash32.h) | 0 | ||||
| -rw-r--r-- | target/ppc/mmu-hash64.c (renamed from target-ppc/mmu-hash64.c) | 0 | ||||
| -rw-r--r-- | target/ppc/mmu-hash64.h (renamed from target-ppc/mmu-hash64.h) | 0 | ||||
| -rw-r--r-- | target/ppc/mmu_helper.c (renamed from target-ppc/mmu_helper.c) | 0 | ||||
| -rw-r--r-- | target/ppc/monitor.c (renamed from target-ppc/monitor.c) | 0 | ||||
| -rw-r--r-- | target/ppc/timebase_helper.c (renamed from target-ppc/timebase_helper.c) | 0 | ||||
| -rw-r--r-- | target/ppc/trace-events (renamed from target-ppc/trace-events) | 2 | ||||
| -rw-r--r-- | target/ppc/translate.c (renamed from target-ppc/translate.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/dfp-impl.inc.c (renamed from target-ppc/translate/dfp-impl.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/dfp-ops.inc.c (renamed from target-ppc/translate/dfp-ops.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/fp-impl.inc.c (renamed from target-ppc/translate/fp-impl.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/fp-ops.inc.c (renamed from target-ppc/translate/fp-ops.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/spe-impl.inc.c (renamed from target-ppc/translate/spe-impl.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/spe-ops.inc.c (renamed from target-ppc/translate/spe-ops.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/vmx-impl.inc.c (renamed from target-ppc/translate/vmx-impl.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/vmx-ops.inc.c (renamed from target-ppc/translate/vmx-ops.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/vsx-impl.inc.c (renamed from target-ppc/translate/vsx-impl.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate/vsx-ops.inc.c (renamed from target-ppc/translate/vsx-ops.inc.c) | 0 | ||||
| -rw-r--r-- | target/ppc/translate_init.c (renamed from target-ppc/translate_init.c) | 0 | ||||
| -rw-r--r-- | target/ppc/user_only_helper.c (renamed from target-ppc/user_only_helper.c) | 0 | ||||
| -rw-r--r-- | target/s390x/Makefile.objs (renamed from target-s390x/Makefile.objs) | 2 | ||||
| -rw-r--r-- | target/s390x/arch_dump.c (renamed from target-s390x/arch_dump.c) | 0 | ||||
| -rw-r--r-- | target/s390x/cc_helper.c (renamed from target-s390x/cc_helper.c) | 0 | ||||
| -rw-r--r-- | target/s390x/cpu-qom.h (renamed from target-s390x/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/s390x/cpu.c (renamed from target-s390x/cpu.c) | 0 | ||||
| -rw-r--r-- | target/s390x/cpu.h (renamed from target-s390x/cpu.h) | 0 | ||||
| -rw-r--r-- | target/s390x/cpu_features.c (renamed from target-s390x/cpu_features.c) | 0 | ||||
| -rw-r--r-- | target/s390x/cpu_features.h (renamed from target-s390x/cpu_features.h) | 0 | ||||
| -rw-r--r-- | target/s390x/cpu_features_def.h (renamed from target-s390x/cpu_features_def.h) | 0 | ||||
| -rw-r--r-- | target/s390x/cpu_models.c (renamed from target-s390x/cpu_models.c) | 0 | ||||
| -rw-r--r-- | target/s390x/cpu_models.h (renamed from target-s390x/cpu_models.h) | 0 | ||||
| -rw-r--r-- | target/s390x/fpu_helper.c (renamed from target-s390x/fpu_helper.c) | 0 | ||||
| -rw-r--r-- | target/s390x/gdbstub.c (renamed from target-s390x/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/s390x/gen-features.c (renamed from target-s390x/gen-features.c) | 0 | ||||
| -rw-r--r-- | target/s390x/helper.c (renamed from target-s390x/helper.c) | 0 | ||||
| -rw-r--r-- | target/s390x/helper.h (renamed from target-s390x/helper.h) | 0 | ||||
| -rw-r--r-- | target/s390x/insn-data.def (renamed from target-s390x/insn-data.def) | 0 | ||||
| -rw-r--r-- | target/s390x/insn-format.def (renamed from target-s390x/insn-format.def) | 0 | ||||
| -rw-r--r-- | target/s390x/int_helper.c (renamed from target-s390x/int_helper.c) | 0 | ||||
| -rw-r--r-- | target/s390x/interrupt.c (renamed from target-s390x/interrupt.c) | 0 | ||||
| -rw-r--r-- | target/s390x/ioinst.c (renamed from target-s390x/ioinst.c) | 0 | ||||
| -rw-r--r-- | target/s390x/kvm.c (renamed from target-s390x/kvm.c) | 0 | ||||
| -rw-r--r-- | target/s390x/machine.c (renamed from target-s390x/machine.c) | 0 | ||||
| -rw-r--r-- | target/s390x/mem_helper.c (renamed from target-s390x/mem_helper.c) | 0 | ||||
| -rw-r--r-- | target/s390x/misc_helper.c (renamed from target-s390x/misc_helper.c) | 0 | ||||
| -rw-r--r-- | target/s390x/mmu_helper.c (renamed from target-s390x/mmu_helper.c) | 0 | ||||
| -rw-r--r-- | target/s390x/trace-events (renamed from target-s390x/trace-events) | 8 | ||||
| -rw-r--r-- | target/s390x/translate.c (renamed from target-s390x/translate.c) | 0 | ||||
| -rw-r--r-- | target/sh4/Makefile.objs (renamed from target-sh4/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/sh4/README.sh4 (renamed from target-sh4/README.sh4) | 2 | ||||
| -rw-r--r-- | target/sh4/cpu-qom.h (renamed from target-sh4/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/sh4/cpu.c (renamed from target-sh4/cpu.c) | 0 | ||||
| -rw-r--r-- | target/sh4/cpu.h (renamed from target-sh4/cpu.h) | 0 | ||||
| -rw-r--r-- | target/sh4/gdbstub.c (renamed from target-sh4/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/sh4/helper.c (renamed from target-sh4/helper.c) | 0 | ||||
| -rw-r--r-- | target/sh4/helper.h (renamed from target-sh4/helper.h) | 0 | ||||
| -rw-r--r-- | target/sh4/monitor.c (renamed from target-sh4/monitor.c) | 0 | ||||
| -rw-r--r-- | target/sh4/op_helper.c (renamed from target-sh4/op_helper.c) | 0 | ||||
| -rw-r--r-- | target/sh4/translate.c (renamed from target-sh4/translate.c) | 0 | ||||
| -rw-r--r-- | target/sparc/Makefile.objs (renamed from target-sparc/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/sparc/TODO (renamed from target-sparc/TODO) | 0 | ||||
| -rw-r--r-- | target/sparc/asi.h (renamed from target-sparc/asi.h) | 0 | ||||
| -rw-r--r-- | target/sparc/cc_helper.c (renamed from target-sparc/cc_helper.c) | 0 | ||||
| -rw-r--r-- | target/sparc/cpu-qom.h (renamed from target-sparc/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/sparc/cpu.c (renamed from target-sparc/cpu.c) | 0 | ||||
| -rw-r--r-- | target/sparc/cpu.h (renamed from target-sparc/cpu.h) | 0 | ||||
| -rw-r--r-- | target/sparc/fop_helper.c (renamed from target-sparc/fop_helper.c) | 0 | ||||
| -rw-r--r-- | target/sparc/gdbstub.c (renamed from target-sparc/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/sparc/helper.c (renamed from target-sparc/helper.c) | 0 | ||||
| -rw-r--r-- | target/sparc/helper.h (renamed from target-sparc/helper.h) | 0 | ||||
| -rw-r--r-- | target/sparc/int32_helper.c (renamed from target-sparc/int32_helper.c) | 0 | ||||
| -rw-r--r-- | target/sparc/int64_helper.c (renamed from target-sparc/int64_helper.c) | 0 | ||||
| -rw-r--r-- | target/sparc/ldst_helper.c (renamed from target-sparc/ldst_helper.c) | 0 | ||||
| -rw-r--r-- | target/sparc/machine.c (renamed from target-sparc/machine.c) | 0 | ||||
| -rw-r--r-- | target/sparc/mmu_helper.c (renamed from target-sparc/mmu_helper.c) | 0 | ||||
| -rw-r--r-- | target/sparc/monitor.c (renamed from target-sparc/monitor.c) | 0 | ||||
| -rw-r--r-- | target/sparc/trace-events (renamed from target-sparc/trace-events) | 8 | ||||
| -rw-r--r-- | target/sparc/translate.c (renamed from target-sparc/translate.c) | 0 | ||||
| -rw-r--r-- | target/sparc/vis_helper.c (renamed from target-sparc/vis_helper.c) | 0 | ||||
| -rw-r--r-- | target/sparc/win_helper.c (renamed from target-sparc/win_helper.c) | 0 | ||||
| -rw-r--r-- | target/tilegx/Makefile.objs (renamed from target-tilegx/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/tilegx/cpu.c (renamed from target-tilegx/cpu.c) | 0 | ||||
| -rw-r--r-- | target/tilegx/cpu.h (renamed from target-tilegx/cpu.h) | 0 | ||||
| -rw-r--r-- | target/tilegx/helper.c (renamed from target-tilegx/helper.c) | 0 | ||||
| -rw-r--r-- | target/tilegx/helper.h (renamed from target-tilegx/helper.h) | 0 | ||||
| -rw-r--r-- | target/tilegx/opcode_tilegx.h (renamed from target-tilegx/opcode_tilegx.h) | 0 | ||||
| -rw-r--r-- | target/tilegx/simd_helper.c (renamed from target-tilegx/simd_helper.c) | 0 | ||||
| -rw-r--r-- | target/tilegx/spr_def_64.h (renamed from target-tilegx/spr_def_64.h) | 0 | ||||
| -rw-r--r-- | target/tilegx/translate.c (renamed from target-tilegx/translate.c) | 0 | ||||
| -rw-r--r-- | target/tricore/Makefile.objs (renamed from target-tricore/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/tricore/cpu-qom.h (renamed from target-tricore/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/tricore/cpu.c (renamed from target-tricore/cpu.c) | 0 | ||||
| -rw-r--r-- | target/tricore/cpu.h (renamed from target-tricore/cpu.h) | 0 | ||||
| -rw-r--r-- | target/tricore/csfr.def (renamed from target-tricore/csfr.def) | 0 | ||||
| -rw-r--r-- | target/tricore/fpu_helper.c (renamed from target-tricore/fpu_helper.c) | 0 | ||||
| -rw-r--r-- | target/tricore/helper.c (renamed from target-tricore/helper.c) | 0 | ||||
| -rw-r--r-- | target/tricore/helper.h (renamed from target-tricore/helper.h) | 0 | ||||
| -rw-r--r-- | target/tricore/op_helper.c (renamed from target-tricore/op_helper.c) | 0 | ||||
| -rw-r--r-- | target/tricore/translate.c (renamed from target-tricore/translate.c) | 0 | ||||
| -rw-r--r-- | target/tricore/tricore-defs.h (renamed from target-tricore/tricore-defs.h) | 0 | ||||
| -rw-r--r-- | target/tricore/tricore-opcodes.h (renamed from target-tricore/tricore-opcodes.h) | 0 | ||||
| -rw-r--r-- | target/unicore32/Makefile.objs (renamed from target-unicore32/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/unicore32/cpu-qom.h (renamed from target-unicore32/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/unicore32/cpu.c (renamed from target-unicore32/cpu.c) | 0 | ||||
| -rw-r--r-- | target/unicore32/cpu.h (renamed from target-unicore32/cpu.h) | 0 | ||||
| -rw-r--r-- | target/unicore32/helper.c (renamed from target-unicore32/helper.c) | 0 | ||||
| -rw-r--r-- | target/unicore32/helper.h (renamed from target-unicore32/helper.h) | 0 | ||||
| -rw-r--r-- | target/unicore32/op_helper.c (renamed from target-unicore32/op_helper.c) | 0 | ||||
| -rw-r--r-- | target/unicore32/softmmu.c (renamed from target-unicore32/softmmu.c) | 0 | ||||
| -rw-r--r-- | target/unicore32/translate.c (renamed from target-unicore32/translate.c) | 0 | ||||
| -rw-r--r-- | target/unicore32/ucf64_helper.c (renamed from target-unicore32/ucf64_helper.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/Makefile.objs (renamed from target-xtensa/Makefile.objs) | 0 | ||||
| -rw-r--r-- | target/xtensa/core-dc232b.c (renamed from target-xtensa/core-dc232b.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/core-dc232b/core-isa.h (renamed from target-xtensa/core-dc232b/core-isa.h) | 0 | ||||
| -rw-r--r-- | target/xtensa/core-dc232b/gdb-config.c (renamed from target-xtensa/core-dc232b/gdb-config.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/core-dc233c.c (renamed from target-xtensa/core-dc233c.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/core-dc233c/core-isa.h (renamed from target-xtensa/core-dc233c/core-isa.h) | 0 | ||||
| -rw-r--r-- | target/xtensa/core-dc233c/gdb-config.c (renamed from target-xtensa/core-dc233c/gdb-config.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/core-fsf.c (renamed from target-xtensa/core-fsf.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/core-fsf/core-isa.h (renamed from target-xtensa/core-fsf/core-isa.h) | 0 | ||||
| -rw-r--r-- | target/xtensa/cpu-qom.h (renamed from target-xtensa/cpu-qom.h) | 0 | ||||
| -rw-r--r-- | target/xtensa/cpu.c (renamed from target-xtensa/cpu.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/cpu.h (renamed from target-xtensa/cpu.h) | 0 | ||||
| -rw-r--r-- | target/xtensa/gdbstub.c (renamed from target-xtensa/gdbstub.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/helper.c (renamed from target-xtensa/helper.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/helper.h (renamed from target-xtensa/helper.h) | 0 | ||||
| -rwxr-xr-x | target/xtensa/import_core.sh (renamed from target-xtensa/import_core.sh) | 0 | ||||
| -rw-r--r-- | target/xtensa/monitor.c (renamed from target-xtensa/monitor.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/op_helper.c (renamed from target-xtensa/op_helper.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/overlay_tool.h (renamed from target-xtensa/overlay_tool.h) | 0 | ||||
| -rw-r--r-- | target/xtensa/translate.c (renamed from target-xtensa/translate.c) | 0 | ||||
| -rw-r--r-- | target/xtensa/xtensa-semi.c (renamed from target-xtensa/xtensa-semi.c) | 0 | ||||
| -rw-r--r-- | tcg/s390/tcg-target.inc.c | 75 | ||||
| -rw-r--r-- | tests/Makefile.include | 2 | ||||
| -rw-r--r-- | tests/qemu-iotests/071.out | 8 | ||||
| -rw-r--r-- | tests/tcg/xtensa/Makefile | 2 | ||||
| -rw-r--r-- | tests/test-aio.c | 4 | ||||
| -rw-r--r-- | tests/test-crypto-cipher.c | 119 | ||||
| -rw-r--r-- | tests/test-crypto-hmac.c | 266 | ||||
| -rw-r--r-- | tests/virtio-9p-test.c | 478 | ||||
| -rw-r--r-- | trace-events | 6 | ||||
| -rw-r--r-- | util/event_notifier-posix.c | 2 | ||||
| -rw-r--r-- | util/qemu-coroutine.c | 7 | ||||
| -rw-r--r-- | vl.c | 3 |
519 files changed, 7610 insertions, 2690 deletions
diff --git a/.gitignore b/.gitignore index 3d7848cb7e..e43c3044dc 100644 --- a/.gitignore +++ b/.gitignore @@ -82,10 +82,6 @@ *.d !/scripts/qemu-guest-agent/fsfreeze-hook.d *.o -*.lo -*.la -*.pc -.libs .sdk *.gcda *.gcno diff --git a/HACKING b/HACKING index 20a910168d..4125c97d8d 100644 --- a/HACKING +++ b/HACKING @@ -1,10 +1,28 @@ 1. Preprocessor +1.1. Variadic macros + For variadic macros, stick with this C99-like syntax: #define DPRINTF(fmt, ...) \ do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0) +1.2. Include directives + +Order include directives as follows: + +#include "qemu/osdep.h" /* Always first... */ +#include <...> /* then system headers... */ +#include "..." /* and finally QEMU headers. */ + +The "qemu/osdep.h" header contains preprocessor macros that affect the behavior +of core system headers like <stdint.h>. It must be the first include so that +core system headers included by external libraries get the preprocessor macros +that QEMU depends on. + +Do not include "qemu/osdep.h" from header files since the .c file will have +already included it. + 2. C types It should be common sense to use the right type, but we have collected diff --git a/MAINTAINERS b/MAINTAINERS index 4a605791fc..1444b26dc0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -106,7 +106,7 @@ F: include/fpu/ Alpha M: Richard Henderson <rth@twiddle.net> S: Maintained -F: target-alpha/ +F: target/alpha/ F: hw/alpha/ F: tests/tcg/alpha/ F: disas/alpha.c @@ -115,7 +115,7 @@ ARM M: Peter Maydell <peter.maydell@linaro.org> L: qemu-arm@nongnu.org S: Maintained -F: target-arm/ +F: target/arm/ F: hw/arm/ F: hw/cpu/a*mpcore.c F: include/hw/cpu/a*mpcore.h @@ -126,7 +126,7 @@ F: disas/libvixl/ CRIS M: Edgar E. Iglesias <edgar.iglesias@gmail.com> S: Maintained -F: target-cris/ +F: target/cris/ F: hw/cris/ F: include/hw/cris/ F: tests/tcg/cris/ @@ -135,7 +135,7 @@ F: disas/cris.c LM32 M: Michael Walle <michael@walle.cc> S: Maintained -F: target-lm32/ +F: target/lm32/ F: disas/lm32.c F: hw/lm32/ F: hw/*/lm32_* @@ -147,13 +147,13 @@ F: tests/tcg/lm32/ M68K M: Laurent Vivier <laurent@vivier.eu> S: Maintained -F: target-m68k/ +F: target/m68k/ F: disas/m68k.c MicroBlaze M: Edgar E. Iglesias <edgar.iglesias@gmail.com> S: Maintained -F: target-microblaze/ +F: target/microblaze/ F: hw/microblaze/ F: disas/microblaze.c @@ -161,7 +161,7 @@ MIPS M: Aurelien Jarno <aurelien@aurel32.net> M: Yongbok Kim <yongbok.kim@imgtec.com> S: Maintained -F: target-mips/ +F: target/mips/ F: hw/mips/ F: hw/misc/mips_* F: hw/intc/mips_gic.c @@ -176,7 +176,7 @@ F: disas/mips.c Moxie M: Anthony Green <green@moxielogic.com> S: Maintained -F: target-moxie/ +F: target/moxie/ F: disas/moxie.c F: hw/moxie/ F: default-configs/moxie-softmmu.mak @@ -184,7 +184,7 @@ F: default-configs/moxie-softmmu.mak OpenRISC M: Jia Liu <proljc@gmail.com> S: Maintained -F: target-openrisc/ +F: target/openrisc/ F: hw/openrisc/ F: tests/tcg/openrisc/ @@ -193,7 +193,7 @@ M: David Gibson <david@gibson.dropbear.id.au> M: Alexander Graf <agraf@suse.de> L: qemu-ppc@nongnu.org S: Maintained -F: target-ppc/ +F: target/ppc/ F: hw/ppc/ F: include/hw/ppc/ F: disas/ppc.c @@ -202,14 +202,14 @@ S390 M: Richard Henderson <rth@twiddle.net> M: Alexander Graf <agraf@suse.de> S: Maintained -F: target-s390x/ +F: target/s390x/ F: hw/s390x/ F: disas/s390.c SH4 M: Aurelien Jarno <aurelien@aurel32.net> S: Odd Fixes -F: target-sh4/ +F: target/sh4/ F: hw/sh4/ F: disas/sh4.c F: include/hw/sh4/ @@ -218,7 +218,7 @@ SPARC M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> M: Artyom Tarasenko <atar4qemu@gmail.com> S: Maintained -F: target-sparc/ +F: target/sparc/ F: hw/sparc/ F: hw/sparc64/ F: disas/sparc.c @@ -226,7 +226,7 @@ F: disas/sparc.c UniCore32 M: Guan Xuetao <gxt@mprc.pku.edu.cn> S: Maintained -F: target-unicore32/ +F: target/unicore32/ F: hw/unicore32/ F: include/hw/unicore32/ @@ -235,7 +235,7 @@ M: Paolo Bonzini <pbonzini@redhat.com> M: Richard Henderson <rth@twiddle.net> M: Eduardo Habkost <ehabkost@redhat.com> S: Maintained -F: target-i386/ +F: target/i386/ F: hw/i386/ F: disas/i386.c @@ -243,14 +243,14 @@ Xtensa M: Max Filippov <jcmvbkbc@gmail.com> W: http://wiki.osll.spb.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa S: Maintained -F: target-xtensa/ +F: target/xtensa/ F: hw/xtensa/ F: tests/tcg/xtensa/ TriCore M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> S: Maintained -F: target-tricore/ +F: target/tricore/ F: hw/tricore/ F: include/hw/tricore/ @@ -269,26 +269,26 @@ ARM M: Peter Maydell <peter.maydell@linaro.org> L: qemu-arm@nongnu.org S: Maintained -F: target-arm/kvm.c +F: target/arm/kvm.c MIPS M: James Hogan <james.hogan@imgtec.com> S: Maintained -F: target-mips/kvm.c +F: target/mips/kvm.c PPC M: Alexander Graf <agraf@suse.de> S: Maintained -F: target-ppc/kvm.c +F: target/ppc/kvm.c S390 M: Christian Borntraeger <borntraeger@de.ibm.com> M: Cornelia Huck <cornelia.huck@de.ibm.com> M: Alexander Graf <agraf@suse.de> S: Maintained -F: target-s390x/kvm.c -F: target-s390x/ioinst.[ch] -F: target-s390x/machine.c +F: target/s390x/kvm.c +F: target/s390x/ioinst.[ch] +F: target/s390x/machine.c F: hw/intc/s390_flic.c F: hw/intc/s390_flic_kvm.c F: include/hw/s390x/s390_flic.h @@ -301,7 +301,7 @@ M: Paolo Bonzini <pbonzini@redhat.com> M: Marcelo Tosatti <mtosatti@redhat.com> L: kvm@vger.kernel.org S: Supported -F: target-i386/kvm.c +F: target/i386/kvm.c Guest CPU Cores (Xen): ---------------------- @@ -508,7 +508,6 @@ M: Shannon Zhao <shannon.zhao@linaro.org> L: qemu-arm@nongnu.org S: Maintained F: hw/arm/virt-acpi-build.c -F: include/hw/arm/virt-acpi-build.h STM32F205 M: Alistair Francis <alistair@alistair23.me> @@ -885,7 +884,6 @@ F: hw/acpi/* F: hw/smbios/* F: hw/i386/acpi-build.[hc] F: hw/arm/virt-acpi-build.c -F: include/hw/arm/virt-acpi-build.h ppc4xx M: Alexander Graf <agraf@suse.de> @@ -1720,9 +1718,9 @@ L: qemu-block@nongnu.org S: Supported F: block/linux-aio.c F: include/block/raw-aio.h -F: block/raw-posix.c -F: block/raw-win32.c -F: block/raw_bsd.c +F: block/raw-format.c +F: block/file-posix.c +F: block/file-win32.c F: block/win32-aio.c qcow2 diff --git a/Makefile b/Makefile index 68accb9252..1a8bfb225c 100644 --- a/Makefile +++ b/Makefile @@ -232,12 +232,10 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS)) recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) -$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h | $(BUILD_DIR)/version.lo +$(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc config-host.h $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.o") -$(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc config-host.h - $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<,"RC","version.lo") -Makefile: $(version-obj-y) $(version-lobj-y) +Makefile: $(version-obj-y) ###################################################################### # Build libraries @@ -359,10 +357,9 @@ clean: rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f qemu-options.def rm -f *.msi - find . \( -name '*.l[oa]' -o -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} + + find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} + rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -f fsdev/*.pod - rm -rf .libs */.libs rm -f qemu-img-cmds.h rm -f ui/shader/*-vert.h ui/shader/*-frag.h @# May not be present in GENERATED_HEADERS diff --git a/Makefile.objs b/Makefile.objs index ecd6576a77..01cef866e4 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -97,7 +97,6 @@ common-obj-y += disas/ ###################################################################### # Resource file for Windows executables version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o -version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo ###################################################################### # tracing @@ -155,11 +154,11 @@ trace-events-y += hw/alpha/trace-events trace-events-y += ui/trace-events trace-events-y += audio/trace-events trace-events-y += net/trace-events -trace-events-y += target-arm/trace-events -trace-events-y += target-i386/trace-events -trace-events-y += target-sparc/trace-events -trace-events-y += target-s390x/trace-events -trace-events-y += target-ppc/trace-events +trace-events-y += target/arm/trace-events +trace-events-y += target/i386/trace-events +trace-events-y += target/sparc/trace-events +trace-events-y += target/s390x/trace-events +trace-events-y += target/ppc/trace-events trace-events-y += qom/trace-events trace-events-y += linux-user/trace-events trace-events-y += qapi/trace-events diff --git a/Makefile.target b/Makefile.target index 7a5080e94a..8ae82cb311 100644 --- a/Makefile.target +++ b/Makefile.target @@ -11,7 +11,7 @@ $(call set-vpath, $(SRC_PATH):$(BUILD_DIR)) ifdef CONFIG_LINUX QEMU_CFLAGS += -I../linux-headers endif -QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -DNEED_CPU_H +QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target/$(TARGET_BASE_ARCH) -DNEED_CPU_H QEMU_CFLAGS+=-I$(SRC_PATH)/include @@ -76,6 +76,7 @@ $(QEMU_PROG)-simpletrace.stp: $(BUILD_DIR)/trace-events-all else stap: endif +.PHONY: stap all: $(PROGS) stap @@ -92,7 +93,7 @@ obj-$(CONFIG_TCG_INTERPRETER) += tci.o obj-y += tcg/tcg-common.o obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o obj-y += fpu/softfloat.o -obj-y += target-$(TARGET_BASE_ARCH)/ +obj-y += target/$(TARGET_BASE_ARCH)/ obj-y += disas.o obj-y += tcg-runtime.o obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o diff --git a/VERSION b/VERSION index e3965f4029..e65e2ce44f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.7.94 +2.8.50 diff --git a/aio-posix.c b/aio-posix.c index e13b9ab2b0..15855715d4 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -18,6 +18,8 @@ #include "block/block.h" #include "qemu/queue.h" #include "qemu/sockets.h" +#include "qemu/cutils.h" +#include "trace.h" #ifdef CONFIG_EPOLL_CREATE1 #include <sys/epoll.h> #endif @@ -27,6 +29,9 @@ struct AioHandler GPollFD pfd; IOHandler *io_read; IOHandler *io_write; + AioPollFn *io_poll; + IOHandler *io_poll_begin; + IOHandler *io_poll_end; int deleted; void *opaque; bool is_external; @@ -200,6 +205,7 @@ void aio_set_fd_handler(AioContext *ctx, bool is_external, IOHandler *io_read, IOHandler *io_write, + AioPollFn *io_poll, void *opaque) { AioHandler *node; @@ -209,7 +215,7 @@ void aio_set_fd_handler(AioContext *ctx, node = find_aio_handler(ctx, fd); /* Are we deleting the fd handler? */ - if (!io_read && !io_write) { + if (!io_read && !io_write && !io_poll) { if (node == NULL) { return; } @@ -228,6 +234,10 @@ void aio_set_fd_handler(AioContext *ctx, QLIST_REMOVE(node, node); deleted = true; } + + if (!node->io_poll) { + ctx->poll_disable_cnt--; + } } else { if (node == NULL) { /* Alloc and insert if it's not already there */ @@ -237,10 +247,16 @@ void aio_set_fd_handler(AioContext *ctx, g_source_add_poll(&ctx->source, &node->pfd); is_new = true; + + ctx->poll_disable_cnt += !io_poll; + } else { + ctx->poll_disable_cnt += !io_poll - !node->io_poll; } + /* Update handler with latest information */ node->io_read = io_read; node->io_write = io_write; + node->io_poll = io_poll; node->opaque = opaque; node->is_external = is_external; @@ -250,22 +266,83 @@ void aio_set_fd_handler(AioContext *ctx, aio_epoll_update(ctx, node, is_new); aio_notify(ctx); + if (deleted) { g_free(node); } } +void aio_set_fd_poll(AioContext *ctx, int fd, + IOHandler *io_poll_begin, + IOHandler *io_poll_end) +{ + AioHandler *node = find_aio_handler(ctx, fd); + + if (!node) { + return; + } + + node->io_poll_begin = io_poll_begin; + node->io_poll_end = io_poll_end; +} + void aio_set_event_notifier(AioContext *ctx, EventNotifier *notifier, bool is_external, - EventNotifierHandler *io_read) + EventNotifierHandler *io_read, + AioPollFn *io_poll) +{ + aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), is_external, + (IOHandler *)io_read, NULL, io_poll, notifier); +} + +void aio_set_event_notifier_poll(AioContext *ctx, + EventNotifier *notifier, + EventNotifierHandler *io_poll_begin, + EventNotifierHandler *io_poll_end) { - aio_set_fd_handler(ctx, event_notifier_get_fd(notifier), - is_external, (IOHandler *)io_read, NULL, notifier); + aio_set_fd_poll(ctx, event_notifier_get_fd(notifier), + (IOHandler *)io_poll_begin, + (IOHandler *)io_poll_end); } +static void poll_set_started(AioContext *ctx, bool started) +{ + AioHandler *node; + + if (started == ctx->poll_started) { + return; + } + + ctx->poll_started = started; + + ctx->walking_handlers++; + QLIST_FOREACH(node, &ctx->aio_handlers, node) { + IOHandler *fn; + + if (node->deleted) { + continue; + } + + if (started) { + fn = node->io_poll_begin; + } else { + fn = node->io_poll_end; + } + + if (fn) { + fn(node->opaque); + } + } + ctx->walking_handlers--; +} + + bool aio_prepare(AioContext *ctx) { + /* Poll mode cannot be used with glib's event loop, disable it. */ + poll_set_started(ctx, false); + return false; } @@ -290,9 +367,13 @@ bool aio_pending(AioContext *ctx) return false; } -bool aio_dispatch(AioContext *ctx) +/* + * Note that dispatch_fds == false has the side-effect of post-poning the + * freeing of deleted handlers. + */ +bool aio_dispatch(AioContext *ctx, bool dispatch_fds) { - AioHandler *node; + AioHandler *node = NULL; bool progress = false; /* @@ -308,7 +389,9 @@ bool aio_dispatch(AioContext *ctx) * We have to walk very carefully in case aio_set_fd_handler is * called while we're walking. */ - node = QLIST_FIRST(&ctx->aio_handlers); + if (dispatch_fds) { + node = QLIST_FIRST(&ctx->aio_handlers); + } while (node) { AioHandler *tmp; int revents; @@ -400,12 +483,100 @@ static void add_pollfd(AioHandler *node) npfd++; } +static bool run_poll_handlers_once(AioContext *ctx) +{ + bool progress = false; + AioHandler *node; + + QLIST_FOREACH(node, &ctx->aio_handlers, node) { + if (!node->deleted && node->io_poll && + node->io_poll(node->opaque)) { + progress = true; + } + + /* Caller handles freeing deleted nodes. Don't do it here. */ + } + + return progress; +} + +/* run_poll_handlers: + * @ctx: the AioContext + * @max_ns: maximum time to poll for, in nanoseconds + * + * Polls for a given time. + * + * Note that ctx->notify_me must be non-zero so this function can detect + * aio_notify(). + * + * Note that the caller must have incremented ctx->walking_handlers. + * + * Returns: true if progress was made, false otherwise + */ +static bool run_poll_handlers(AioContext *ctx, int64_t max_ns) +{ + bool progress; + int64_t end_time; + + assert(ctx->notify_me); + assert(ctx->walking_handlers > 0); + assert(ctx->poll_disable_cnt == 0); + + trace_run_poll_handlers_begin(ctx, max_ns); + + end_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + max_ns; + + do { + progress = run_poll_handlers_once(ctx); + } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time); + + trace_run_poll_handlers_end(ctx, progress); + + return progress; +} + +/* try_poll_mode: + * @ctx: the AioContext + * @blocking: busy polling is only attempted when blocking is true + * + * ctx->notify_me must be non-zero so this function can detect aio_notify(). + * + * Note that the caller must have incremented ctx->walking_handlers. + * + * Returns: true if progress was made, false otherwise + */ +static bool try_poll_mode(AioContext *ctx, bool blocking) +{ + if (blocking && ctx->poll_max_ns && ctx->poll_disable_cnt == 0) { + /* See qemu_soonest_timeout() uint64_t hack */ + int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx), + (uint64_t)ctx->poll_ns); + + if (max_ns) { + poll_set_started(ctx, true); + + if (run_poll_handlers(ctx, max_ns)) { + return true; + } + } + } + + poll_set_started(ctx, false); + + /* Even if we don't run busy polling, try polling once in case it can make + * progress and the caller will be able to avoid ppoll(2)/epoll_wait(2). + */ + return run_poll_handlers_once(ctx); +} + bool aio_poll(AioContext *ctx, bool blocking) { AioHandler *node; - int i, ret; + int i; + int ret = 0; bool progress; int64_t timeout; + int64_t start = 0; aio_context_acquire(ctx); progress = false; @@ -423,41 +594,91 @@ bool aio_poll(AioContext *ctx, bool blocking) ctx->walking_handlers++; - assert(npfd == 0); + if (ctx->poll_max_ns) { + start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); + } + + if (try_poll_mode(ctx, blocking)) { + progress = true; + } else { + assert(npfd == 0); - /* fill pollfds */ + /* fill pollfds */ - if (!aio_epoll_enabled(ctx)) { - QLIST_FOREACH(node, &ctx->aio_handlers, node) { - if (!node->deleted && node->pfd.events - && aio_node_check(ctx, node->is_external)) { - add_pollfd(node); + if (!aio_epoll_enabled(ctx)) { + QLIST_FOREACH(node, &ctx->aio_handlers, node) { + if (!node->deleted && node->pfd.events + && aio_node_check(ctx, node->is_external)) { + add_pollfd(node); + } } } - } - timeout = blocking ? aio_compute_timeout(ctx) : 0; + timeout = blocking ? aio_compute_timeout(ctx) : 0; - /* wait until next event */ - if (timeout) { - aio_context_release(ctx); + /* wait until next event */ + if (timeout) { + aio_context_release(ctx); + } + if (aio_epoll_check_poll(ctx, pollfds, npfd, timeout)) { + AioHandler epoll_handler; + + epoll_handler.pfd.fd = ctx->epollfd; + epoll_handler.pfd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR; + npfd = 0; + add_pollfd(&epoll_handler); + ret = aio_epoll(ctx, pollfds, npfd, timeout); + } else { + ret = qemu_poll_ns(pollfds, npfd, timeout); + } + if (timeout) { + aio_context_acquire(ctx); + } } - if (aio_epoll_check_poll(ctx, pollfds, npfd, timeout)) { - AioHandler epoll_handler; - epoll_handler.pfd.fd = ctx->epollfd; - epoll_handler.pfd.events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR; - npfd = 0; - add_pollfd(&epoll_handler); - ret = aio_epoll(ctx, pollfds, npfd, timeout); - } else { - ret = qemu_poll_ns(pollfds, npfd, timeout); - } if (blocking) { atomic_sub(&ctx->notify_me, 2); } - if (timeout) { - aio_context_acquire(ctx); + + /* Adjust polling time */ + if (ctx->poll_max_ns) { + int64_t block_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start; + + if (block_ns <= ctx->poll_ns) { + /* This is the sweet spot, no adjustment needed */ + } else if (block_ns > ctx->poll_max_ns) { + /* We'd have to poll for too long, poll less */ + int64_t old = ctx->poll_ns; + + if (ctx->poll_shrink) { + ctx->poll_ns /= ctx->poll_shrink; + } else { + ctx->poll_ns = 0; + } + + trace_poll_shrink(ctx, old, ctx->poll_ns); + } else if (ctx->poll_ns < ctx->poll_max_ns && + block_ns < ctx->poll_max_ns) { + /* There is room to grow, poll longer */ + int64_t old = ctx->poll_ns; + int64_t grow = ctx->poll_grow; + + if (grow == 0) { + grow = 2; + } + + if (ctx->poll_ns) { + ctx->poll_ns *= grow; + } else { + ctx->poll_ns = 4000; /* start polling at 4 microseconds */ + } + + if (ctx->poll_ns > ctx->poll_max_ns) { + ctx->poll_ns = ctx->poll_max_ns; + } + + trace_poll_grow(ctx, old, ctx->poll_ns); + } } aio_notify_accept(ctx); @@ -473,7 +694,7 @@ bool aio_poll(AioContext *ctx, bool blocking) ctx->walking_handlers--; /* Run dispatch even if there were no readable fds to run timers */ - if (aio_dispatch(ctx)) { + if (aio_dispatch(ctx, ret > 0)) { progress = true; } @@ -484,6 +705,13 @@ bool aio_poll(AioContext *ctx, bool blocking) void aio_context_setup(AioContext *ctx) { + /* TODO remove this in final patch submission */ + if (getenv("QEMU_AIO_POLL_MAX_NS")) { + fprintf(stderr, "The QEMU_AIO_POLL_MAX_NS environment variable has " + "been replaced with -object iothread,poll-max-ns=NUM\n"); + exit(1); + } + #ifdef CONFIG_EPOLL_CREATE1 assert(!ctx->epollfd); ctx->epollfd = epoll_create1(EPOLL_CLOEXEC); @@ -495,3 +723,17 @@ void aio_context_setup(AioContext *ctx) } #endif } + +void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, + int64_t grow, int64_t shrink, Error **errp) +{ + /* No thread synchronization here, it doesn't matter if an incorrect value + * is used once. + */ + ctx->poll_max_ns = max_ns; + ctx->poll_ns = 0; + ctx->poll_grow = grow; + ctx->poll_shrink = shrink; + + aio_notify(ctx); +} diff --git a/aio-win32.c b/aio-win32.c index c8c249e260..d19dc429d8 100644 --- a/aio-win32.c +++ b/aio-win32.c @@ -20,6 +20,7 @@ #include "block/block.h" #include "qemu/queue.h" #include "qemu/sockets.h" +#include "qapi/error.h" struct AioHandler { EventNotifier *e; @@ -38,6 +39,7 @@ void aio_set_fd_handler(AioContext *ctx, bool is_external, IOHandler *io_read, IOHandler *io_write, + AioPollFn *io_poll, void *opaque) { /* fd is a SOCKET in our case */ @@ -100,10 +102,18 @@ void aio_set_fd_handler(AioContext *ctx, aio_notify(ctx); } +void aio_set_fd_poll(AioContext *ctx, int fd, + IOHandler *io_poll_begin, + IOHandler *io_poll_end) +{ + /* Not implemented */ +} + void aio_set_event_notifier(AioContext *ctx, EventNotifier *e, bool is_external, - EventNotifierHandler *io_notify) + EventNotifierHandler *io_notify, + AioPollFn *io_poll) { AioHandler *node; @@ -150,6 +160,14 @@ void aio_set_event_notifier(AioContext *ctx, aio_notify(ctx); } +void aio_set_event_notifier_poll(AioContext *ctx, + EventNotifier *notifier, + EventNotifierHandler *io_poll_begin, + EventNotifierHandler *io_poll_end) +{ + /* Not implemented */ +} + bool aio_prepare(AioContext *ctx) { static struct timeval tv0; @@ -271,12 +289,14 @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event) return progress; } -bool aio_dispatch(AioContext *ctx) +bool aio_dispatch(AioContext *ctx, bool dispatch_fds) { bool progress; progress = aio_bh_poll(ctx); - progress |= aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE); + if (dispatch_fds) { + progress |= aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE); + } progress |= timerlistgroup_run_timers(&ctx->tlg); return progress; } @@ -374,3 +394,9 @@ bool aio_poll(AioContext *ctx, bool blocking) void aio_context_setup(AioContext *ctx) { } + +void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, + int64_t grow, int64_t shrink, Error **errp) +{ + error_setg(errp, "AioContext polling is not implemented on Windows"); +} diff --git a/async.c b/async.c index b2de360c23..2960171834 100644 --- a/async.c +++ b/async.c @@ -251,7 +251,7 @@ aio_ctx_dispatch(GSource *source, AioContext *ctx = (AioContext *) source; assert(callback == NULL); - aio_dispatch(ctx); + aio_dispatch(ctx, true); return true; } @@ -282,7 +282,7 @@ aio_ctx_finalize(GSource *source) } qemu_mutex_unlock(&ctx->bh_lock); - aio_set_event_notifier(ctx, &ctx->notifier, false, NULL); + aio_set_event_notifier(ctx, &ctx->notifier, false, NULL, NULL); event_notifier_cleanup(&ctx->notifier); qemu_rec_mutex_destroy(&ctx->lock); qemu_mutex_destroy(&ctx->bh_lock); @@ -349,6 +349,15 @@ static void event_notifier_dummy_cb(EventNotifier *e) { } +/* Returns true if aio_notify() was called (e.g. a BH was scheduled) */ +static bool event_notifier_poll(void *opaque) +{ + EventNotifier *e = opaque; + AioContext *ctx = container_of(e, AioContext, notifier); + + return atomic_read(&ctx->notified); +} + AioContext *aio_context_new(Error **errp) { int ret; @@ -366,7 +375,8 @@ AioContext *aio_context_new(Error **errp) aio_set_event_notifier(ctx, &ctx->notifier, false, (EventNotifierHandler *) - event_notifier_dummy_cb); + event_notifier_dummy_cb, + event_notifier_poll); #ifdef CONFIG_LINUX_AIO ctx->linux_aio = NULL; #endif @@ -375,6 +385,11 @@ AioContext *aio_context_new(Error **errp) qemu_rec_mutex_init(&ctx->lock); timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx); + ctx->poll_ns = 0; + ctx->poll_max_ns = 0; + ctx->poll_grow = 0; + ctx->poll_shrink = 0; + return ctx; fail: g_source_destroy(&ctx->source); diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c index eda954b2a2..486b4a62bc 100644 --- a/backends/cryptodev-builtin.c +++ b/backends/cryptodev-builtin.c @@ -111,23 +111,42 @@ cryptodev_builtin_get_unused_session_index( return -1; } +#define AES_KEYSIZE_128 16 +#define AES_KEYSIZE_192 24 +#define AES_KEYSIZE_256 32 +#define AES_KEYSIZE_128_XTS AES_KEYSIZE_256 +#define AES_KEYSIZE_256_XTS 64 + static int -cryptodev_builtin_get_aes_algo(uint32_t key_len, Error **errp) +cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp) { int algo; - if (key_len == 128 / 8) { + if (key_len == AES_KEYSIZE_128) { algo = QCRYPTO_CIPHER_ALG_AES_128; - } else if (key_len == 192 / 8) { + } else if (key_len == AES_KEYSIZE_192) { algo = QCRYPTO_CIPHER_ALG_AES_192; - } else if (key_len == 256 / 8) { - algo = QCRYPTO_CIPHER_ALG_AES_256; + } else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */ + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + algo = QCRYPTO_CIPHER_ALG_AES_128; + } else { + algo = QCRYPTO_CIPHER_ALG_AES_256; + } + } else if (key_len == AES_KEYSIZE_256_XTS) { + if (mode == QCRYPTO_CIPHER_MODE_XTS) { + algo = QCRYPTO_CIPHER_ALG_AES_256; + } else { + goto err; + } } else { - error_setg(errp, "Unsupported key length :%u", key_len); - return -1; + goto err; } return algo; + +err: + error_setg(errp, "Unsupported key length :%u", key_len); + return -1; } static int cryptodev_builtin_create_cipher_session( @@ -155,32 +174,48 @@ static int cryptodev_builtin_create_cipher_session( switch (sess_info->cipher_alg) { case VIRTIO_CRYPTO_CIPHER_AES_ECB: + mode = QCRYPTO_CIPHER_MODE_ECB; algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, - errp); + mode, errp); if (algo < 0) { return -1; } - mode = QCRYPTO_CIPHER_MODE_ECB; break; case VIRTIO_CRYPTO_CIPHER_AES_CBC: + mode = QCRYPTO_CIPHER_MODE_CBC; algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, - errp); + mode, errp); if (algo < 0) { return -1; } - mode = QCRYPTO_CIPHER_MODE_CBC; break; case VIRTIO_CRYPTO_CIPHER_AES_CTR: + mode = QCRYPTO_CIPHER_MODE_CTR; algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, - errp); + mode, errp); if (algo < 0) { return -1; } - mode = QCRYPTO_CIPHER_MODE_CTR; break; - case VIRTIO_CRYPTO_CIPHER_DES_ECB: - algo = QCRYPTO_CIPHER_ALG_DES_RFB; + case VIRTIO_CRYPTO_CIPHER_AES_XTS: + mode = QCRYPTO_CIPHER_MODE_XTS; + algo = cryptodev_builtin_get_aes_algo(sess_info->key_len, + mode, errp); + if (algo < 0) { + return -1; + } + break; + case VIRTIO_CRYPTO_CIPHER_3DES_ECB: mode = QCRYPTO_CIPHER_MODE_ECB; + algo = QCRYPTO_CIPHER_ALG_3DES; + break; + case VIRTIO_CRYPTO_CIPHER_3DES_CBC: + mode = QCRYPTO_CIPHER_MODE_CBC; + algo = QCRYPTO_CIPHER_ALG_3DES; + break; + case VIRTIO_CRYPTO_CIPHER_3DES_CTR: + mode = QCRYPTO_CIPHER_MODE_CTR; + algo = QCRYPTO_CIPHER_ALG_3DES; break; default: error_setg(errp, "Unsupported cipher alg :%u", diff --git a/block/Makefile.objs b/block/Makefile.objs index 67a036a1df..0b8fd06f27 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -1,4 +1,4 @@ -block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o +block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o block-obj-y += qed-check.o @@ -6,8 +6,8 @@ block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o block-obj-y += quorum.o block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o block-obj-y += block-backend.o snapshot.o qapi.o -block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o -block-obj-$(CONFIG_POSIX) += raw-posix.o +block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o +block-obj-$(CONFIG_POSIX) += file-posix.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o block-obj-y += null.o mirror.o commit.o io.o block-obj-y += throttle-groups.o diff --git a/block/blkdebug.c b/block/blkdebug.c index 4127571454..acccf85666 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -58,10 +58,6 @@ typedef struct BlkdebugSuspendedReq { QLIST_ENTRY(BlkdebugSuspendedReq) next; } BlkdebugSuspendedReq; -static const AIOCBInfo blkdebug_aiocb_info = { - .aiocb_size = sizeof(BlkdebugAIOCB), -}; - enum { ACTION_INJECT_ERROR, ACTION_SET_STATE, @@ -77,7 +73,7 @@ typedef struct BlkdebugRule { int error; int immediately; int once; - int64_t sector; + int64_t offset; } inject; struct { int new_state; @@ -174,6 +170,7 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp) const char* event_name; BlkdebugEvent event; struct BlkdebugRule *rule; + int64_t sector; /* Find the right event for the rule */ event_name = qemu_opt_get(opts, "event"); @@ -200,7 +197,9 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp) rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0); rule->options.inject.immediately = qemu_opt_get_bool(opts, "immediately", 0); - rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1); + sector = qemu_opt_get_number(opts, "sector", -1); + rule->options.inject.offset = + sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE; break; case ACTION_SET_STATE: @@ -408,17 +407,14 @@ out: static void error_callback_bh(void *opaque) { - struct BlkdebugAIOCB *acb = opaque; - acb->common.cb(acb->common.opaque, acb->ret); - qemu_aio_unref(acb); + Coroutine *co = opaque; + qemu_coroutine_enter(co); } -static BlockAIOCB *inject_error(BlockDriverState *bs, - BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule) +static int inject_error(BlockDriverState *bs, BlkdebugRule *rule) { BDRVBlkdebugState *s = bs->opaque; int error = rule->options.inject.error; - struct BlkdebugAIOCB *acb; bool immediately = rule->options.inject.immediately; if (rule->options.inject.once) { @@ -426,81 +422,79 @@ static BlockAIOCB *inject_error(BlockDriverState *bs, remove_rule(rule); } - if (immediately) { - return NULL; + if (!immediately) { + aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh, + qemu_coroutine_self()); + qemu_coroutine_yield(); } - acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); - acb->ret = -error; - - aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh, acb); - - return &acb->common; + return -error; } -static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockCompletionFunc *cb, void *opaque) +static int coroutine_fn +blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, int flags) { BDRVBlkdebugState *s = bs->opaque; BlkdebugRule *rule = NULL; QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { - if (rule->options.inject.sector == -1 || - (rule->options.inject.sector >= sector_num && - rule->options.inject.sector < sector_num + nb_sectors)) { + uint64_t inject_offset = rule->options.inject.offset; + + if (inject_offset == -1 || + (inject_offset >= offset && inject_offset < offset + bytes)) + { break; } } if (rule && rule->options.inject.error) { - return inject_error(bs, cb, opaque, rule); + return inject_error(bs, rule); } - return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, - cb, opaque); + return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); } -static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockCompletionFunc *cb, void *opaque) +static int coroutine_fn +blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, int flags) { BDRVBlkdebugState *s = bs->opaque; BlkdebugRule *rule = NULL; QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { - if (rule->options.inject.sector == -1 || - (rule->options.inject.sector >= sector_num && - rule->options.inject.sector < sector_num + nb_sectors)) { + uint64_t inject_offset = rule->options.inject.offset; + + if (inject_offset == -1 || + (inject_offset >= offset && inject_offset < offset + bytes)) + { break; } } if (rule && rule->options.inject.error) { - return inject_error(bs, cb, opaque, rule); + return inject_error(bs, rule); } - return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, - cb, opaque); + return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); } -static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs, - BlockCompletionFunc *cb, void *opaque) +static int blkdebug_co_flush(BlockDriverState *bs) { BDRVBlkdebugState *s = bs->opaque; BlkdebugRule *rule = NULL; QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) { - if (rule->options.inject.sector == -1) { + if (rule->options.inject.offset == -1) { break; } } if (rule && rule->options.inject.error) { - return inject_error(bs, cb, opaque, rule); + return inject_error(bs, rule); } - return bdrv_aio_flush(bs->file->bs, cb, opaque); + return bdrv_co_flush(bs->file->bs); } @@ -752,9 +746,9 @@ static BlockDriver bdrv_blkdebug = { .bdrv_refresh_filename = blkdebug_refresh_filename, .bdrv_refresh_limits = blkdebug_refresh_limits, - .bdrv_aio_readv = blkdebug_aio_readv, - .bdrv_aio_writev = blkdebug_aio_writev, - .bdrv_aio_flush = blkdebug_aio_flush, + .bdrv_co_preadv = blkdebug_co_preadv, + .bdrv_co_pwritev = blkdebug_co_pwritev, + .bdrv_co_flush_to_disk = blkdebug_co_flush, .bdrv_debug_event = blkdebug_debug_event, .bdrv_debug_breakpoint = blkdebug_debug_breakpoint, diff --git a/block/blkverify.c b/block/blkverify.c index 28f9af6dba..43a940c2f5 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -19,38 +19,36 @@ typedef struct { BdrvChild *test_file; } BDRVBlkverifyState; -typedef struct BlkverifyAIOCB BlkverifyAIOCB; -struct BlkverifyAIOCB { - BlockAIOCB common; +typedef struct BlkverifyRequest { + Coroutine *co; + BlockDriverState *bs; /* Request metadata */ bool is_write; - int64_t sector_num; - int nb_sectors; + uint64_t offset; + uint64_t bytes; + int flags; - int ret; /* first completed request's result */ - unsigned int done; /* completion counter */ + int (*request_fn)(BdrvChild *, int64_t, unsigned int, QEMUIOVector *, + BdrvRequestFlags); - QEMUIOVector *qiov; /* user I/O vector */ - QEMUIOVector raw_qiov; /* cloned I/O vector for raw file */ - void *buf; /* buffer for raw file I/O */ + int ret; /* test image result */ + int raw_ret; /* raw image result */ - void (*verify)(BlkverifyAIOCB *acb); -}; + unsigned int done; /* completion counter */ -static const AIOCBInfo blkverify_aiocb_info = { - .aiocb_size = sizeof(BlkverifyAIOCB), -}; + QEMUIOVector *qiov; /* user I/O vector */ + QEMUIOVector *raw_qiov; /* cloned I/O vector for raw file */ +} BlkverifyRequest; -static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb, +static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyRequest *r, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ", - acb->is_write ? "write" : "read", acb->sector_num, - acb->nb_sectors); + fprintf(stderr, "blkverify: %s offset=%" PRId64 " bytes=%" PRId64 " ", + r->is_write ? "write" : "read", r->offset, r->bytes); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -166,113 +164,106 @@ static int64_t blkverify_getlength(BlockDriverState *bs) return bdrv_getlength(s->test_file->bs); } -static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, - int64_t sector_num, QEMUIOVector *qiov, - int nb_sectors, - BlockCompletionFunc *cb, - void *opaque) +static void coroutine_fn blkverify_do_test_req(void *opaque) { - BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque); - - acb->is_write = is_write; - acb->sector_num = sector_num; - acb->nb_sectors = nb_sectors; - acb->ret = -EINPROGRESS; - acb->done = 0; - acb->qiov = qiov; - acb->buf = NULL; - acb->verify = NULL; - return acb; + BlkverifyRequest *r = opaque; + BDRVBlkverifyState *s = r->bs->opaque; + + r->ret = r->request_fn(s->test_file, r->offset, r->bytes, r->qiov, + r->flags); + r->done++; + qemu_coroutine_enter_if_inactive(r->co); } -static void blkverify_aio_bh(void *opaque) +static void coroutine_fn blkverify_do_raw_req(void *opaque) { - BlkverifyAIOCB *acb = opaque; + BlkverifyRequest *r = opaque; - if (acb->buf) { - qemu_iovec_destroy(&acb->raw_qiov); - qemu_vfree(acb->buf); - } - acb->common.cb(acb->common.opaque, acb->ret); - qemu_aio_unref(acb); + r->raw_ret = r->request_fn(r->bs->file, r->offset, r->bytes, r->raw_qiov, + r->flags); + r->done++; + qemu_coroutine_enter_if_inactive(r->co); } -static void blkverify_aio_cb(void *opaque, int ret) +static int coroutine_fn +blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, QEMUIOVector *raw_qiov, + int flags, bool is_write) { - BlkverifyAIOCB *acb = opaque; - - switch (++acb->done) { - case 1: - acb->ret = ret; - break; - - case 2: - if (acb->ret != ret) { - blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret); - } - - if (acb->verify) { - acb->verify(acb); - } + Coroutine *co_a, *co_b; + + *r = (BlkverifyRequest) { + .co = qemu_coroutine_self(), + .bs = bs, + .offset = offset, + .bytes = bytes, + .qiov = qiov, + .raw_qiov = raw_qiov, + .flags = flags, + .is_write = is_write, + .request_fn = is_write ? bdrv_co_pwritev : bdrv_co_preadv, + }; + + co_a = qemu_coroutine_create(blkverify_do_test_req, r); + co_b = qemu_coroutine_create(blkverify_do_raw_req, r); + + qemu_coroutine_enter(co_a); + qemu_coroutine_enter(co_b); + + while (r->done < 2) { + qemu_coroutine_yield(); + } - aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), - blkverify_aio_bh, acb); - break; + if (r->ret != r->raw_ret) { + blkverify_err(r, "return value mismatch %d != %d", r->ret, r->raw_ret); } + + return r->ret; } -static void blkverify_verify_readv(BlkverifyAIOCB *acb) +static int coroutine_fn +blkverify_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, int flags) { - ssize_t offset = qemu_iovec_compare(acb->qiov, &acb->raw_qiov); - if (offset != -1) { - blkverify_err(acb, "contents mismatch in sector %" PRId64, - acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE)); + BlkverifyRequest r; + QEMUIOVector raw_qiov; + void *buf; + ssize_t cmp_offset; + int ret; + + buf = qemu_blockalign(bs->file->bs, qiov->size); + qemu_iovec_init(&raw_qiov, qiov->niov); + qemu_iovec_clone(&raw_qiov, qiov, buf); + + ret = blkverify_co_prwv(bs, &r, offset, bytes, qiov, &raw_qiov, flags, + false); + + cmp_offset = qemu_iovec_compare(qiov, &raw_qiov); + if (cmp_offset != -1) { + blkverify_err(&r, "contents mismatch at offset %" PRId64, + offset + cmp_offset); } -} -static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockCompletionFunc *cb, void *opaque) -{ - BDRVBlkverifyState *s = bs->opaque; - BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov, - nb_sectors, cb, opaque); - - acb->verify = blkverify_verify_readv; - acb->buf = qemu_blockalign(bs->file->bs, qiov->size); - qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov); - qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf); - - bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors, - blkverify_aio_cb, acb); - bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors, - blkverify_aio_cb, acb); - return &acb->common; + qemu_iovec_destroy(&raw_qiov); + qemu_vfree(buf); + + return ret; } -static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs, - int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, - BlockCompletionFunc *cb, void *opaque) +static int coroutine_fn +blkverify_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, int flags) { - BDRVBlkverifyState *s = bs->opaque; - BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov, - nb_sectors, cb, opaque); - - bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors, - blkverify_aio_cb, acb); - bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, - blkverify_aio_cb, acb); - return &acb->common; + BlkverifyRequest r; + return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true); } -static BlockAIOCB *blkverify_aio_flush(BlockDriverState *bs, - BlockCompletionFunc *cb, - void *opaque) +static int blkverify_co_flush(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; /* Only flush test file, the raw file is not important */ - return bdrv_aio_flush(s->test_file->bs, cb, opaque); + return bdrv_co_flush(s->test_file->bs); } static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, @@ -332,9 +323,9 @@ static BlockDriver bdrv_blkverify = { .bdrv_getlength = blkverify_getlength, .bdrv_refresh_filename = blkverify_refresh_filename, - .bdrv_aio_readv = blkverify_aio_readv, - .bdrv_aio_writev = blkverify_aio_writev, - .bdrv_aio_flush = blkverify_aio_flush, + .bdrv_co_preadv = blkverify_co_preadv, + .bdrv_co_pwritev = blkverify_co_pwritev, + .bdrv_co_flush = blkverify_co_flush, .is_filter = true, .bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter, diff --git a/block/curl.c b/block/curl.c index 0404c1b5fa..792fef8269 100644 --- a/block/curl.c +++ b/block/curl.c @@ -192,19 +192,19 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action, switch (action) { case CURL_POLL_IN: aio_set_fd_handler(s->aio_context, fd, false, - curl_multi_read, NULL, state); + curl_multi_read, NULL, NULL, state); break; case CURL_POLL_OUT: aio_set_fd_handler(s->aio_context, fd, false, - NULL, curl_multi_do, state); + NULL, curl_multi_do, NULL, state); break; case CURL_POLL_INOUT: aio_set_fd_handler(s->aio_context, fd, false, - curl_multi_read, curl_multi_do, state); + curl_multi_read, curl_multi_do, NULL, state); break; case CURL_POLL_REMOVE: aio_set_fd_handler(s->aio_context, fd, false, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); break; } diff --git a/block/raw-posix.c b/block/file-posix.c index 28b47d977b..28b47d977b 100644 --- a/block/raw-posix.c +++ b/block/file-posix.c diff --git a/block/raw-win32.c b/block/file-win32.c index 800fabdd72..800fabdd72 100644 --- a/block/raw-win32.c +++ b/block/file-win32.c diff --git a/block/gluster.c b/block/gluster.c index a0a74e49fd..1a22f2982d 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1253,7 +1253,7 @@ static int qemu_gluster_has_zero_init(BlockDriverState *bs) * If @start is in a trailing hole or beyond EOF, return -ENXIO. * If we can't find out, return a negative errno other than -ENXIO. * - * (Shamefully copied from raw-posix.c, only miniscule adaptions.) + * (Shamefully copied from file-posix.c, only miniscule adaptions.) */ static int find_allocation(BlockDriverState *bs, off_t start, off_t *data, off_t *hole) @@ -1349,7 +1349,7 @@ exit: * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes * beyond the end of the disk image it will be clamped. * - * (Based on raw_co_get_block_status() from raw-posix.c.) + * (Based on raw_co_get_block_status() from file-posix.c.) */ static int64_t coroutine_fn qemu_gluster_co_get_block_status( BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum, diff --git a/block/iscsi.c b/block/iscsi.c index 0960929d57..6aeeb9ec4f 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -362,6 +362,7 @@ iscsi_set_events(IscsiLun *iscsilun) false, (ev & POLLIN) ? iscsi_process_read : NULL, (ev & POLLOUT) ? iscsi_process_write : NULL, + NULL, iscsilun); iscsilun->events = ev; } @@ -1526,7 +1527,7 @@ static void iscsi_detach_aio_context(BlockDriverState *bs) IscsiLun *iscsilun = bs->opaque; aio_set_fd_handler(iscsilun->aio_context, iscsi_get_fd(iscsilun->iscsi), - false, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL); iscsilun->events = 0; if (iscsilun->nop_timer) { diff --git a/block/linux-aio.c b/block/linux-aio.c index 1685ec29a3..03ab741d37 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -255,6 +255,20 @@ static void qemu_laio_completion_cb(EventNotifier *e) } } +static bool qemu_laio_poll_cb(void *opaque) +{ + EventNotifier *e = opaque; + LinuxAioState *s = container_of(e, LinuxAioState, e); + struct io_event *events; + + if (!io_getevents_peek(s->ctx, &events)) { + return false; + } + + qemu_laio_process_completions_and_submit(s); + return true; +} + static void laio_cancel(BlockAIOCB *blockacb) { struct qemu_laiocb *laiocb = (struct qemu_laiocb *)blockacb; @@ -439,7 +453,7 @@ BlockAIOCB *laio_submit(BlockDriverState *bs, LinuxAioState *s, int fd, void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context) { - aio_set_event_notifier(old_context, &s->e, false, NULL); + aio_set_event_notifier(old_context, &s->e, false, NULL, NULL); qemu_bh_delete(s->completion_bh); } @@ -448,7 +462,8 @@ void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context) s->aio_context = new_context; s->completion_bh = aio_bh_new(new_context, qemu_laio_completion_bh, s); aio_set_event_notifier(new_context, &s->e, false, - qemu_laio_completion_cb); + qemu_laio_completion_cb, + qemu_laio_poll_cb); } LinuxAioState *laio_init(void) diff --git a/block/nbd-client.c b/block/nbd-client.c index 3779c6c999..06f1532805 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -145,7 +145,7 @@ static int nbd_co_send_request(BlockDriverState *bs, aio_context = bdrv_get_aio_context(bs); aio_set_fd_handler(aio_context, s->sioc->fd, false, - nbd_reply_ready, nbd_restart_write, bs); + nbd_reply_ready, nbd_restart_write, NULL, bs); if (qiov) { qio_channel_set_cork(s->ioc, true); rc = nbd_send_request(s->ioc, request); @@ -161,7 +161,7 @@ static int nbd_co_send_request(BlockDriverState *bs, rc = nbd_send_request(s->ioc, request); } aio_set_fd_handler(aio_context, s->sioc->fd, false, - nbd_reply_ready, NULL, bs); + nbd_reply_ready, NULL, NULL, bs); s->send_coroutine = NULL; qemu_co_mutex_unlock(&s->send_mutex); return rc; @@ -366,14 +366,14 @@ void nbd_client_detach_aio_context(BlockDriverState *bs) { aio_set_fd_handler(bdrv_get_aio_context(bs), nbd_get_client_session(bs)->sioc->fd, - false, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL); } void nbd_client_attach_aio_context(BlockDriverState *bs, AioContext *new_context) { aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sioc->fd, - false, nbd_reply_ready, NULL, bs); + false, nbd_reply_ready, NULL, NULL, bs); } void nbd_client_close(BlockDriverState *bs) diff --git a/block/nfs.c b/block/nfs.c index a490660027..a564340d15 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -197,7 +197,8 @@ static void nfs_set_events(NFSClient *client) aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), false, (ev & POLLIN) ? nfs_process_read : NULL, - (ev & POLLOUT) ? nfs_process_write : NULL, client); + (ev & POLLOUT) ? nfs_process_write : NULL, + NULL, client); } client->events = ev; @@ -395,7 +396,7 @@ static void nfs_detach_aio_context(BlockDriverState *bs) NFSClient *client = bs->opaque; aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), - false, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL); client->events = 0; } @@ -415,7 +416,7 @@ static void nfs_client_close(NFSClient *client) nfs_close(client->context, client->fh); } aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context), - false, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL); nfs_destroy_context(client->context); } memset(client, 0, sizeof(NFSClient)); diff --git a/block/quorum.c b/block/quorum.c index d122299352..86e2072dce 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -97,7 +97,7 @@ typedef struct QuorumAIOCB QuorumAIOCB; * $children_count QuorumChildRequest. */ typedef struct QuorumChildRequest { - BlockAIOCB *aiocb; + BlockDriverState *bs; QEMUIOVector qiov; uint8_t *buf; int ret; @@ -110,11 +110,12 @@ typedef struct QuorumChildRequest { * used to do operations on each children and track overall progress. */ struct QuorumAIOCB { - BlockAIOCB common; + BlockDriverState *bs; + Coroutine *co; /* Request metadata */ - uint64_t sector_num; - int nb_sectors; + uint64_t offset; + uint64_t bytes; QEMUIOVector *qiov; /* calling IOV */ @@ -133,32 +134,15 @@ struct QuorumAIOCB { int children_read; /* how many children have been read from */ }; -static bool quorum_vote(QuorumAIOCB *acb); - -static void quorum_aio_cancel(BlockAIOCB *blockacb) -{ - QuorumAIOCB *acb = container_of(blockacb, QuorumAIOCB, common); - BDRVQuorumState *s = acb->common.bs->opaque; - int i; - - /* cancel all callbacks */ - for (i = 0; i < s->num_children; i++) { - if (acb->qcrs[i].aiocb) { - bdrv_aio_cancel_async(acb->qcrs[i].aiocb); - } - } -} - -static AIOCBInfo quorum_aiocb_info = { - .aiocb_size = sizeof(QuorumAIOCB), - .cancel_async = quorum_aio_cancel, -}; +typedef struct QuorumCo { + QuorumAIOCB *acb; + int idx; +} QuorumCo; static void quorum_aio_finalize(QuorumAIOCB *acb) { - acb->common.cb(acb->common.opaque, acb->vote_ret); g_free(acb->qcrs); - qemu_aio_unref(acb); + g_free(acb); } static bool quorum_sha256_compare(QuorumVoteValue *a, QuorumVoteValue *b) @@ -171,30 +155,26 @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b) return a->l == b->l; } -static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s, - BlockDriverState *bs, +static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs, QEMUIOVector *qiov, - uint64_t sector_num, - int nb_sectors, - BlockCompletionFunc *cb, - void *opaque) + uint64_t offset, + uint64_t bytes) { - QuorumAIOCB *acb = qemu_aio_get(&quorum_aiocb_info, bs, cb, opaque); + BDRVQuorumState *s = bs->opaque; + QuorumAIOCB *acb = g_new(QuorumAIOCB, 1); int i; - acb->common.bs->opaque = s; - acb->sector_num = sector_num; - acb->nb_sectors = nb_sectors; - acb->qiov = qiov; - acb->qcrs = g_new0(QuorumChildRequest, s->num_children); - acb->count = 0; - acb->success_count = 0; - acb->rewrite_count = 0; - acb->votes.compare = quorum_sha256_compare; - QLIST_INIT(&acb->votes.vote_list); - acb->is_read = false; - acb->vote_ret = 0; + *acb = (QuorumAIOCB) { + .co = qemu_coroutine_self(), + .bs = bs, + .offset = offset, + .bytes = bytes, + .qiov = qiov, + .votes.compare = quorum_sha256_compare, + .votes.vote_list = QLIST_HEAD_INITIALIZER(acb.votes.vote_list), + }; + acb->qcrs = g_new0(QuorumChildRequest, s->num_children); for (i = 0; i < s->num_children; i++) { acb->qcrs[i].buf = NULL; acb->qcrs[i].ret = 0; @@ -204,30 +184,37 @@ static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s, return acb; } -static void quorum_report_bad(QuorumOpType type, uint64_t sector_num, - int nb_sectors, char *node_name, int ret) +static void quorum_report_bad(QuorumOpType type, uint64_t offset, + uint64_t bytes, char *node_name, int ret) { const char *msg = NULL; + int64_t start_sector = offset / BDRV_SECTOR_SIZE; + int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE); + if (ret < 0) { msg = strerror(-ret); } - qapi_event_send_quorum_report_bad(type, !!msg, msg, node_name, - sector_num, nb_sectors, &error_abort); + qapi_event_send_quorum_report_bad(type, !!msg, msg, node_name, start_sector, + end_sector - start_sector, &error_abort); } static void quorum_report_failure(QuorumAIOCB *acb) { - const char *reference = bdrv_get_device_or_node_name(acb->common.bs); - qapi_event_send_quorum_failure(reference, acb->sector_num, - acb->nb_sectors, &error_abort); + const char *reference = bdrv_get_device_or_node_name(acb->bs); + int64_t start_sector = acb->offset / BDRV_SECTOR_SIZE; + int64_t end_sector = DIV_ROUND_UP(acb->offset + acb->bytes, + BDRV_SECTOR_SIZE); + + qapi_event_send_quorum_failure(reference, start_sector, + end_sector - start_sector, &error_abort); } static int quorum_vote_error(QuorumAIOCB *acb); static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb) { - BDRVQuorumState *s = acb->common.bs->opaque; + BDRVQuorumState *s = acb->bs->opaque; if (acb->success_count < s->threshold) { acb->vote_ret = quorum_vote_error(acb); @@ -238,22 +225,7 @@ static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb) return false; } -static void quorum_rewrite_aio_cb(void *opaque, int ret) -{ - QuorumAIOCB *acb = opaque; - - /* one less rewrite to do */ - acb->rewrite_count--; - - /* wait until all rewrite callbacks have completed */ - if (acb->rewrite_count) { - return; - } - - quorum_aio_finalize(acb); -} - -static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb); +static int read_fifo_child(QuorumAIOCB *acb); static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source) { @@ -272,70 +244,7 @@ static void quorum_report_bad_acb(QuorumChildRequest *sacb, int ret) { QuorumAIOCB *acb = sacb->parent; QuorumOpType type = acb->is_read ? QUORUM_OP_TYPE_READ : QUORUM_OP_TYPE_WRITE; - quorum_report_bad(type, acb->sector_num, acb->nb_sectors, - sacb->aiocb->bs->node_name, ret); -} - -static void quorum_fifo_aio_cb(void *opaque, int ret) -{ - QuorumChildRequest *sacb = opaque; - QuorumAIOCB *acb = sacb->parent; - BDRVQuorumState *s = acb->common.bs->opaque; - - assert(acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO); - - if (ret < 0) { - quorum_report_bad_acb(sacb, ret); - - /* We try to read next child in FIFO order if we fail to read */ - if (acb->children_read < s->num_children) { - read_fifo_child(acb); - return; - } - } - - acb->vote_ret = ret; - - /* FIXME: rewrite failed children if acb->children_read > 1? */ - quorum_aio_finalize(acb); -} - -static void quorum_aio_cb(void *opaque, int ret) -{ - QuorumChildRequest *sacb = opaque; - QuorumAIOCB *acb = sacb->parent; - BDRVQuorumState *s = acb->common.bs->opaque; - bool rewrite = false; - int i; - - sacb->ret = ret; - if (ret == 0) { - acb->success_count++; - } else { - quorum_report_bad_acb(sacb, ret); - } - acb->count++; - assert(acb->count <= s->num_children); - assert(acb->success_count <= s->num_children); - if (acb->count < s->num_children) { - return; - } - - /* Do the vote on read */ - if (acb->is_read) { - rewrite = quorum_vote(acb); - for (i = 0; i < s->num_children; i++) { - qemu_vfree(acb->qcrs[i].buf); - qemu_iovec_destroy(&acb->qcrs[i].qiov); - } - } else { - quorum_has_too_much_io_failed(acb); - } - - /* if no rewrite is done the code will finish right away */ - if (!rewrite) { - quorum_aio_finalize(acb); - } + quorum_report_bad(type, acb->offset, acb->bytes, sacb->bs->node_name, ret); } static void quorum_report_bad_versions(BDRVQuorumState *s, @@ -350,14 +259,31 @@ static void quorum_report_bad_versions(BDRVQuorumState *s, continue; } QLIST_FOREACH(item, &version->items, next) { - quorum_report_bad(QUORUM_OP_TYPE_READ, acb->sector_num, - acb->nb_sectors, + quorum_report_bad(QUORUM_OP_TYPE_READ, acb->offset, acb->bytes, s->children[item->index]->bs->node_name, 0); } } } -static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb, +static void quorum_rewrite_entry(void *opaque) +{ + QuorumCo *co = opaque; + QuorumAIOCB *acb = co->acb; + BDRVQuorumState *s = acb->bs->opaque; + + /* Ignore any errors, it's just a correction attempt for already + * corrupted data. */ + bdrv_co_pwritev(s->children[co->idx], acb->offset, acb->bytes, + acb->qiov, 0); + + /* Wake up the caller after the last rewrite */ + acb->rewrite_count--; + if (!acb->rewrite_count) { + qemu_coroutine_enter_if_inactive(acb->co); + } +} + +static bool quorum_rewrite_bad_versions(QuorumAIOCB *acb, QuorumVoteValue *value) { QuorumVoteVersion *version; @@ -376,7 +302,7 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb, } } - /* quorum_rewrite_aio_cb will count down this to zero */ + /* quorum_rewrite_entry will count down this to zero */ acb->rewrite_count = count; /* now fire the correcting rewrites */ @@ -385,9 +311,14 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb, continue; } QLIST_FOREACH(item, &version->items, next) { - bdrv_aio_writev(s->children[item->index], acb->sector_num, - acb->qiov, acb->nb_sectors, quorum_rewrite_aio_cb, - acb); + Coroutine *co; + QuorumCo data = { + .acb = acb, + .idx = item->index, + }; + + co = qemu_coroutine_create(quorum_rewrite_entry, &data); + qemu_coroutine_enter(co); } } @@ -507,8 +438,8 @@ static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb, va_list ap; va_start(ap, fmt); - fprintf(stderr, "quorum: sector_num=%" PRId64 " nb_sectors=%d ", - acb->sector_num, acb->nb_sectors); + fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64 " ", + acb->offset, acb->bytes); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -519,16 +450,15 @@ static bool quorum_compare(QuorumAIOCB *acb, QEMUIOVector *a, QEMUIOVector *b) { - BDRVQuorumState *s = acb->common.bs->opaque; + BDRVQuorumState *s = acb->bs->opaque; ssize_t offset; /* This driver will replace blkverify in this particular case */ if (s->is_blkverify) { offset = qemu_iovec_compare(a, b); if (offset != -1) { - quorum_err(acb, "contents mismatch in sector %" PRId64, - acb->sector_num + - (uint64_t)(offset / BDRV_SECTOR_SIZE)); + quorum_err(acb, "contents mismatch at offset %" PRIu64, + acb->offset + offset); } return true; } @@ -539,7 +469,7 @@ static bool quorum_compare(QuorumAIOCB *acb, /* Do a vote to get the error code */ static int quorum_vote_error(QuorumAIOCB *acb) { - BDRVQuorumState *s = acb->common.bs->opaque; + BDRVQuorumState *s = acb->bs->opaque; QuorumVoteVersion *winner = NULL; QuorumVotes error_votes; QuorumVoteValue result_value; @@ -568,17 +498,16 @@ static int quorum_vote_error(QuorumAIOCB *acb) return ret; } -static bool quorum_vote(QuorumAIOCB *acb) +static void quorum_vote(QuorumAIOCB *acb) { bool quorum = true; - bool rewrite = false; int i, j, ret; QuorumVoteValue hash; - BDRVQuorumState *s = acb->common.bs->opaque; + BDRVQuorumState *s = acb->bs->opaque; QuorumVoteVersion *winner; if (quorum_has_too_much_io_failed(acb)) { - return false; + return; } /* get the index of the first successful read */ @@ -606,7 +535,7 @@ static bool quorum_vote(QuorumAIOCB *acb) /* Every successful read agrees */ if (quorum) { quorum_copy_qiov(acb->qiov, &acb->qcrs[i].qiov); - return false; + return; } /* compute hashes for each successful read, also store indexes */ @@ -641,19 +570,46 @@ static bool quorum_vote(QuorumAIOCB *acb) /* corruption correction is enabled */ if (s->rewrite_corrupted) { - rewrite = quorum_rewrite_bad_versions(s, acb, &winner->value); + quorum_rewrite_bad_versions(acb, &winner->value); } free_exit: /* free lists */ quorum_free_vote_list(&acb->votes); - return rewrite; } -static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb) +static void read_quorum_children_entry(void *opaque) { - BDRVQuorumState *s = acb->common.bs->opaque; - int i; + QuorumCo *co = opaque; + QuorumAIOCB *acb = co->acb; + BDRVQuorumState *s = acb->bs->opaque; + int i = co->idx; + QuorumChildRequest *sacb = &acb->qcrs[i]; + + sacb->bs = s->children[i]->bs; + sacb->ret = bdrv_co_preadv(s->children[i], acb->offset, acb->bytes, + &acb->qcrs[i].qiov, 0); + + if (sacb->ret == 0) { + acb->success_count++; + } else { + quorum_report_bad_acb(sacb, sacb->ret); + } + + acb->count++; + assert(acb->count <= s->num_children); + assert(acb->success_count <= s->num_children); + + /* Wake up the caller after the last read */ + if (acb->count == s->num_children) { + qemu_coroutine_enter_if_inactive(acb->co); + } +} + +static int read_quorum_children(QuorumAIOCB *acb) +{ + BDRVQuorumState *s = acb->bs->opaque; + int i, ret; acb->children_read = s->num_children; for (i = 0; i < s->num_children; i++) { @@ -663,65 +619,131 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb) } for (i = 0; i < s->num_children; i++) { - acb->qcrs[i].aiocb = bdrv_aio_readv(s->children[i], acb->sector_num, - &acb->qcrs[i].qiov, acb->nb_sectors, - quorum_aio_cb, &acb->qcrs[i]); + Coroutine *co; + QuorumCo data = { + .acb = acb, + .idx = i, + }; + + co = qemu_coroutine_create(read_quorum_children_entry, &data); + qemu_coroutine_enter(co); } - return &acb->common; + while (acb->count < s->num_children) { + qemu_coroutine_yield(); + } + + /* Do the vote on read */ + quorum_vote(acb); + for (i = 0; i < s->num_children; i++) { + qemu_vfree(acb->qcrs[i].buf); + qemu_iovec_destroy(&acb->qcrs[i].qiov); + } + + while (acb->rewrite_count) { + qemu_coroutine_yield(); + } + + ret = acb->vote_ret; + + return ret; } -static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb) +static int read_fifo_child(QuorumAIOCB *acb) { - BDRVQuorumState *s = acb->common.bs->opaque; - int n = acb->children_read++; + BDRVQuorumState *s = acb->bs->opaque; + int n, ret; + + /* We try to read the next child in FIFO order if we failed to read */ + do { + n = acb->children_read++; + acb->qcrs[n].bs = s->children[n]->bs; + ret = bdrv_co_preadv(s->children[n], acb->offset, acb->bytes, + acb->qiov, 0); + if (ret < 0) { + quorum_report_bad_acb(&acb->qcrs[n], ret); + } + } while (ret < 0 && acb->children_read < s->num_children); - acb->qcrs[n].aiocb = bdrv_aio_readv(s->children[n], acb->sector_num, - acb->qiov, acb->nb_sectors, - quorum_fifo_aio_cb, &acb->qcrs[n]); + /* FIXME: rewrite failed children if acb->children_read > 1? */ - return &acb->common; + return ret; } -static BlockAIOCB *quorum_aio_readv(BlockDriverState *bs, - int64_t sector_num, - QEMUIOVector *qiov, - int nb_sectors, - BlockCompletionFunc *cb, - void *opaque) +static int quorum_co_preadv(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, int flags) { BDRVQuorumState *s = bs->opaque; - QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num, - nb_sectors, cb, opaque); + QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes); + int ret; + acb->is_read = true; acb->children_read = 0; if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) { - return read_quorum_children(acb); + ret = read_quorum_children(acb); + } else { + ret = read_fifo_child(acb); + } + quorum_aio_finalize(acb); + + return ret; +} + +static void write_quorum_entry(void *opaque) +{ + QuorumCo *co = opaque; + QuorumAIOCB *acb = co->acb; + BDRVQuorumState *s = acb->bs->opaque; + int i = co->idx; + QuorumChildRequest *sacb = &acb->qcrs[i]; + + sacb->bs = s->children[i]->bs; + sacb->ret = bdrv_co_pwritev(s->children[i], acb->offset, acb->bytes, + acb->qiov, 0); + if (sacb->ret == 0) { + acb->success_count++; + } else { + quorum_report_bad_acb(sacb, sacb->ret); } + acb->count++; + assert(acb->count <= s->num_children); + assert(acb->success_count <= s->num_children); - return read_fifo_child(acb); + /* Wake up the caller after the last write */ + if (acb->count == s->num_children) { + qemu_coroutine_enter_if_inactive(acb->co); + } } -static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs, - int64_t sector_num, - QEMUIOVector *qiov, - int nb_sectors, - BlockCompletionFunc *cb, - void *opaque) +static int quorum_co_pwritev(BlockDriverState *bs, uint64_t offset, + uint64_t bytes, QEMUIOVector *qiov, int flags) { BDRVQuorumState *s = bs->opaque; - QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num, nb_sectors, - cb, opaque); - int i; + QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes); + int i, ret; for (i = 0; i < s->num_children; i++) { - acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i], sector_num, - qiov, nb_sectors, &quorum_aio_cb, - &acb->qcrs[i]); + Coroutine *co; + QuorumCo data = { + .acb = acb, + .idx = i, + }; + + co = qemu_coroutine_create(write_quorum_entry, &data); + qemu_coroutine_enter(co); + } + + while (acb->count < s->num_children) { + qemu_coroutine_yield(); } - return &acb->common; + quorum_has_too_much_io_failed(acb); + + ret = acb->vote_ret; + quorum_aio_finalize(acb); + + return ret; } static int64_t quorum_getlength(BlockDriverState *bs) @@ -765,7 +787,7 @@ static coroutine_fn int quorum_co_flush(BlockDriverState *bs) result = bdrv_co_flush(s->children[i]->bs); if (result) { quorum_report_bad(QUORUM_OP_TYPE_FLUSH, 0, - bdrv_nb_sectors(s->children[i]->bs), + bdrv_getlength(s->children[i]->bs), s->children[i]->bs->node_name, result); result_value.l = result; quorum_count_vote(&error_votes, &result_value, i); @@ -1098,8 +1120,8 @@ static BlockDriver bdrv_quorum = { .bdrv_getlength = quorum_getlength, - .bdrv_aio_readv = quorum_aio_readv, - .bdrv_aio_writev = quorum_aio_writev, + .bdrv_co_preadv = quorum_co_preadv, + .bdrv_co_pwritev = quorum_co_pwritev, .bdrv_add_child = quorum_add_child, .bdrv_del_child = quorum_del_child, diff --git a/block/raw_bsd.c b/block/raw-format.c index 8a5b9b0424..8404a82e0c 100644 --- a/block/raw_bsd.c +++ b/block/raw-format.c @@ -1,4 +1,4 @@ -/* BlockDriver implementation for "raw" +/* BlockDriver implementation for "raw" format driver * * Copyright (C) 2010-2016 Red Hat, Inc. * Copyright (C) 2010, Blue Swirl <blauwirbel@gmail.com> diff --git a/block/sheepdog.c b/block/sheepdog.c index 4c9af89180..5637e0cd37 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -664,7 +664,7 @@ static coroutine_fn void do_co_req(void *opaque) co = qemu_coroutine_self(); aio_set_fd_handler(srco->aio_context, sockfd, false, - NULL, restart_co_req, co); + NULL, restart_co_req, NULL, co); ret = send_co_req(sockfd, hdr, data, wlen); if (ret < 0) { @@ -672,7 +672,7 @@ static coroutine_fn void do_co_req(void *opaque) } aio_set_fd_handler(srco->aio_context, sockfd, false, - restart_co_req, NULL, co); + restart_co_req, NULL, NULL, co); ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr)); if (ret != sizeof(*hdr)) { @@ -698,7 +698,7 @@ out: /* there is at most one request for this sockfd, so it is safe to * set each handler to NULL. */ aio_set_fd_handler(srco->aio_context, sockfd, false, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); srco->ret = ret; srco->finished = true; @@ -760,7 +760,7 @@ static coroutine_fn void reconnect_to_sdog(void *opaque) AIOReq *aio_req, *next; aio_set_fd_handler(s->aio_context, s->fd, false, NULL, - NULL, NULL); + NULL, NULL, NULL); close(s->fd); s->fd = -1; @@ -964,7 +964,7 @@ static int get_sheep_fd(BDRVSheepdogState *s, Error **errp) } aio_set_fd_handler(s->aio_context, fd, false, - co_read_response, NULL, s); + co_read_response, NULL, NULL, s); return fd; } @@ -1226,7 +1226,7 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, qemu_co_mutex_lock(&s->lock); s->co_send = qemu_coroutine_self(); aio_set_fd_handler(s->aio_context, s->fd, false, - co_read_response, co_write_request, s); + co_read_response, co_write_request, NULL, s); socket_set_cork(s->fd, 1); /* send a header */ @@ -1245,7 +1245,7 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, out: socket_set_cork(s->fd, 0); aio_set_fd_handler(s->aio_context, s->fd, false, - co_read_response, NULL, s); + co_read_response, NULL, NULL, s); s->co_send = NULL; qemu_co_mutex_unlock(&s->lock); } @@ -1396,7 +1396,7 @@ static void sd_detach_aio_context(BlockDriverState *bs) BDRVSheepdogState *s = bs->opaque; aio_set_fd_handler(s->aio_context, s->fd, false, NULL, - NULL, NULL); + NULL, NULL, NULL); } static void sd_attach_aio_context(BlockDriverState *bs, @@ -1406,7 +1406,7 @@ static void sd_attach_aio_context(BlockDriverState *bs, s->aio_context = new_context; aio_set_fd_handler(new_context, s->fd, false, - co_read_response, NULL, s); + co_read_response, NULL, NULL, s); } /* TODO Convert to fine grained options */ @@ -1520,7 +1520,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, return 0; out: aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, - false, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL); if (s->fd >= 0) { closesocket(s->fd); } @@ -1559,7 +1559,7 @@ static void sd_reopen_commit(BDRVReopenState *state) if (s->fd) { aio_set_fd_handler(s->aio_context, s->fd, false, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); closesocket(s->fd); } @@ -1583,7 +1583,7 @@ static void sd_reopen_abort(BDRVReopenState *state) if (re_s->fd) { aio_set_fd_handler(s->aio_context, re_s->fd, false, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); closesocket(re_s->fd); } @@ -1972,7 +1972,7 @@ static void sd_close(BlockDriverState *bs) } aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, - false, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL); closesocket(s->fd); g_free(s->host_spec); } diff --git a/block/ssh.c b/block/ssh.c index 15ed2818c5..e0edf20f78 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -911,7 +911,7 @@ static coroutine_fn void set_fd_handler(BDRVSSHState *s, BlockDriverState *bs) rd_handler, wr_handler); aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, - false, rd_handler, wr_handler, co); + false, rd_handler, wr_handler, NULL, co); } static coroutine_fn void clear_fd_handler(BDRVSSHState *s, @@ -919,7 +919,7 @@ static coroutine_fn void clear_fd_handler(BDRVSSHState *s, { DPRINTF("s->sock=%d", s->sock); aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, - false, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL); } /* A non-blocking call returned EAGAIN, so yield, ensuring the diff --git a/block/trace-events b/block/trace-events index cfc05f2478..671a6a851c 100644 --- a/block/trace-events +++ b/block/trace-events @@ -53,8 +53,8 @@ qmp_block_job_resume(void *job) "job %p" qmp_block_job_complete(void *job) "job %p" qmp_block_stream(void *bs, void *job) "bs %p job %p" -# block/raw-win32.c -# block/raw-posix.c +# block/file-win32.c +# block/file-posix.c paio_submit_co(int64_t offset, int count, int type) "offset %"PRId64" count %d type %d" paio_submit(void *acb, void *opaque, int64_t offset, int count, int type) "acb %p opaque %p offset %"PRId64" count %d type %d" diff --git a/block/win32-aio.c b/block/win32-aio.c index 95e3ab1541..8cdf73b00d 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -175,7 +175,7 @@ int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile) void win32_aio_detach_aio_context(QEMUWin32AIOState *aio, AioContext *old_context) { - aio_set_event_notifier(old_context, &aio->e, false, NULL); + aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL); aio->is_aio_context_attached = false; } @@ -184,7 +184,7 @@ void win32_aio_attach_aio_context(QEMUWin32AIOState *aio, { aio->is_aio_context_attached = true; aio_set_event_notifier(new_context, &aio->e, false, - win32_aio_completion_cb); + win32_aio_completion_cb, NULL); } QEMUWin32AIOState *win32_aio_init(void) diff --git a/configure b/configure index 3770d7c263..86f5214dd0 100755 --- a/configure +++ b/configure @@ -28,8 +28,6 @@ TMPB="qemu-conf" TMPC="${TMPDIR1}/${TMPB}.c" TMPO="${TMPDIR1}/${TMPB}.o" TMPCXX="${TMPDIR1}/${TMPB}.cxx" -TMPL="${TMPDIR1}/${TMPB}.lo" -TMPA="${TMPDIR1}/lib${TMPB}.la" TMPE="${TMPDIR1}/${TMPB}.exe" TMPMO="${TMPDIR1}/${TMPB}.mo" @@ -313,6 +311,7 @@ gnutls_rnd="" nettle="" nettle_kdf="no" gcrypt="" +gcrypt_hmac="no" gcrypt_kdf="no" vte="" virglrenderer="" @@ -2417,6 +2416,19 @@ EOF if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then gcrypt_kdf=yes fi + + cat > $TMPC << EOF +#include <gcrypt.h> +int main(void) { + gcry_mac_hd_t handle; + gcry_mac_open(&handle, GCRY_MAC_HMAC_MD5, + GCRY_MAC_FLAG_SECURE, NULL); + return 0; +} +EOF + if compile_prog "$gcrypt_cflags" "$gcrypt_libs" ; then + gcrypt_hmac=yes + fi else if test "$gcrypt" = "yes"; then feature_not_found "gcrypt" "Install gcrypt devel" @@ -2738,7 +2750,7 @@ if compile_prog "" "" ; then fi ########################################## -# xfsctl() probe, used for raw-posix +# xfsctl() probe, used for file-posix.c if test "$xfs" != "no" ; then cat > $TMPC << EOF #include <stddef.h> /* NULL */ @@ -5387,6 +5399,9 @@ if test "$gnutls_rnd" = "yes" ; then fi if test "$gcrypt" = "yes" ; then echo "CONFIG_GCRYPT=y" >> $config_host_mak + if test "$gcrypt_hmac" = "yes" ; then + echo "CONFIG_GCRYPT_HMAC=y" >> $config_host_mak + fi if test "$gcrypt_kdf" = "yes" ; then echo "CONFIG_GCRYPT_KDF=y" >> $config_host_mak fi diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index a36d2d9bdf..1f749f2087 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -3,6 +3,10 @@ crypto-obj-y += hash.o crypto-obj-$(CONFIG_NETTLE) += hash-nettle.o crypto-obj-$(if $(CONFIG_NETTLE),n,$(CONFIG_GCRYPT)) += hash-gcrypt.o crypto-obj-$(if $(CONFIG_NETTLE),n,$(if $(CONFIG_GCRYPT),n,y)) += hash-glib.o +crypto-obj-y += hmac.o +crypto-obj-$(CONFIG_NETTLE) += hmac-nettle.o +crypto-obj-$(CONFIG_GCRYPT_HMAC) += hmac-gcrypt.o +crypto-obj-$(if $(CONFIG_NETTLE),n,$(if $(CONFIG_GCRYPT_HMAC),n,y)) += hmac-glib.o crypto-obj-y += aes.o crypto-obj-y += desrfb.o crypto-obj-y += cipher.o diff --git a/crypto/cipher-gcrypt.c b/crypto/cipher-gcrypt.c index c550db9008..6487ecaf37 100644 --- a/crypto/cipher-gcrypt.c +++ b/crypto/cipher-gcrypt.c @@ -29,6 +29,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, { switch (alg) { case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: @@ -99,6 +100,10 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, gcryalg = GCRY_CIPHER_DES; break; + case QCRYPTO_CIPHER_ALG_3DES: + gcryalg = GCRY_CIPHER_3DES; + break; + case QCRYPTO_CIPHER_ALG_AES_128: gcryalg = GCRY_CIPHER_AES128; break; @@ -200,6 +205,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, case QCRYPTO_CIPHER_ALG_TWOFISH_256: ctx->blocksize = 16; break; + case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_CAST5_128: ctx->blocksize = 8; break; diff --git a/crypto/cipher-nettle.c b/crypto/cipher-nettle.c index cd094cd6a5..dfc9030227 100644 --- a/crypto/cipher-nettle.c +++ b/crypto/cipher-nettle.c @@ -78,6 +78,18 @@ static void des_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, des_decrypt(ctx, length, dst, src); } +static void des3_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_encrypt(ctx, length, dst, src); +} + +static void des3_decrypt_native(cipher_ctx_t ctx, cipher_length_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_decrypt(ctx, length, dst, src); +} + static void cast128_encrypt_native(cipher_ctx_t ctx, cipher_length_t length, uint8_t *dst, const uint8_t *src) { @@ -140,6 +152,18 @@ static void des_decrypt_wrapper(const void *ctx, size_t length, des_decrypt(ctx, length, dst, src); } +static void des3_encrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_encrypt(ctx, length, dst, src); +} + +static void des3_decrypt_wrapper(const void *ctx, size_t length, + uint8_t *dst, const uint8_t *src) +{ + des3_decrypt(ctx, length, dst, src); +} + static void cast128_encrypt_wrapper(const void *ctx, size_t length, uint8_t *dst, const uint8_t *src) { @@ -197,6 +221,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, { switch (alg) { case QCRYPTO_CIPHER_ALG_DES_RFB: + case QCRYPTO_CIPHER_ALG_3DES: case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: @@ -254,6 +279,7 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, cipher->mode = mode; ctx = g_new0(QCryptoCipherNettle, 1); + cipher->opaque = ctx; switch (alg) { case QCRYPTO_CIPHER_ALG_DES_RFB: @@ -270,6 +296,18 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, ctx->blocksize = DES_BLOCK_SIZE; break; + case QCRYPTO_CIPHER_ALG_3DES: + ctx->ctx = g_new0(struct des3_ctx, 1); + des3_set_key(ctx->ctx, key); + + ctx->alg_encrypt_native = des3_encrypt_native; + ctx->alg_decrypt_native = des3_decrypt_native; + ctx->alg_encrypt_wrapper = des3_encrypt_wrapper; + ctx->alg_decrypt_wrapper = des3_decrypt_wrapper; + + ctx->blocksize = DES3_BLOCK_SIZE; + break; + case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: @@ -384,13 +422,11 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, } ctx->iv = g_new0(uint8_t, ctx->blocksize); - cipher->opaque = ctx; return cipher; error: - g_free(cipher); - g_free(ctx); + qcrypto_cipher_free(cipher); return NULL; } diff --git a/crypto/cipher.c b/crypto/cipher.c index a9bca41302..9ecaff702b 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -28,6 +28,7 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_192] = 24, [QCRYPTO_CIPHER_ALG_AES_256] = 32, [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, + [QCRYPTO_CIPHER_ALG_3DES] = 24, [QCRYPTO_CIPHER_ALG_CAST5_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_192] = 24, @@ -42,6 +43,7 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = { [QCRYPTO_CIPHER_ALG_AES_192] = 16, [QCRYPTO_CIPHER_ALG_AES_256] = 16, [QCRYPTO_CIPHER_ALG_DES_RFB] = 8, + [QCRYPTO_CIPHER_ALG_3DES] = 8, [QCRYPTO_CIPHER_ALG_CAST5_128] = 8, [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16, [QCRYPTO_CIPHER_ALG_SERPENT_192] = 16, @@ -107,8 +109,9 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg, } if (mode == QCRYPTO_CIPHER_MODE_XTS) { - if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { - error_setg(errp, "XTS mode not compatible with DES-RFB"); + if (alg == QCRYPTO_CIPHER_ALG_DES_RFB + || alg == QCRYPTO_CIPHER_ALG_3DES) { + error_setg(errp, "XTS mode not compatible with DES-RFB/3DES"); return false; } if (nkey % 2) { diff --git a/crypto/hmac-gcrypt.c b/crypto/hmac-gcrypt.c new file mode 100644 index 0000000000..21189e694f --- /dev/null +++ b/crypto/hmac-gcrypt.c @@ -0,0 +1,152 @@ +/* + * QEMU Crypto hmac algorithms (based on libgcrypt) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.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/hmac.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, +}; + +typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt; +struct QCryptoHmacGcrypt { + gcry_mac_hd_t handle; +}; + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && + qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) { + return true; + } + + return false; +} + +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoHmac *hmac; + QCryptoHmacGcrypt *ctx; + gcry_error_t err; + + if (!qcrypto_hmac_supports(alg)) { + error_setg(errp, "Unsupported hmac algorithm %s", + QCryptoHashAlgorithm_lookup[alg]); + return NULL; + } + + hmac = g_new0(QCryptoHmac, 1); + hmac->alg = alg; + + ctx = g_new0(QCryptoHmacGcrypt, 1); + + err = gcry_mac_open(&ctx->handle, qcrypto_hmac_alg_map[alg], + GCRY_MAC_FLAG_SECURE, NULL); + if (err != 0) { + error_setg(errp, "Cannot initialize hmac: %s", + gcry_strerror(err)); + goto error; + } + + err = gcry_mac_setkey(ctx->handle, (const void *)key, nkey); + if (err != 0) { + error_setg(errp, "Cannot set key: %s", + gcry_strerror(err)); + goto error; + } + + hmac->opaque = ctx; + return hmac; + +error: + g_free(ctx); + g_free(hmac); + return NULL; +} + +void qcrypto_hmac_free(QCryptoHmac *hmac) +{ + QCryptoHmacGcrypt *ctx; + + if (!hmac) { + return; + } + + ctx = hmac->opaque; + gcry_mac_close(ctx->handle); + + g_free(ctx); + g_free(hmac); +} + +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + QCryptoHmacGcrypt *ctx; + gcry_error_t err; + uint32_t ret; + int i; + + ctx = hmac->opaque; + + for (i = 0; i < niov; i++) { + gcry_mac_write(ctx->handle, iov[i].iov_base, iov[i].iov_len); + } + + ret = gcry_mac_get_algo_maclen(qcrypto_hmac_alg_map[hmac->alg]); + if (ret <= 0) { + error_setg(errp, "Unable to get hmac length: %s", + gcry_strerror(ret)); + return -1; + } + + 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 hmac %d", + *resultlen, ret); + return -1; + } + + err = gcry_mac_read(ctx->handle, *result, resultlen); + if (err != 0) { + error_setg(errp, "Cannot get result: %s", + gcry_strerror(err)); + return -1; + } + + err = gcry_mac_reset(ctx->handle); + if (err != 0) { + error_setg(errp, "Cannot reset hmac context: %s", + gcry_strerror(err)); + return -1; + } + + return 0; +} diff --git a/crypto/hmac-glib.c b/crypto/hmac-glib.c new file mode 100644 index 0000000000..08a1fdd10a --- /dev/null +++ b/crypto/hmac-glib.c @@ -0,0 +1,166 @@ +/* + * QEMU Crypto hmac algorithms (based on glib) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.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/hmac.h" + +/* Support for HMAC Algos has been added in GLib 2.30 */ +#if GLIB_CHECK_VERSION(2, 30, 0) + +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, +/* Support for HMAC SHA-512 in GLib 2.42 */ +#if GLIB_CHECK_VERSION(2, 42, 0) + [QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512, +#else + [QCRYPTO_HASH_ALG_SHA512] = -1, +#endif + [QCRYPTO_HASH_ALG_SHA224] = -1, + [QCRYPTO_HASH_ALG_SHA384] = -1, + [QCRYPTO_HASH_ALG_RIPEMD160] = -1, +}; + +typedef struct QCryptoHmacGlib QCryptoHmacGlib; +struct QCryptoHmacGlib { + GHmac *ghmac; +}; + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && + qcrypto_hmac_alg_map[alg] != -1) { + return true; + } + + return false; +} + +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoHmac *hmac; + QCryptoHmacGlib *ctx; + + if (!qcrypto_hmac_supports(alg)) { + error_setg(errp, "Unsupported hmac algorithm %s", + QCryptoHashAlgorithm_lookup[alg]); + return NULL; + } + + hmac = g_new0(QCryptoHmac, 1); + hmac->alg = alg; + + ctx = g_new0(QCryptoHmacGlib, 1); + + ctx->ghmac = g_hmac_new(qcrypto_hmac_alg_map[alg], + (const uint8_t *)key, nkey); + if (!ctx->ghmac) { + error_setg(errp, "Cannot initialize hmac and set key"); + goto error; + } + + hmac->opaque = ctx; + return hmac; + +error: + g_free(ctx); + g_free(hmac); + return NULL; +} + +void qcrypto_hmac_free(QCryptoHmac *hmac) +{ + QCryptoHmacGlib *ctx; + + if (!hmac) { + return; + } + + ctx = hmac->opaque; + g_hmac_unref(ctx->ghmac); + + g_free(ctx); + g_free(hmac); +} + +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + QCryptoHmacGlib *ctx; + int i, ret; + + ctx = hmac->opaque; + + for (i = 0; i < niov; i++) { + g_hmac_update(ctx->ghmac, iov[i].iov_base, iov[i].iov_len); + } + + ret = g_checksum_type_get_length(qcrypto_hmac_alg_map[hmac->alg]); + if (ret < 0) { + error_setg(errp, "Unable to get hmac length"); + return -1; + } + + 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 hmac %d", + *resultlen, ret); + return -1; + } + + g_hmac_get_digest(ctx->ghmac, *result, resultlen); + + return 0; +} + +#else + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + return false; +} + +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + return NULL; +} + +void qcrypto_hmac_free(QCryptoHmac *hmac) +{ + return; +} + +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + return -1; +} + +#endif diff --git a/crypto/hmac-nettle.c b/crypto/hmac-nettle.c new file mode 100644 index 0000000000..4a9e6b2c7d --- /dev/null +++ b/crypto/hmac-nettle.c @@ -0,0 +1,175 @@ +/* + * QEMU Crypto hmac algorithms (based on nettle) + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.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/hmac.h" +#include <nettle/hmac.h> + +typedef void (*qcrypto_nettle_hmac_setkey)(void *ctx, + size_t key_length, const uint8_t *key); + +typedef void (*qcrypto_nettle_hmac_update)(void *ctx, + size_t length, const uint8_t *data); + +typedef void (*qcrypto_nettle_hmac_digest)(void *ctx, + size_t length, uint8_t *digest); + +typedef struct QCryptoHmacNettle QCryptoHmacNettle; +struct QCryptoHmacNettle { + union qcrypto_nettle_hmac_ctx { + struct hmac_md5_ctx md5_ctx; + struct hmac_sha1_ctx sha1_ctx; + struct hmac_sha256_ctx sha256_ctx; /* equals hmac_sha224_ctx */ + struct hmac_sha512_ctx sha512_ctx; /* equals hmac_sha384_ctx */ + struct hmac_ripemd160_ctx ripemd160_ctx; + } u; +}; + +struct qcrypto_nettle_hmac_alg { + qcrypto_nettle_hmac_setkey setkey; + 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] = { + .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] = { + .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] = { + .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] = { + .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] = { + .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] = { + .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] = { + .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, + .len = RIPEMD160_DIGEST_SIZE, + }, +}; + +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg) +{ + if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) && + qcrypto_hmac_alg_map[alg].setkey != NULL) { + return true; + } + + return false; +} + +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp) +{ + QCryptoHmac *hmac; + QCryptoHmacNettle *ctx; + + if (!qcrypto_hmac_supports(alg)) { + error_setg(errp, "Unsupported hmac algorithm %s", + QCryptoHashAlgorithm_lookup[alg]); + return NULL; + } + + hmac = g_new0(QCryptoHmac, 1); + hmac->alg = alg; + + ctx = g_new0(QCryptoHmacNettle, 1); + + qcrypto_hmac_alg_map[alg].setkey(&ctx->u, nkey, key); + + hmac->opaque = ctx; + + return hmac; +} + +void qcrypto_hmac_free(QCryptoHmac *hmac) +{ + QCryptoHmacNettle *ctx; + + if (!hmac) { + return; + } + + ctx = hmac->opaque; + + g_free(ctx); + g_free(hmac); +} + +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + QCryptoHmacNettle *ctx; + int i; + + ctx = (QCryptoHmacNettle *)hmac->opaque; + + for (i = 0; i < niov; ++i) { + size_t len = iov[i].iov_len; + uint8_t *base = iov[i].iov_base; + while (len) { + size_t shortlen = MIN(len, UINT_MAX); + qcrypto_hmac_alg_map[hmac->alg].update(&ctx->u, len, base); + len -= shortlen; + base += len; + } + } + + if (*resultlen == 0) { + *resultlen = qcrypto_hmac_alg_map[hmac->alg].len; + *result = g_new0(uint8_t, *resultlen); + } else if (*resultlen != qcrypto_hmac_alg_map[hmac->alg].len) { + error_setg(errp, + "Result buffer size %zu is smaller than hash %zu", + *resultlen, qcrypto_hmac_alg_map[hmac->alg].len); + return -1; + } + + qcrypto_hmac_alg_map[hmac->alg].digest(&ctx->u, *resultlen, *result); + + return 0; +} diff --git a/crypto/hmac.c b/crypto/hmac.c new file mode 100644 index 0000000000..5750405cfb --- /dev/null +++ b/crypto/hmac.c @@ -0,0 +1,72 @@ +/* + * QEMU Crypto hmac algorithms + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES 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. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/hmac.h" + +static const char hex[] = "0123456789abcdef"; + +int qcrypto_hmac_bytes(QCryptoHmac *hmac, + const char *buf, + size_t len, + uint8_t **result, + size_t *resultlen, + Error **errp) +{ + struct iovec iov = { + .iov_base = (char *)buf, + .iov_len = len + }; + + return qcrypto_hmac_bytesv(hmac, &iov, 1, result, resultlen, errp); +} + +int qcrypto_hmac_digestv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + char **digest, + Error **errp) +{ + uint8_t *result = NULL; + size_t resultlen = 0; + size_t i; + + if (qcrypto_hmac_bytesv(hmac, iov, niov, &result, &resultlen, errp) < 0) { + 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]; + } + + (*digest)[resultlen * 2] = '\0'; + + g_free(result); + return 0; +} + +int qcrypto_hmac_digest(QCryptoHmac *hmac, + const char *buf, + size_t len, + char **digest, + Error **errp) +{ + struct iovec iov = { + .iov_base = (char *)buf, + .iov_len = len + }; + + return qcrypto_hmac_digestv(hmac, &iov, 1, digest, errp); +} diff --git a/crypto/hmac.h b/crypto/hmac.h new file mode 100644 index 0000000000..0d3acd728a --- /dev/null +++ b/crypto/hmac.h @@ -0,0 +1,166 @@ +/* + * QEMU Crypto hmac algorithms + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES 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. + * + */ + +#ifndef QCRYPTO_HMAC_H +#define QCRYPTO_HMAC_H + +#include "qapi-types.h" + +typedef struct QCryptoHmac QCryptoHmac; +struct QCryptoHmac { + QCryptoHashAlgorithm alg; + void *opaque; +}; + +/** + * qcrypto_hmac_supports: + * @alg: the hmac algorithm + * + * Determine if @alg hmac algorithm is supported by + * the current configured build + * + * Returns: + * true if the algorithm is supported, false otherwise + */ +bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg); + +/** + * qcrypto_hmac_new: + * @alg: the hmac algorithm + * @key: the key bytes + * @nkey: the length of @key + * @errp: pointer to a NULL-initialized error object + * + * Creates a new hmac object with the algorithm @alg + * + * The @key parameter provides the bytes representing + * the secret key to use. The @nkey parameter specifies + * the length of @key in bytes + * + * Note: must use qcrypto_hmac_free() to release the + * returned hmac object when no longer required + * + * Returns: + * a new hmac object, or NULL on error + */ +QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg, + const uint8_t *key, size_t nkey, + Error **errp); + +/** + * qcrypto_hmac_free: + * @hmac: the hmac object + * + * Release the memory associated with @hmac that was + * previously allocated by qcrypto_hmac_new() + */ +void qcrypto_hmac_free(QCryptoHmac *hmac); + +/** + * qcrypto_hmac_bytesv: + * @hmac: the hmac object + * @iov: the array of memory regions to hmac + * @niov: the length of @iov + * @result: pointer to hold output hmac + * @resultlen: pointer to hold length of @result + * @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. + * + * Returns: + * 0 on success, -1 on error + */ +int qcrypto_hmac_bytesv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + uint8_t **result, + size_t *resultlen, + Error **errp); + +/** + * qcrypto_hmac_bytes: + * @hmac: the hmac object + * @buf: the memory region to hmac + * @len: the length of @buf + * @result: pointer to hold output hmac + * @resultlen: pointer to hold length of @result + * @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. + * + * Returns: + * 0 on success, -1 on error + */ +int qcrypto_hmac_bytes(QCryptoHmac *hmac, + const char *buf, + size_t len, + uint8_t **result, + size_t *resultlen, + Error **errp); + +/** + * qcrypto_hmac_digestv: + * @hmac: the hmac object + * @iov: the array of memory regions to hmac + * @niov: the length of @iov + * @digest: pointer to hold output hmac + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory regions + * present in @iov. The @digest pointer will be + * filled with the printable hex digest of the computed + * hmac, 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_hmac_digestv(QCryptoHmac *hmac, + const struct iovec *iov, + size_t niov, + char **digest, + Error **errp); + +/** + * qcrypto_hmac_digest: + * @hmac: the hmac object + * @buf: the memory region to hmac + * @len: the length of @buf + * @digest: pointer to hold output hmac + * @errp: pointer to a NULL-initialized error object + * + * Computes the hmac across all the memory region + * @buf of length @len. The @digest pointer will be + * filled with the printable hex digest of the computed + * hmac, 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_hmac_digest(QCryptoHmac *hmac, + const char *buf, + size_t len, + char **digest, + Error **errp); + +#endif diff --git a/disas/cris.c b/disas/cris.c index 7f35bc0c6b..08161d1f21 100644 --- a/disas/cris.c +++ b/disas/cris.c @@ -21,9 +21,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "disas/bfd.h" -//#include "sysdep.h" -#include "target-cris/opcode-cris.h" -//#include "libiberty.h" +#include "target/cris/opcode-cris.h" #define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) diff --git a/disas/m68k.c b/disas/m68k.c index 8e7c3f76c4..073abb9efd 100644 --- a/disas/m68k.c +++ b/disas/m68k.c @@ -4698,10 +4698,6 @@ get_field (const unsigned char *data, enum floatformat_byteorders order, return result; } -#ifndef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif - /* Convert from FMT to a double. FROM is the address of the extended float. Store the double in *TO. */ @@ -4733,7 +4729,7 @@ floatformat_to_double (const struct floatformat *fmt, nan = 0; while (mant_bits_left > 0) { - mant_bits = min (mant_bits_left, 32); + mant_bits = MIN(mant_bits_left, 32); if (get_field (ufrom, fmt->byteorder, fmt->totalsize, mant_off, mant_bits) != 0) @@ -4793,7 +4789,7 @@ floatformat_to_double (const struct floatformat *fmt, while (mant_bits_left > 0) { - mant_bits = min (mant_bits_left, 32); + mant_bits = MIN(mant_bits_left, 32); mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, mant_off, mant_bits); diff --git a/docs/replay.txt b/docs/replay.txt index 779c6c059e..347b2ff055 100644 --- a/docs/replay.txt +++ b/docs/replay.txt @@ -195,3 +195,17 @@ Queue is flushed at checkpoints and information about processed requests is recorded to the log. In replay phase the queue is matched with events read from the log. Therefore block devices requests are processed deterministically. + +Network devices +--------------- + +Record and replay for network interactions is performed with the network filter. +Each backend must have its own instance of the replay filter as follows: + -netdev user,id=net1 -device rtl8139,netdev=net1 + -object filter-replay,id=replay,netdev=net1 + +Replay network filter is used to record and replay network packets. While +recording the virtual machine this filter puts all packets coming from +the outer world into the log. In replay mode packets from the log are +injected into the network device. All interactions with network backend +in replay mode are disabled. diff --git a/exec.c b/exec.c index 08c558eecf..8d4bb0e8c1 100644 --- a/exec.c +++ b/exec.c @@ -2938,6 +2938,31 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_ return true; } +static hwaddr +address_space_extend_translation(AddressSpace *as, hwaddr addr, hwaddr target_len, + MemoryRegion *mr, hwaddr base, hwaddr len, + bool is_write) +{ + hwaddr done = 0; + hwaddr xlat; + MemoryRegion *this_mr; + + for (;;) { + target_len -= len; + addr += len; + done += len; + if (target_len == 0) { + return done; + } + + len = target_len; + this_mr = address_space_translate(as, addr, &xlat, &len, is_write); + if (this_mr != mr || xlat != base + done) { + return done; + } + } +} + /* 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 if resources needed to perform the mapping are exhausted. @@ -2951,9 +2976,8 @@ void *address_space_map(AddressSpace *as, bool is_write) { hwaddr len = *plen; - hwaddr done = 0; - hwaddr l, xlat, base; - MemoryRegion *mr, *this_mr; + hwaddr l, xlat; + MemoryRegion *mr; void *ptr; if (len == 0) { @@ -2987,26 +3011,10 @@ void *address_space_map(AddressSpace *as, return bounce.buffer; } - base = xlat; - - for (;;) { - len -= l; - addr += l; - done += l; - if (len == 0) { - break; - } - - l = len; - this_mr = address_space_translate(as, addr, &xlat, &l, is_write); - if (this_mr != mr || xlat != base + done) { - break; - } - } memory_region_ref(mr); - *plen = done; - ptr = qemu_ram_ptr_length(mr->ram_block, base, plen); + *plen = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write); + ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen); rcu_read_unlock(); return ptr; @@ -3058,597 +3066,92 @@ void cpu_physical_memory_unmap(void *buffer, hwaddr len, return address_space_unmap(&address_space_memory, buffer, len, is_write, access_len); } -/* warning: addr must be aligned */ -static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, - MemTxResult *result, - enum device_endian endian) -{ - uint8_t *ptr; - uint64_t val; - MemoryRegion *mr; - hwaddr l = 4; - hwaddr addr1; - MemTxResult r; - bool release_lock = false; - - rcu_read_lock(); - mr = address_space_translate(as, addr, &addr1, &l, false); - if (l < 4 || !memory_access_is_direct(mr, false)) { - release_lock |= prepare_mmio_access(mr); - - /* I/O case */ - r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs); -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap32(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap32(val); - } -#endif - } else { - /* RAM case */ - ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - switch (endian) { - case DEVICE_LITTLE_ENDIAN: - val = ldl_le_p(ptr); - break; - case DEVICE_BIG_ENDIAN: - val = ldl_be_p(ptr); - break; - default: - val = ldl_p(ptr); - break; - } - r = MEMTX_OK; - } - if (result) { - *result = r; - } - if (release_lock) { - qemu_mutex_unlock_iothread(); - } - rcu_read_unlock(); - return val; -} - -uint32_t address_space_ldl(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_ldl_internal(as, addr, attrs, result, - DEVICE_NATIVE_ENDIAN); -} - -uint32_t address_space_ldl_le(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_ldl_internal(as, addr, attrs, result, - DEVICE_LITTLE_ENDIAN); -} - -uint32_t address_space_ldl_be(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_ldl_internal(as, addr, attrs, result, - DEVICE_BIG_ENDIAN); -} - -uint32_t ldl_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_ldl(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_ldl_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -/* warning: addr must be aligned */ -static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, - MemTxResult *result, - enum device_endian endian) -{ - uint8_t *ptr; - uint64_t val; - MemoryRegion *mr; - hwaddr l = 8; - hwaddr addr1; - MemTxResult r; - bool release_lock = false; - - rcu_read_lock(); - mr = address_space_translate(as, addr, &addr1, &l, - false); - if (l < 8 || !memory_access_is_direct(mr, false)) { - release_lock |= prepare_mmio_access(mr); - - /* I/O case */ - r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs); -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap64(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap64(val); - } -#endif - } else { - /* RAM case */ - ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - switch (endian) { - case DEVICE_LITTLE_ENDIAN: - val = ldq_le_p(ptr); - break; - case DEVICE_BIG_ENDIAN: - val = ldq_be_p(ptr); - break; - default: - val = ldq_p(ptr); - break; - } - r = MEMTX_OK; - } - if (result) { - *result = r; - } - if (release_lock) { - qemu_mutex_unlock_iothread(); - } - rcu_read_unlock(); - return val; -} - -uint64_t address_space_ldq(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_ldq_internal(as, addr, attrs, result, - DEVICE_NATIVE_ENDIAN); -} - -uint64_t address_space_ldq_le(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_ldq_internal(as, addr, attrs, result, - DEVICE_LITTLE_ENDIAN); -} - -uint64_t address_space_ldq_be(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_ldq_internal(as, addr, attrs, result, - DEVICE_BIG_ENDIAN); -} - -uint64_t ldq_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_ldq(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_ldq_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_ldq_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -/* XXX: optimize */ -uint32_t address_space_ldub(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - uint8_t val; - MemTxResult r; - - r = address_space_rw(as, addr, attrs, &val, 1, 0); - if (result) { - *result = r; - } - return val; -} - -uint32_t ldub_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -/* warning: addr must be aligned */ -static inline uint32_t address_space_lduw_internal(AddressSpace *as, - hwaddr addr, - MemTxAttrs attrs, - MemTxResult *result, - enum device_endian endian) -{ - uint8_t *ptr; - uint64_t val; - MemoryRegion *mr; - hwaddr l = 2; - hwaddr addr1; - MemTxResult r; - bool release_lock = false; - - rcu_read_lock(); - mr = address_space_translate(as, addr, &addr1, &l, - false); - if (l < 2 || !memory_access_is_direct(mr, false)) { - release_lock |= prepare_mmio_access(mr); - - /* I/O case */ - r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs); -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap16(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap16(val); - } -#endif - } else { - /* RAM case */ - ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - switch (endian) { - case DEVICE_LITTLE_ENDIAN: - val = lduw_le_p(ptr); - break; - case DEVICE_BIG_ENDIAN: - val = lduw_be_p(ptr); - break; - default: - val = lduw_p(ptr); - break; - } - r = MEMTX_OK; - } - if (result) { - *result = r; - } - if (release_lock) { - qemu_mutex_unlock_iothread(); - } - rcu_read_unlock(); - return val; -} - -uint32_t address_space_lduw(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_lduw_internal(as, addr, attrs, result, - DEVICE_NATIVE_ENDIAN); -} - -uint32_t address_space_lduw_le(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_lduw_internal(as, addr, attrs, result, - DEVICE_LITTLE_ENDIAN); -} - -uint32_t address_space_lduw_be(AddressSpace *as, hwaddr addr, - MemTxAttrs attrs, MemTxResult *result) -{ - return address_space_lduw_internal(as, addr, attrs, result, - DEVICE_BIG_ENDIAN); -} - -uint32_t lduw_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_lduw(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr) -{ - return address_space_lduw_be(as, addr, MEMTXATTRS_UNSPECIFIED, NULL); -} - -/* warning: addr must be aligned. The ram page is not masked as dirty - and the code inside is not invalidated. It is useful if the dirty - bits are used to track modified PTEs */ -void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - uint8_t *ptr; - MemoryRegion *mr; - hwaddr l = 4; - hwaddr addr1; - MemTxResult r; - uint8_t dirty_log_mask; - bool release_lock = false; - - rcu_read_lock(); - mr = address_space_translate(as, addr, &addr1, &l, - true); - if (l < 4 || !memory_access_is_direct(mr, true)) { - release_lock |= prepare_mmio_access(mr); - - r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); - } else { - ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - stl_p(ptr, val); - - dirty_log_mask = memory_region_get_dirty_log_mask(mr); - dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE); - cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr, - 4, dirty_log_mask); - r = MEMTX_OK; - } - if (result) { - *result = r; - } - if (release_lock) { - qemu_mutex_unlock_iothread(); - } - rcu_read_unlock(); -} - -void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val) -{ - address_space_stl_notdirty(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} - -/* warning: addr must be aligned */ -static inline void address_space_stl_internal(AddressSpace *as, - hwaddr addr, uint32_t val, - MemTxAttrs attrs, - MemTxResult *result, - enum device_endian endian) -{ - uint8_t *ptr; - MemoryRegion *mr; - hwaddr l = 4; - hwaddr addr1; - MemTxResult r; - bool release_lock = false; - - rcu_read_lock(); - mr = address_space_translate(as, addr, &addr1, &l, - true); - if (l < 4 || !memory_access_is_direct(mr, true)) { - release_lock |= prepare_mmio_access(mr); - -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap32(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap32(val); - } -#endif - r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); - } else { - /* RAM case */ - ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - switch (endian) { - case DEVICE_LITTLE_ENDIAN: - stl_le_p(ptr, val); - break; - case DEVICE_BIG_ENDIAN: - stl_be_p(ptr, val); - break; - default: - stl_p(ptr, val); - break; - } - invalidate_and_set_dirty(mr, addr1, 4); - r = MEMTX_OK; - } - if (result) { - *result = r; - } - if (release_lock) { - qemu_mutex_unlock_iothread(); - } - rcu_read_unlock(); -} - -void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - address_space_stl_internal(as, addr, val, attrs, result, - DEVICE_NATIVE_ENDIAN); -} - -void address_space_stl_le(AddressSpace *as, hwaddr addr, uint32_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - address_space_stl_internal(as, addr, val, attrs, result, - DEVICE_LITTLE_ENDIAN); -} - -void address_space_stl_be(AddressSpace *as, hwaddr addr, uint32_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - address_space_stl_internal(as, addr, val, attrs, result, - DEVICE_BIG_ENDIAN); -} - -void stl_phys(AddressSpace *as, hwaddr addr, uint32_t val) -{ - address_space_stl(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} - -void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val) -{ - address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} - -void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val) -{ - address_space_stl_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} - -/* XXX: optimize */ -void address_space_stb(AddressSpace *as, hwaddr addr, uint32_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - uint8_t v = val; - MemTxResult r; - - r = address_space_rw(as, addr, attrs, &v, 1, 1); - if (result) { - *result = r; - } -} - -void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val) -{ - address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} +#define ARG1_DECL AddressSpace *as +#define ARG1 as +#define SUFFIX +#define TRANSLATE(...) address_space_translate(as, __VA_ARGS__) +#define IS_DIRECT(mr, is_write) memory_access_is_direct(mr, is_write) +#define MAP_RAM(mr, ofs) qemu_map_ram_ptr((mr)->ram_block, ofs) +#define INVALIDATE(mr, ofs, len) invalidate_and_set_dirty(mr, ofs, len) +#define RCU_READ_LOCK(...) rcu_read_lock() +#define RCU_READ_UNLOCK(...) rcu_read_unlock() +#include "memory_ldst.inc.c" -/* warning: addr must be aligned */ -static inline void address_space_stw_internal(AddressSpace *as, - hwaddr addr, uint32_t val, - MemTxAttrs attrs, - MemTxResult *result, - enum device_endian endian) +int64_t address_space_cache_init(MemoryRegionCache *cache, + AddressSpace *as, + hwaddr addr, + hwaddr len, + bool is_write) { - uint8_t *ptr; + hwaddr l, xlat; MemoryRegion *mr; - hwaddr l = 2; - hwaddr addr1; - MemTxResult r; - bool release_lock = false; + void *ptr; - rcu_read_lock(); - mr = address_space_translate(as, addr, &addr1, &l, true); - if (l < 2 || !memory_access_is_direct(mr, true)) { - release_lock |= prepare_mmio_access(mr); + assert(len > 0); -#if defined(TARGET_WORDS_BIGENDIAN) - if (endian == DEVICE_LITTLE_ENDIAN) { - val = bswap16(val); - } -#else - if (endian == DEVICE_BIG_ENDIAN) { - val = bswap16(val); - } -#endif - r = memory_region_dispatch_write(mr, addr1, val, 2, attrs); - } else { - /* RAM case */ - ptr = qemu_map_ram_ptr(mr->ram_block, addr1); - switch (endian) { - case DEVICE_LITTLE_ENDIAN: - stw_le_p(ptr, val); - break; - case DEVICE_BIG_ENDIAN: - stw_be_p(ptr, val); - break; - default: - stw_p(ptr, val); - break; - } - invalidate_and_set_dirty(mr, addr1, 2); - r = MEMTX_OK; - } - if (result) { - *result = r; - } - if (release_lock) { - qemu_mutex_unlock_iothread(); + l = len; + mr = address_space_translate(as, addr, &xlat, &l, is_write); + if (!memory_access_is_direct(mr, is_write)) { + return -EINVAL; } - rcu_read_unlock(); -} - -void address_space_stw(AddressSpace *as, hwaddr addr, uint32_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - address_space_stw_internal(as, addr, val, attrs, result, - DEVICE_NATIVE_ENDIAN); -} -void address_space_stw_le(AddressSpace *as, hwaddr addr, uint32_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - address_space_stw_internal(as, addr, val, attrs, result, - DEVICE_LITTLE_ENDIAN); -} + l = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write); + ptr = qemu_ram_ptr_length(mr->ram_block, xlat, &l); -void address_space_stw_be(AddressSpace *as, hwaddr addr, uint32_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - address_space_stw_internal(as, addr, val, attrs, result, - DEVICE_BIG_ENDIAN); -} + cache->xlat = xlat; + cache->is_write = is_write; + cache->mr = mr; + cache->ptr = ptr; + cache->len = l; + memory_region_ref(cache->mr); -void stw_phys(AddressSpace *as, hwaddr addr, uint32_t val) -{ - address_space_stw(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} - -void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val) -{ - address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); + return l; } -void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val) +void address_space_cache_invalidate(MemoryRegionCache *cache, + hwaddr addr, + hwaddr access_len) { - address_space_stw_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); + assert(cache->is_write); + invalidate_and_set_dirty(cache->mr, addr + cache->xlat, access_len); } -/* XXX: optimize */ -void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val, - MemTxAttrs attrs, MemTxResult *result) +void address_space_cache_destroy(MemoryRegionCache *cache) { - MemTxResult r; - val = tswap64(val); - r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1); - if (result) { - *result = r; + if (!cache->mr) { + return; } -} -void address_space_stq_le(AddressSpace *as, hwaddr addr, uint64_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - MemTxResult r; - val = cpu_to_le64(val); - r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1); - if (result) { - *result = r; - } -} -void address_space_stq_be(AddressSpace *as, hwaddr addr, uint64_t val, - MemTxAttrs attrs, MemTxResult *result) -{ - MemTxResult r; - val = cpu_to_be64(val); - r = address_space_rw(as, addr, attrs, (void *) &val, 8, 1); - if (result) { - *result = r; + if (xen_enabled()) { + xen_invalidate_map_cache_entry(cache->ptr); } + memory_region_unref(cache->mr); } -void stq_phys(AddressSpace *as, hwaddr addr, uint64_t val) -{ - address_space_stq(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} - -void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val) -{ - address_space_stq_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} - -void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val) -{ - address_space_stq_be(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); -} +/* Called from RCU critical section. This function has the same + * semantics as address_space_translate, but it only works on a + * predefined range of a MemoryRegion that was mapped with + * address_space_cache_init. + */ +static inline MemoryRegion *address_space_translate_cached( + MemoryRegionCache *cache, hwaddr addr, hwaddr *xlat, + hwaddr *plen, bool is_write) +{ + assert(addr < cache->len && *plen <= cache->len - addr); + *xlat = addr + cache->xlat; + return cache->mr; +} + +#define ARG1_DECL MemoryRegionCache *cache +#define ARG1 cache +#define SUFFIX _cached +#define TRANSLATE(...) address_space_translate_cached(cache, __VA_ARGS__) +#define IS_DIRECT(mr, is_write) true +#define MAP_RAM(mr, ofs) (cache->ptr + (ofs - cache->xlat)) +#define INVALIDATE(mr, ofs, len) ((void)0) +#define RCU_READ_LOCK() ((void)0) +#define RCU_READ_UNLOCK() ((void)0) +#include "memory_ldst.inc.c" /* virtual memory access for debug (includes writing to ROM) */ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index faebd91f5f..fa58877570 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -47,7 +47,7 @@ ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) va_list ap; va_start(ap, fmt); - ret = virtio_pdu_vmarshal(pdu, offset, fmt, ap); + ret = pdu->s->transport->pdu_vmarshal(pdu, offset, fmt, ap); va_end(ap); return ret; @@ -59,7 +59,7 @@ ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) va_list ap; va_start(ap, fmt); - ret = virtio_pdu_vunmarshal(pdu, offset, fmt, ap); + ret = pdu->s->transport->pdu_vunmarshal(pdu, offset, fmt, ap); va_end(ap); return ret; @@ -67,7 +67,7 @@ ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) static void pdu_push_and_notify(V9fsPDU *pdu) { - virtio_9p_push_and_notify(pdu); + pdu->s->transport->push_and_notify(pdu); } static int omode_to_uflags(int8_t mode) @@ -1633,14 +1633,43 @@ out_nofid: pdu_complete(pdu, err); } +/* + * Create a QEMUIOVector for a sub-region of PDU iovecs + * + * @qiov: uninitialized QEMUIOVector + * @skip: number of bytes to skip from beginning of PDU + * @size: number of bytes to include + * @is_write: true - write, false - read + * + * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up + * with qemu_iovec_destroy(). + */ +static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu, + size_t skip, size_t size, + bool is_write) +{ + QEMUIOVector elem; + struct iovec *iov; + unsigned int niov; + + if (is_write) { + pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov); + } else { + pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size); + } + + qemu_iovec_init_external(&elem, iov, niov); + qemu_iovec_init(qiov, niov); + qemu_iovec_concat(qiov, &elem, skip, size); +} + static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, uint64_t off, uint32_t max_count) { ssize_t err; size_t offset = 7; uint64_t read_count; - V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); - VirtQueueElement *elem = v->elems[pdu->idx]; + QEMUIOVector qiov_full; if (fidp->fs.xattr.len < off) { read_count = 0; @@ -1656,9 +1685,11 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, } offset += err; - err = v9fs_pack(elem->in_sg, elem->in_num, offset, + v9fs_init_qiov_from_pdu(&qiov_full, pdu, 0, read_count, false); + err = v9fs_pack(qiov_full.iov, qiov_full.niov, offset, ((char *)fidp->fs.xattr.value) + off, read_count); + qemu_iovec_destroy(&qiov_full); if (err < 0) { return err; } @@ -1732,32 +1763,6 @@ static int coroutine_fn v9fs_do_readdir_with_stat(V9fsPDU *pdu, return count; } -/* - * Create a QEMUIOVector for a sub-region of PDU iovecs - * - * @qiov: uninitialized QEMUIOVector - * @skip: number of bytes to skip from beginning of PDU - * @size: number of bytes to include - * @is_write: true - write, false - read - * - * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up - * with qemu_iovec_destroy(). - */ -static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu, - size_t skip, size_t size, - bool is_write) -{ - QEMUIOVector elem; - struct iovec *iov; - unsigned int niov; - - virtio_init_iov_from_pdu(pdu, &iov, &niov, is_write); - - qemu_iovec_init_external(&elem, iov, niov); - qemu_iovec_init(qiov, niov); - qemu_iovec_concat(qiov, &elem, skip, size); -} - static void coroutine_fn v9fs_read(void *opaque) { int32_t fid; @@ -3440,7 +3445,6 @@ void pdu_submit(V9fsPDU *pdu) /* Returns 0 on success, 1 on failure. */ int v9fs_device_realize_common(V9fsState *s, Error **errp) { - V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); int i, len; struct stat stat; FsDriverEntry *fse; @@ -3451,9 +3455,9 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp) QLIST_INIT(&s->free_list); QLIST_INIT(&s->active_list); for (i = 0; i < (MAX_REQ - 1); i++) { - QLIST_INSERT_HEAD(&s->free_list, &v->pdus[i], next); - v->pdus[i].s = s; - v->pdus[i].idx = i; + QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next); + s->pdus[i].s = s; + s->pdus[i].idx = i; } v9fs_path_init(&path); @@ -3521,7 +3525,7 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp) rc = 0; out: if (rc) { - if (s->ops->cleanup && s->ctx.private) { + if (s->ops && s->ops->cleanup && s->ctx.private) { s->ops->cleanup(&s->ctx); } g_free(s->tag); diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 3976b7fe3d..b7e836251e 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -99,8 +99,8 @@ enum p9_proto_version { V9FS_PROTO_2000L = 0x02, }; -#define P9_NOTAG (u16)(~0) -#define P9_NOFID (u32)(~0) +#define P9_NOTAG UINT16_MAX +#define P9_NOFID UINT32_MAX #define P9_MAXWELEM 16 #define FID_REFERENCED 0x1 @@ -229,6 +229,8 @@ typedef struct V9fsState char *tag; enum p9_proto_version proto_version; int32_t msize; + V9fsPDU pdus[MAX_REQ]; + const struct V9fsTransport *transport; /* * lock ensuring atomic path update * on rename. @@ -342,4 +344,24 @@ void pdu_free(V9fsPDU *pdu); void pdu_submit(V9fsPDU *pdu); void v9fs_reset(V9fsState *s); +struct V9fsTransport { + ssize_t (*pdu_vmarshal)(V9fsPDU *pdu, size_t offset, const char *fmt, + va_list ap); + ssize_t (*pdu_vunmarshal)(V9fsPDU *pdu, size_t offset, const char *fmt, + va_list ap); + void (*init_in_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov, + unsigned int *pniov, size_t size); + void (*init_out_iov_from_pdu)(V9fsPDU *pdu, struct iovec **piov, + unsigned int *pniov); + void (*push_and_notify)(V9fsPDU *pdu); +}; + +static inline int v9fs_register_transport(V9fsState *s, + const struct V9fsTransport *t) +{ + assert(!s->transport); + s->transport = t; + return 0; +} + #endif diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 1782e4a227..27a4a32f5c 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -20,7 +20,9 @@ #include "hw/virtio/virtio-access.h" #include "qemu/iov.h" -void virtio_9p_push_and_notify(V9fsPDU *pdu) +static const struct V9fsTransport virtio_9p_transport; + +static void virtio_9p_push_and_notify(V9fsPDU *pdu) { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); @@ -126,6 +128,7 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp) v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag); virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size); v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); + v9fs_register_transport(s, &virtio_9p_transport); out: return; @@ -148,8 +151,8 @@ static void virtio_9p_reset(VirtIODevice *vdev) v9fs_reset(&v->state); } -ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, - const char *fmt, va_list ap) +static ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, + const char *fmt, va_list ap) { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); @@ -158,8 +161,8 @@ ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, return v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap); } -ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset, - const char *fmt, va_list ap) +static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset, + const char *fmt, va_list ap) { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); @@ -168,22 +171,37 @@ ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset, return v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap); } -void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, - unsigned int *pniov, bool is_write) +/* The size parameter is used by other transports. Do not drop it. */ +static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, + unsigned int *pniov, size_t size) { V9fsState *s = pdu->s; V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); VirtQueueElement *elem = v->elems[pdu->idx]; - if (is_write) { - *piov = elem->out_sg; - *pniov = elem->out_num; - } else { - *piov = elem->in_sg; - *pniov = elem->in_num; - } + *piov = elem->in_sg; + *pniov = elem->in_num; } +static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, + unsigned int *pniov) +{ + V9fsState *s = pdu->s; + V9fsVirtioState *v = container_of(s, V9fsVirtioState, state); + VirtQueueElement *elem = v->elems[pdu->idx]; + + *piov = elem->out_sg; + *pniov = elem->out_num; +} + +static const struct V9fsTransport virtio_9p_transport = { + .pdu_vmarshal = virtio_pdu_vmarshal, + .pdu_vunmarshal = virtio_pdu_vunmarshal, + .init_in_iov_from_pdu = virtio_init_in_iov_from_pdu, + .init_out_iov_from_pdu = virtio_init_out_iov_from_pdu, + .push_and_notify = virtio_9p_push_and_notify, +}; + /* virtio-9p device */ static const VMStateDescription vmstate_virtio_9p = { diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 25c47c7cb6..e763da2c02 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -10,20 +10,10 @@ typedef struct V9fsVirtioState VirtIODevice parent_obj; VirtQueue *vq; size_t config_size; - V9fsPDU pdus[MAX_REQ]; VirtQueueElement *elems[MAX_REQ]; V9fsState state; } V9fsVirtioState; -void virtio_9p_push_and_notify(V9fsPDU *pdu); - -ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset, - const char *fmt, va_list ap); -ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset, - const char *fmt, va_list ap); -void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, - unsigned int *pniov, bool is_write); - #define TYPE_VIRTIO_9P "virtio-9p-device" #define VIRTIO_9P(obj) \ OBJECT_CHECK(V9fsVirtioState, (obj), TYPE_VIRTIO_9P) diff --git a/hw/alpha/alpha_sys.h b/hw/alpha/alpha_sys.h index ed911f22a1..b6d8369ed7 100644 --- a/hw/alpha/alpha_sys.h +++ b/hw/alpha/alpha_sys.h @@ -3,7 +3,7 @@ #ifndef HW_ALPHA_SYS_H #define HW_ALPHA_SYS_H -#include "target-alpha/cpu-qom.h" +#include "target/alpha/cpu-qom.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" #include "hw/ide.h" diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index c7206fda6d..40c13838fb 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -34,13 +34,18 @@ typedef struct AspeedBoardState { typedef struct AspeedBoardConfig { const char *soc_name; uint32_t hw_strap1; + const char *fmc_model; + const char *spi_model; + uint32_t num_cs; } AspeedBoardConfig; enum { PALMETTO_BMC, AST2500_EVB, + ROMULUS_BMC, }; +/* Palmetto hardware value: 0x120CE416 */ #define PALMETTO_BMC_HW_STRAP1 ( \ SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \ SCU_AST2400_HW_STRAP_DRAM_CONFIG(2 /* DDR3 with CL=6, CWL=5 */) | \ @@ -54,6 +59,7 @@ enum { SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \ SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT)) +/* AST2500 evb hardware value: 0xF100C2E6 */ #define AST2500_EVB_HW_STRAP1 (( \ AST2500_HW_STRAP1_DEFAULTS | \ SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ @@ -64,9 +70,38 @@ enum { SCU_HW_STRAP_MAC0_RGMII) & \ ~SCU_HW_STRAP_2ND_BOOT_WDT) +/* Romulus hardware value: 0xF10AD206 */ +#define ROMULUS_BMC_HW_STRAP1 ( \ + AST2500_HW_STRAP1_DEFAULTS | \ + SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \ + SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \ + SCU_AST2500_HW_STRAP_UART_DEBUG | \ + SCU_AST2500_HW_STRAP_DDR4_ENABLE | \ + SCU_AST2500_HW_STRAP_ACPI_ENABLE | \ + SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER)) + static const AspeedBoardConfig aspeed_boards[] = { - [PALMETTO_BMC] = { "ast2400-a0", PALMETTO_BMC_HW_STRAP1 }, - [AST2500_EVB] = { "ast2500-a1", AST2500_EVB_HW_STRAP1 }, + [PALMETTO_BMC] = { + .soc_name = "ast2400-a1", + .hw_strap1 = PALMETTO_BMC_HW_STRAP1, + .fmc_model = "n25q256a", + .spi_model = "mx25l25635e", + .num_cs = 1, + }, + [AST2500_EVB] = { + .soc_name = "ast2500-a1", + .hw_strap1 = AST2500_EVB_HW_STRAP1, + .fmc_model = "n25q256a", + .spi_model = "mx25l25635e", + .num_cs = 1, + }, + [ROMULUS_BMC] = { + .soc_name = "ast2500-a1", + .hw_strap1 = ROMULUS_BMC_HW_STRAP1, + .fmc_model = "n25q256a", + .spi_model = "mx66l1g45g", + .num_cs = 2, + }, }; static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, @@ -112,6 +147,8 @@ static void aspeed_board_init(MachineState *machine, &error_abort); object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1", &error_abort); + object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs", + &error_abort); object_property_set_bool(OBJECT(&bmc->soc), true, "realized", &error_abort); @@ -128,8 +165,8 @@ static void aspeed_board_init(MachineState *machine, object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), &error_abort); - aspeed_board_init_flashes(&bmc->soc.fmc, "n25q256a", &error_abort); - aspeed_board_init_flashes(&bmc->soc.spi[0], "mx25l25635e", &error_abort); + aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort); + aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort); aspeed_board_binfo.kernel_filename = machine->kernel_filename; aspeed_board_binfo.initrd_filename = machine->initrd_filename; @@ -188,10 +225,35 @@ static const TypeInfo ast2500_evb_type = { .class_init = ast2500_evb_class_init, }; +static void romulus_bmc_init(MachineState *machine) +{ + aspeed_board_init(machine, &aspeed_boards[ROMULUS_BMC]); +} + +static void romulus_bmc_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "OpenPOWER Romulus BMC (ARM1176)"; + mc->init = romulus_bmc_init; + mc->max_cpus = 1; + mc->no_sdcard = 1; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->no_parallel = 1; +} + +static const TypeInfo romulus_bmc_type = { + .name = MACHINE_TYPE_NAME("romulus-bmc"), + .parent = TYPE_MACHINE, + .class_init = romulus_bmc_class_init, +}; + static void aspeed_machine_init(void) { type_register_static(&palmetto_bmc_type); type_register_static(&ast2500_evb_type); + type_register_static(&romulus_bmc_type); } type_init(aspeed_machine_init) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index e14f5c217e..b3e7f07b61 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -29,6 +29,7 @@ #define ASPEED_SOC_VIC_BASE 0x1E6C0000 #define ASPEED_SOC_SDMC_BASE 0x1E6E0000 #define ASPEED_SOC_SCU_BASE 0x1E6E2000 +#define ASPEED_SOC_SRAM_BASE 0x1E720000 #define ASPEED_SOC_TIMER_BASE 0x1E782000 #define ASPEED_SOC_I2C_BASE 0x1E78A000 @@ -47,15 +48,47 @@ static const char *aspeed_soc_ast2500_typenames[] = { "aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" }; static const AspeedSoCInfo aspeed_socs[] = { - { "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, - 1, aspeed_soc_ast2400_spi_bases, - "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, - { "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE, - 1, aspeed_soc_ast2400_spi_bases, - "aspeed.smc.fmc", aspeed_soc_ast2400_typenames }, - { "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE, - 2, aspeed_soc_ast2500_spi_bases, - "aspeed.smc.ast2500-fmc", aspeed_soc_ast2500_typenames }, + { + .name = "ast2400-a0", + .cpu_model = "arm926", + .silicon_rev = AST2400_A0_SILICON_REV, + .sdram_base = AST2400_SDRAM_BASE, + .sram_size = 0x8000, + .spis_num = 1, + .spi_bases = aspeed_soc_ast2400_spi_bases, + .fmc_typename = "aspeed.smc.fmc", + .spi_typename = aspeed_soc_ast2400_typenames, + }, { + .name = "ast2400-a1", + .cpu_model = "arm926", + .silicon_rev = AST2400_A1_SILICON_REV, + .sdram_base = AST2400_SDRAM_BASE, + .sram_size = 0x8000, + .spis_num = 1, + .spi_bases = aspeed_soc_ast2400_spi_bases, + .fmc_typename = "aspeed.smc.fmc", + .spi_typename = aspeed_soc_ast2400_typenames, + }, { + .name = "ast2400", + .cpu_model = "arm926", + .silicon_rev = AST2400_A0_SILICON_REV, + .sdram_base = AST2400_SDRAM_BASE, + .sram_size = 0x8000, + .spis_num = 1, + .spi_bases = aspeed_soc_ast2400_spi_bases, + .fmc_typename = "aspeed.smc.fmc", + .spi_typename = aspeed_soc_ast2400_typenames, + }, { + .name = "ast2500-a1", + .cpu_model = "arm1176", + .silicon_rev = AST2500_A1_SILICON_REV, + .sdram_base = AST2500_SDRAM_BASE, + .sram_size = 0x9000, + .spis_num = 2, + .spi_bases = aspeed_soc_ast2500_spi_bases, + .fmc_typename = "aspeed.smc.ast2500-fmc", + .spi_typename = aspeed_soc_ast2500_typenames, + }, }; /* @@ -87,9 +120,13 @@ static void aspeed_soc_init(Object *obj) { AspeedSoCState *s = ASPEED_SOC(obj); AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + char *cpu_typename; int i; - s->cpu = cpu_arm_init(sc->info->cpu_model); + cpu_typename = g_strdup_printf("%s-" TYPE_ARM_CPU, sc->info->cpu_model); + object_initialize(&s->cpu, sizeof(s->cpu), cpu_typename); + object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL); + g_free(cpu_typename); object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); @@ -116,11 +153,13 @@ static void aspeed_soc_init(Object *obj) object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename); object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL); qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default()); + object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs", + &error_abort); for (i = 0; i < sc->info->spis_num; i++) { object_initialize(&s->spi[i], sizeof(s->spi[i]), sc->info->spi_typename[i]); - object_property_add_child(obj, "spi", OBJECT(&s->spi[i]), NULL); + object_property_add_child(obj, "spi[*]", OBJECT(&s->spi[i]), NULL); qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); } @@ -146,6 +185,24 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(get_system_memory(), ASPEED_SOC_IOMEM_BASE, &s->iomem, -1); + /* CPU */ + object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* SRAM */ + memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram", + sc->info->sram_size, &err); + if (err) { + error_propagate(errp, err); + return; + } + vmstate_register_ram_global(&s->sram); + memory_region_add_subregion(get_system_memory(), ASPEED_SOC_SRAM_BASE, + &s->sram); + /* VIC */ object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); if (err) { @@ -154,9 +211,9 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); + qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, - qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); + qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ)); /* Timer */ object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); @@ -195,10 +252,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, qdev_get_gpio_in(DEVICE(&s->vic), 12)); - /* FMC */ - object_property_set_int(OBJECT(&s->fmc), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->fmc), true, "realized", &local_err); - error_propagate(&err, local_err); + /* FMC, The number of CS is set at the board level */ + object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err); if (err) { error_propagate(errp, err); return; @@ -240,12 +295,6 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data) sc->info = (AspeedSoCInfo *) data; dc->realize = aspeed_soc_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo aspeed_soc_type_info = { diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 21ea1d6210..d31b4577f0 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1258,7 +1258,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s) } /* These are only stubs now. */ -static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) +static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) { PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c); PXA2xxI2CState *s = slave->host; @@ -1280,6 +1280,8 @@ static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) break; } pxa2xx_i2c_update(s); + + return 0; } static int pxa2xx_i2c_rx(I2CSlave *i2c) @@ -1449,17 +1451,10 @@ static const VMStateDescription vmstate_pxa2xx_i2c = { } }; -static int pxa2xx_i2c_slave_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data) { I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - k->init = pxa2xx_i2c_slave_init; k->event = pxa2xx_i2c_event; k->recv = pxa2xx_i2c_rx; k->send = pxa2xx_i2c_tx; @@ -2070,7 +2065,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, } if (!revision) revision = "pxa270"; - + s->cpu = cpu_arm_init(revision); if (s->cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); diff --git a/hw/arm/strongarm.h b/hw/arm/strongarm.h index 1470eac4f5..e98840b461 100644 --- a/hw/arm/strongarm.h +++ b/hw/arm/strongarm.h @@ -2,7 +2,7 @@ #define STRONGARM_H #include "exec/memory.h" -#include "target-arm/cpu-qom.h" +#include "target/arm/cpu-qom.h" #define SA_CS0 0x00000000 #define SA_CS1 0x08000000 diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 1ee12f49b3..c3db996930 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -172,7 +172,7 @@ static int tosa_dac_send(I2CSlave *i2c, uint8_t data) return 0; } -static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event) +static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event) { TosaDACState *s = TOSA_DAC(i2c); @@ -194,6 +194,8 @@ static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event) default: break; } + + return 0; } static int tosa_dac_recv(I2CSlave *s) @@ -202,12 +204,6 @@ static int tosa_dac_recv(I2CSlave *s) return -1; } -static int tosa_dac_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - static void tosa_tg_init(PXA2xxState *cpu) { I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]); @@ -275,7 +271,6 @@ static void tosa_dac_class_init(ObjectClass *klass, void *data) { I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - k->init = tosa_dac_init; k->event = tosa_dac_event; k->recv = tosa_dac_recv; k->send = tosa_dac_send; diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index d4160dfa7d..085a611173 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -29,11 +29,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" -#include "hw/arm/virt-acpi-build.h" #include "qemu/bitmap.h" #include "trace.h" #include "qom/cpu.h" -#include "target-arm/cpu.h" +#include "target/arm/cpu.h" #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" #include "hw/nvram/fw_cfg.h" @@ -43,6 +42,7 @@ #include "hw/acpi/aml-build.h" #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" +#include "hw/arm/virt.h" #include "sysemu/numa.h" #include "kvm_arm.h" @@ -384,7 +384,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset) } static void -build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_iort(GArray *table_data, BIOSLinker *linker) { int iort_start = table_data->len; AcpiIortIdMapping *idmap; @@ -439,11 +439,11 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } static void -build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { AcpiSerialPortConsoleRedirection *spcr; - const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART]; - int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE; + const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART]; + int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE; spcr = acpi_data_push(table_data, sizeof(*spcr)); @@ -472,16 +472,16 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } static void -build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { AcpiSystemResourceAffinityTable *srat; AcpiSratProcessorGiccAffinity *core; AcpiSratMemoryAffinity *numamem; int i, j, srat_start; uint64_t mem_base; - uint32_t *cpu_node = g_malloc0(guest_info->smp_cpus * sizeof(uint32_t)); + uint32_t *cpu_node = g_malloc0(vms->smp_cpus * sizeof(uint32_t)); - for (i = 0; i < guest_info->smp_cpus; i++) { + for (i = 0; i < vms->smp_cpus; i++) { j = numa_get_node_for_cpu(i); if (j < nb_numa_nodes) { cpu_node[i] = j; @@ -492,7 +492,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) srat = acpi_data_push(table_data, sizeof(*srat)); srat->reserved1 = cpu_to_le32(1); - for (i = 0; i < guest_info->smp_cpus; ++i) { + for (i = 0; i < vms->smp_cpus; ++i) { core = acpi_data_push(table_data, sizeof(*core)); core->type = ACPI_SRAT_PROCESSOR_GICC; core->length = sizeof(*core); @@ -502,7 +502,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } g_free(cpu_node); - mem_base = guest_info->memmap[VIRT_MEM].base; + mem_base = vms->memmap[VIRT_MEM].base; for (i = 0; i < nb_numa_nodes; ++i) { numamem = acpi_data_push(table_data, sizeof(*numamem)); build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i, @@ -515,10 +515,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } static void -build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { AcpiTableMcfg *mcfg; - const MemMapEntry *memmap = guest_info->memmap; + const MemMapEntry *memmap = vms->memmap; int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]); mcfg = acpi_data_push(table_data, len); @@ -535,24 +535,33 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) /* GTDT */ static void -build_gtdt(GArray *table_data, BIOSLinker *linker) +build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); int gtdt_start = table_data->len; AcpiGenericTimerTable *gtdt; + uint32_t irqflags; + + if (vmc->claim_edge_triggered_timers) { + irqflags = ACPI_GTDT_INTERRUPT_MODE_EDGE; + } else { + irqflags = ACPI_GTDT_INTERRUPT_MODE_LEVEL; + } gtdt = acpi_data_push(table_data, sizeof *gtdt); /* The interrupt values are the same with the device tree when adding 16 */ - gtdt->secure_el1_interrupt = ARCH_TIMER_S_EL1_IRQ + 16; - gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE; + gtdt->secure_el1_interrupt = cpu_to_le32(ARCH_TIMER_S_EL1_IRQ + 16); + gtdt->secure_el1_flags = cpu_to_le32(irqflags); - gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16; - gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE | ACPI_GTDT_ALWAYS_ON; + gtdt->non_secure_el1_interrupt = cpu_to_le32(ARCH_TIMER_NS_EL1_IRQ + 16); + gtdt->non_secure_el1_flags = cpu_to_le32(irqflags | + ACPI_GTDT_CAP_ALWAYS_ON); - gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16; - gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE; + gtdt->virtual_timer_interrupt = cpu_to_le32(ARCH_TIMER_VIRT_IRQ + 16); + gtdt->virtual_timer_flags = cpu_to_le32(irqflags); - gtdt->non_secure_el2_interrupt = ARCH_TIMER_NS_EL2_IRQ + 16; - gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE; + gtdt->non_secure_el2_interrupt = cpu_to_le32(ARCH_TIMER_NS_EL2_IRQ + 16); + gtdt->non_secure_el2_flags = cpu_to_le32(irqflags); build_header(linker, table_data, (void *)(table_data->data + gtdt_start), "GTDT", @@ -561,11 +570,12 @@ build_gtdt(GArray *table_data, BIOSLinker *linker) /* MADT */ static void -build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); int madt_start = table_data->len; - const MemMapEntry *memmap = guest_info->memmap; - const int *irqmap = guest_info->irqmap; + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; AcpiMultipleApicTable *madt; AcpiMadtGenericDistributor *gicd; AcpiMadtGenericMsiFrame *gic_msi; @@ -576,30 +586,30 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicd = acpi_data_push(table_data, sizeof *gicd); gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR; gicd->length = sizeof(*gicd); - gicd->base_address = memmap[VIRT_GIC_DIST].base; - gicd->version = guest_info->gic_version; + gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base); + gicd->version = vms->gic_version; - for (i = 0; i < guest_info->smp_cpus; i++) { - AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, - sizeof *gicc); + for (i = 0; i < vms->smp_cpus; i++) { + AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data, + sizeof(*gicc)); ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i)); - gicc->type = ACPI_APIC_GENERIC_INTERRUPT; + gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE; gicc->length = sizeof(*gicc); - if (guest_info->gic_version == 2) { - gicc->base_address = memmap[VIRT_GIC_CPU].base; + if (vms->gic_version == 2) { + gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base); } - gicc->cpu_interface_number = i; - gicc->arm_mpidr = armcpu->mp_affinity; - gicc->uid = i; - gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED); + gicc->cpu_interface_number = cpu_to_le32(i); + gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity); + gicc->uid = cpu_to_le32(i); + gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED); if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); } } - if (guest_info->gic_version == 3) { + if (vms->gic_version == 3) { AcpiMadtGenericTranslator *gic_its; AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data, sizeof *gicr); @@ -609,7 +619,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base); gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size); - if (its_class_name() && !guest_info->no_its) { + if (its_class_name() && !vmc->no_its) { gic_its = acpi_data_push(table_data, sizeof *gic_its); gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR; gic_its->length = sizeof(*gic_its); @@ -641,8 +651,8 @@ build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset) /* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */ fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI); - fadt->arm_boot_flags = cpu_to_le16((1 << ACPI_FADT_ARM_USE_PSCI_G_0_2) | - (1 << ACPI_FADT_ARM_PSCI_USE_HVC)); + fadt->arm_boot_flags = cpu_to_le16(ACPI_FADT_ARM_PSCI_COMPLIANT | + ACPI_FADT_ARM_PSCI_USE_HVC); /* ACPI v5.1 (fadt->revision.fadt->minor_revision) */ fadt->minor_revision = 0x1; @@ -658,11 +668,11 @@ build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset) /* DSDT */ static void -build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) { Aml *scope, *dsdt; - const MemMapEntry *memmap = guest_info->memmap; - const int *irqmap = guest_info->irqmap; + const MemMapEntry *memmap = vms->memmap; + const int *irqmap = vms->irqmap; dsdt = init_aml_allocator(); /* Reserve space for header */ @@ -674,7 +684,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) * the RTC ACPI device at all when using UEFI. */ scope = aml_scope("\\_SB"); - acpi_dsdt_add_cpus(scope, guest_info->smp_cpus); + acpi_dsdt_add_cpus(scope, vms->smp_cpus); acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], (irqmap[VIRT_UART] + ARM_SPI_BASE)); acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); @@ -682,7 +692,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE), - guest_info->use_highmem); + vms->highmem); acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO], (irqmap[VIRT_GPIO] + ARM_SPI_BASE)); acpi_dsdt_add_power_button(scope); @@ -705,12 +715,12 @@ struct AcpiBuildState { MemoryRegion *linker_mr; /* Is table patched? */ bool patched; - VirtGuestInfo *guest_info; } AcpiBuildState; static -void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) +void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) { + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); GArray *table_offsets; unsigned dsdt, rsdt; GArray *tables_blob = tables->table_data; @@ -724,32 +734,32 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) /* DSDT is pointed to by FADT */ dsdt = tables_blob->len; - build_dsdt(tables_blob, tables->linker, guest_info); + build_dsdt(tables_blob, tables->linker, vms); /* FADT MADT GTDT MCFG SPCR pointed to by RSDT */ acpi_add_table(table_offsets, tables_blob); build_fadt(tables_blob, tables->linker, dsdt); acpi_add_table(table_offsets, tables_blob); - build_madt(tables_blob, tables->linker, guest_info); + build_madt(tables_blob, tables->linker, vms); acpi_add_table(table_offsets, tables_blob); - build_gtdt(tables_blob, tables->linker); + build_gtdt(tables_blob, tables->linker, vms); acpi_add_table(table_offsets, tables_blob); - build_mcfg(tables_blob, tables->linker, guest_info); + build_mcfg(tables_blob, tables->linker, vms); acpi_add_table(table_offsets, tables_blob); - build_spcr(tables_blob, tables->linker, guest_info); + build_spcr(tables_blob, tables->linker, vms); if (nb_numa_nodes > 0) { acpi_add_table(table_offsets, tables_blob); - build_srat(tables_blob, tables->linker, guest_info); + build_srat(tables_blob, tables->linker, vms); } - if (its_class_name() && !guest_info->no_its) { + if (its_class_name() && !vmc->no_its) { acpi_add_table(table_offsets, tables_blob); - build_iort(tables_blob, tables->linker, guest_info); + build_iort(tables_blob, tables->linker); } /* RSDT is pointed to by RSDP */ @@ -788,13 +798,12 @@ static void virt_acpi_build_update(void *build_opaque) acpi_build_tables_init(&tables); - virt_acpi_build(build_state->guest_info, &tables); + virt_acpi_build(VIRT_MACHINE(qdev_get_machine()), &tables); acpi_ram_update(build_state->table_mr, tables.table_data); acpi_ram_update(build_state->rsdp_mr, tables.rsdp); acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); - acpi_build_tables_cleanup(&tables, true); } @@ -822,12 +831,12 @@ static const VMStateDescription vmstate_virt_acpi_build = { }, }; -void virt_acpi_setup(VirtGuestInfo *guest_info) +void virt_acpi_setup(VirtMachineState *vms) { AcpiBuildTables tables; AcpiBuildState *build_state; - if (!guest_info->fw_cfg) { + if (!vms->fw_cfg) { trace_virt_acpi_setup(); return; } @@ -838,10 +847,9 @@ void virt_acpi_setup(VirtGuestInfo *guest_info) } build_state = g_malloc0(sizeof *build_state); - build_state->guest_info = guest_info; acpi_build_tables_init(&tables); - virt_acpi_build(build_state->guest_info, &tables); + virt_acpi_build(vms, &tables); /* Now expose it all to Guest */ build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data, @@ -853,8 +861,8 @@ void virt_acpi_setup(VirtGuestInfo *guest_info) acpi_add_rom_blob(build_state, tables.linker->cmd_blob, "etc/table-loader", 0); - fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE, - tables.tcpalog->data, acpi_data_len(tables.tcpalog)); + fw_cfg_add_file(vms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, + acpi_data_len(tables.tcpalog)); build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp, ACPI_BUILD_RSDP_FILE, 0); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index d04e4acbd9..7a03f84051 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -41,14 +41,12 @@ #include "sysemu/numa.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" -#include "hw/boards.h" #include "hw/compat.h" #include "hw/loader.h" #include "exec/address-spaces.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "hw/pci-host/gpex.h" -#include "hw/arm/virt-acpi-build.h" #include "hw/arm/sysbus-fdt.h" #include "hw/platform-bus.h" #include "hw/arm/fdt.h" @@ -59,51 +57,6 @@ #include "qapi/visitor.h" #include "standard-headers/linux/input.h" -/* Number of external interrupt lines to configure the GIC with */ -#define NUM_IRQS 256 - -#define PLATFORM_BUS_NUM_IRQS 64 - -static ARMPlatformBusSystemParams platform_bus_params; - -typedef struct VirtBoardInfo { - struct arm_boot_info bootinfo; - const char *cpu_model; - const MemMapEntry *memmap; - const int *irqmap; - int smp_cpus; - void *fdt; - int fdt_size; - uint32_t clock_phandle; - uint32_t gic_phandle; - uint32_t msi_phandle; - bool using_psci; -} VirtBoardInfo; - -typedef struct { - MachineClass parent; - VirtBoardInfo *daughterboard; - bool disallow_affinity_adjustment; - bool no_its; - bool no_pmu; -} VirtMachineClass; - -typedef struct { - MachineState parent; - bool secure; - bool highmem; - int32_t gic_version; -} VirtMachineState; - -#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") -#define VIRT_MACHINE(obj) \ - OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) -#define VIRT_MACHINE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE) -#define VIRT_MACHINE_CLASS(klass) \ - OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) - - #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ void *data) \ @@ -133,6 +86,13 @@ typedef struct { DEFINE_VIRT_MACHINE_LATEST(major, minor, false) +/* Number of external interrupt lines to configure the GIC with */ +#define NUM_IRQS 256 + +#define PLATFORM_BUS_NUM_IRQS 64 + +static ARMPlatformBusSystemParams platform_bus_params; + /* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means * RAM can go up to the 256GB mark, leaving 256GB of the physical * address space unallocated and free for future use between 256G and 512G. @@ -202,51 +162,36 @@ static const int a15irqmap[] = { [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */ }; -static VirtBoardInfo machines[] = { - { - .cpu_model = "cortex-a15", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "cortex-a53", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "cortex-a57", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, - { - .cpu_model = "host", - .memmap = a15memmap, - .irqmap = a15irqmap, - }, +static const char *valid_cpus[] = { + "cortex-a15", + "cortex-a53", + "cortex-a57", + "host", + NULL }; -static VirtBoardInfo *find_machine_info(const char *cpu) +static bool cpuname_valid(const char *cpu) { int i; - for (i = 0; i < ARRAY_SIZE(machines); i++) { - if (strcmp(cpu, machines[i].cpu_model) == 0) { - return &machines[i]; + for (i = 0; i < ARRAY_SIZE(valid_cpus); i++) { + if (strcmp(cpu, valid_cpus[i]) == 0) { + return true; } } - return NULL; + return false; } -static void create_fdt(VirtBoardInfo *vbi) +static void create_fdt(VirtMachineState *vms) { - void *fdt = create_device_tree(&vbi->fdt_size); + void *fdt = create_device_tree(&vms->fdt_size); if (!fdt) { error_report("create_device_tree() failed"); exit(1); } - vbi->fdt = fdt; + vms->fdt = fdt; /* Header */ qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,dummy-virt"); @@ -266,27 +211,27 @@ static void create_fdt(VirtBoardInfo *vbi) * optional but in practice if you omit them the kernel refuses to * probe for the device. */ - vbi->clock_phandle = qemu_fdt_alloc_phandle(fdt); + vms->clock_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_add_subnode(fdt, "/apb-pclk"); qemu_fdt_setprop_string(fdt, "/apb-pclk", "compatible", "fixed-clock"); qemu_fdt_setprop_cell(fdt, "/apb-pclk", "#clock-cells", 0x0); qemu_fdt_setprop_cell(fdt, "/apb-pclk", "clock-frequency", 24000000); qemu_fdt_setprop_string(fdt, "/apb-pclk", "clock-output-names", "clk24mhz"); - qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle); + qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vms->clock_phandle); } -static void fdt_add_psci_node(const VirtBoardInfo *vbi) +static void fdt_add_psci_node(const VirtMachineState *vms) { uint32_t cpu_suspend_fn; uint32_t cpu_off_fn; uint32_t cpu_on_fn; uint32_t migrate_fn; - void *fdt = vbi->fdt; + void *fdt = vms->fdt; ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); - if (!vbi->using_psci) { + if (!vms->using_psci) { return; } @@ -327,41 +272,60 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); } -static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype) +static void fdt_add_timer_nodes(const VirtMachineState *vms) { - /* Note that on A15 h/w these interrupts are level-triggered, - * but for the GIC implementation provided by both QEMU and KVM - * they are edge-triggered. + /* On real hardware these interrupts are level-triggered. + * On KVM they were edge-triggered before host kernel version 4.4, + * and level-triggered afterwards. + * On emulated QEMU they are level-triggered. + * + * Getting the DTB info about them wrong is awkward for some + * guest kernels: + * pre-4.8 ignore the DT and leave the interrupt configured + * with whatever the GIC reset value (or the bootloader) left it at + * 4.8 before rc6 honour the incorrect data by programming it back + * into the GIC, causing problems + * 4.8rc6 and later ignore the DT and always write "level triggered" + * into the GIC + * + * For backwards-compatibility, virt-2.8 and earlier will continue + * to say these are edge-triggered, but later machines will report + * the correct information. */ ARMCPU *armcpu; - uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI; + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); + uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI; + + if (vmc->claim_edge_triggered_timers) { + irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI; + } - if (gictype == 2) { + if (vms->gic_version == 2) { irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, GIC_FDT_IRQ_PPI_CPU_WIDTH, - (1 << vbi->smp_cpus) - 1); + (1 << vms->smp_cpus) - 1); } - qemu_fdt_add_subnode(vbi->fdt, "/timer"); + qemu_fdt_add_subnode(vms->fdt, "/timer"); armcpu = ARM_CPU(qemu_get_cpu(0)); if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) { const char compat[] = "arm,armv8-timer\0arm,armv7-timer"; - qemu_fdt_setprop(vbi->fdt, "/timer", "compatible", + qemu_fdt_setprop(vms->fdt, "/timer", "compatible", compat, sizeof(compat)); } else { - qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible", + qemu_fdt_setprop_string(vms->fdt, "/timer", "compatible", "arm,armv7-timer"); } - qemu_fdt_setprop(vbi->fdt, "/timer", "always-on", NULL, 0); - qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts", + qemu_fdt_setprop(vms->fdt, "/timer", "always-on", NULL, 0); + qemu_fdt_setprop_cells(vms->fdt, "/timer", "interrupts", GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); } -static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) +static void fdt_add_cpu_nodes(const VirtMachineState *vms) { int cpu; int addr_cells = 1; @@ -380,7 +344,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) * The simplest way to go is to examine affinity IDs of all our CPUs. If * at least one of them has Aff3 populated, we set #address-cells to 2. */ - for (cpu = 0; cpu < vbi->smp_cpus; cpu++) { + for (cpu = 0; cpu < vms->smp_cpus; cpu++) { ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); if (armcpu->mp_affinity & ARM_AFF3_MASK) { @@ -389,101 +353,101 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) } } - qemu_fdt_add_subnode(vbi->fdt, "/cpus"); - qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", addr_cells); - qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0); + qemu_fdt_add_subnode(vms->fdt, "/cpus"); + qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#address-cells", addr_cells); + qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#size-cells", 0x0); - for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) { + for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) { char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu); ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu)); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "cpu"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "cpu"); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", armcpu->dtb_compatible); - if (vbi->using_psci && vbi->smp_cpus > 1) { - qemu_fdt_setprop_string(vbi->fdt, nodename, + if (vms->using_psci && vms->smp_cpus > 1) { + qemu_fdt_setprop_string(vms->fdt, nodename, "enable-method", "psci"); } if (addr_cells == 2) { - qemu_fdt_setprop_u64(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_u64(vms->fdt, nodename, "reg", armcpu->mp_affinity); } else { - qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_cell(vms->fdt, nodename, "reg", armcpu->mp_affinity); } i = numa_get_node_for_cpu(cpu); if (i < nb_numa_nodes) { - qemu_fdt_setprop_cell(vbi->fdt, nodename, "numa-node-id", i); + qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id", i); } g_free(nodename); } } -static void fdt_add_its_gic_node(VirtBoardInfo *vbi) +static void fdt_add_its_gic_node(VirtMachineState *vms) { - vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt); - qemu_fdt_add_subnode(vbi->fdt, "/intc/its"); - qemu_fdt_setprop_string(vbi->fdt, "/intc/its", "compatible", + vms->msi_phandle = qemu_fdt_alloc_phandle(vms->fdt); + qemu_fdt_add_subnode(vms->fdt, "/intc/its"); + qemu_fdt_setprop_string(vms->fdt, "/intc/its", "compatible", "arm,gic-v3-its"); - qemu_fdt_setprop(vbi->fdt, "/intc/its", "msi-controller", NULL, 0); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/its", "reg", - 2, vbi->memmap[VIRT_GIC_ITS].base, - 2, vbi->memmap[VIRT_GIC_ITS].size); - qemu_fdt_setprop_cell(vbi->fdt, "/intc/its", "phandle", vbi->msi_phandle); + qemu_fdt_setprop(vms->fdt, "/intc/its", "msi-controller", NULL, 0); + qemu_fdt_setprop_sized_cells(vms->fdt, "/intc/its", "reg", + 2, vms->memmap[VIRT_GIC_ITS].base, + 2, vms->memmap[VIRT_GIC_ITS].size); + qemu_fdt_setprop_cell(vms->fdt, "/intc/its", "phandle", vms->msi_phandle); } -static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) +static void fdt_add_v2m_gic_node(VirtMachineState *vms) { - vbi->msi_phandle = qemu_fdt_alloc_phandle(vbi->fdt); - qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m"); - qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible", + vms->msi_phandle = qemu_fdt_alloc_phandle(vms->fdt); + qemu_fdt_add_subnode(vms->fdt, "/intc/v2m"); + qemu_fdt_setprop_string(vms->fdt, "/intc/v2m", "compatible", "arm,gic-v2m-frame"); - qemu_fdt_setprop(vbi->fdt, "/intc/v2m", "msi-controller", NULL, 0); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg", - 2, vbi->memmap[VIRT_GIC_V2M].base, - 2, vbi->memmap[VIRT_GIC_V2M].size); - qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->msi_phandle); + qemu_fdt_setprop(vms->fdt, "/intc/v2m", "msi-controller", NULL, 0); + qemu_fdt_setprop_sized_cells(vms->fdt, "/intc/v2m", "reg", + 2, vms->memmap[VIRT_GIC_V2M].base, + 2, vms->memmap[VIRT_GIC_V2M].size); + qemu_fdt_setprop_cell(vms->fdt, "/intc/v2m", "phandle", vms->msi_phandle); } -static void fdt_add_gic_node(VirtBoardInfo *vbi, int type) +static void fdt_add_gic_node(VirtMachineState *vms) { - vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt); - qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle); - - qemu_fdt_add_subnode(vbi->fdt, "/intc"); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3); - qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2); - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2); - qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0); - if (type == 3) { - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + vms->gic_phandle = qemu_fdt_alloc_phandle(vms->fdt); + qemu_fdt_setprop_cell(vms->fdt, "/", "interrupt-parent", vms->gic_phandle); + + qemu_fdt_add_subnode(vms->fdt, "/intc"); + qemu_fdt_setprop_cell(vms->fdt, "/intc", "#interrupt-cells", 3); + qemu_fdt_setprop(vms->fdt, "/intc", "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(vms->fdt, "/intc", "#address-cells", 0x2); + qemu_fdt_setprop_cell(vms->fdt, "/intc", "#size-cells", 0x2); + qemu_fdt_setprop(vms->fdt, "/intc", "ranges", NULL, 0); + if (vms->gic_version == 3) { + qemu_fdt_setprop_string(vms->fdt, "/intc", "compatible", "arm,gic-v3"); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_REDIST].base, - 2, vbi->memmap[VIRT_GIC_REDIST].size); + qemu_fdt_setprop_sized_cells(vms->fdt, "/intc", "reg", + 2, vms->memmap[VIRT_GIC_DIST].base, + 2, vms->memmap[VIRT_GIC_DIST].size, + 2, vms->memmap[VIRT_GIC_REDIST].base, + 2, vms->memmap[VIRT_GIC_REDIST].size); } else { /* 'cortex-a15-gic' means 'GIC v2' */ - qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible", + qemu_fdt_setprop_string(vms->fdt, "/intc", "compatible", "arm,cortex-a15-gic"); - qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg", - 2, vbi->memmap[VIRT_GIC_DIST].base, - 2, vbi->memmap[VIRT_GIC_DIST].size, - 2, vbi->memmap[VIRT_GIC_CPU].base, - 2, vbi->memmap[VIRT_GIC_CPU].size); + qemu_fdt_setprop_sized_cells(vms->fdt, "/intc", "reg", + 2, vms->memmap[VIRT_GIC_DIST].base, + 2, vms->memmap[VIRT_GIC_DIST].size, + 2, vms->memmap[VIRT_GIC_CPU].base, + 2, vms->memmap[VIRT_GIC_CPU].size); } - qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle); + qemu_fdt_setprop_cell(vms->fdt, "/intc", "phandle", vms->gic_phandle); } -static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype) +static void fdt_add_pmu_nodes(const VirtMachineState *vms) { CPUState *cpu; ARMCPU *armcpu; @@ -497,24 +461,24 @@ static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype) } } - if (gictype == 2) { + if (vms->gic_version == 2) { irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, GIC_FDT_IRQ_PPI_CPU_WIDTH, - (1 << vbi->smp_cpus) - 1); + (1 << vms->smp_cpus) - 1); } armcpu = ARM_CPU(qemu_get_cpu(0)); - qemu_fdt_add_subnode(vbi->fdt, "/pmu"); + qemu_fdt_add_subnode(vms->fdt, "/pmu"); if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) { const char compat[] = "arm,armv8-pmuv3"; - qemu_fdt_setprop(vbi->fdt, "/pmu", "compatible", + qemu_fdt_setprop(vms->fdt, "/pmu", "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_cells(vbi->fdt, "/pmu", "interrupts", + qemu_fdt_setprop_cells(vms->fdt, "/pmu", "interrupts", GIC_FDT_IRQ_TYPE_PPI, VIRTUAL_PMU_IRQ, irqflags); } } -static void create_its(VirtBoardInfo *vbi, DeviceState *gicdev) +static void create_its(VirtMachineState *vms, DeviceState *gicdev) { const char *itsclass = its_class_name(); DeviceState *dev; @@ -529,19 +493,19 @@ static void create_its(VirtBoardInfo *vbi, DeviceState *gicdev) object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3", &error_abort); qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_ITS].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base); - fdt_add_its_gic_node(vbi); + fdt_add_its_gic_node(vms); } -static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) +static void create_v2m(VirtMachineState *vms, qemu_irq *pic) { int i; - int irq = vbi->irqmap[VIRT_GIC_V2M]; + int irq = vms->irqmap[VIRT_GIC_V2M]; DeviceState *dev; dev = qdev_create(NULL, "arm-gicv2m"); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_V2M].base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_V2M].base); qdev_prop_set_uint32(dev, "base-spi", irq); qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS); qdev_init_nofail(dev); @@ -550,17 +514,17 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); } - fdt_add_v2m_gic_node(vbi); + fdt_add_v2m_gic_node(vms); } -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, - bool secure, bool no_its) +static void create_gic(VirtMachineState *vms, qemu_irq *pic) { /* We create a standalone GIC */ + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); DeviceState *gicdev; SysBusDevice *gicbusdev; const char *gictype; - int i; + int type = vms->gic_version, i; gictype = (type == 3) ? gicv3_class_name() : gic_class_name(); @@ -572,15 +536,15 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, */ qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); if (!kvm_irqchip_in_kernel()) { - qdev_prop_set_bit(gicdev, "has-security-extensions", secure); + qdev_prop_set_bit(gicdev, "has-security-extensions", vms->secure); } qdev_init_nofail(gicdev); gicbusdev = SYS_BUS_DEVICE(gicdev); - sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base); + sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base); if (type == 3) { - sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_REDIST].base); + sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base); } else { - sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base); + sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_CPU].base); } /* Wire the outputs from each CPU's generic timer to the @@ -616,22 +580,22 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, pic[i] = qdev_get_gpio_in(gicdev, i); } - fdt_add_gic_node(vbi, type); + fdt_add_gic_node(vms); - if (type == 3 && !no_its) { - create_its(vbi, gicdev); + if (type == 3 && !vmc->no_its) { + create_its(vms, gicdev); } else if (type == 2) { - create_v2m(vbi, pic); + create_v2m(vms, pic); } } -static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, +static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, MemoryRegion *mem, CharDriverState *chr) { char *nodename; - hwaddr base = vbi->memmap[uart].base; - hwaddr size = vbi->memmap[uart].size; - int irq = vbi->irqmap[uart]; + hwaddr base = vms->memmap[uart].base; + hwaddr size = vms->memmap[uart].size; + int irq = vms->irqmap[uart]; const char compat[] = "arm,pl011\0arm,primecell"; const char clocknames[] = "uartclk\0apb_pclk"; DeviceState *dev = qdev_create(NULL, "pl011"); @@ -644,51 +608,51 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, sysbus_connect_irq(s, 0, pic[irq]); nodename = g_strdup_printf("/pl011@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_add_subnode(vms->fdt, nodename); /* Note that we can't use setprop_string because of the embedded NUL */ - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", + qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks", - vbi->clock_phandle, vbi->clock_phandle); - qemu_fdt_setprop(vbi->fdt, nodename, "clock-names", + qemu_fdt_setprop_cells(vms->fdt, nodename, "clocks", + vms->clock_phandle, vms->clock_phandle); + qemu_fdt_setprop(vms->fdt, nodename, "clock-names", clocknames, sizeof(clocknames)); if (uart == VIRT_UART) { - qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename); + qemu_fdt_setprop_string(vms->fdt, "/chosen", "stdout-path", nodename); } else { /* Mark as not usable by the normal world */ - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); } g_free(nodename); } -static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic) +static void create_rtc(const VirtMachineState *vms, qemu_irq *pic) { char *nodename; - hwaddr base = vbi->memmap[VIRT_RTC].base; - hwaddr size = vbi->memmap[VIRT_RTC].size; - int irq = vbi->irqmap[VIRT_RTC]; + hwaddr base = vms->memmap[VIRT_RTC].base; + hwaddr size = vms->memmap[VIRT_RTC].size; + int irq = vms->irqmap[VIRT_RTC]; const char compat[] = "arm,pl031\0arm,primecell"; sysbus_create_simple("pl031", base, pic[irq]); nodename = g_strdup_printf("/pl031@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle); - qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "clocks", vms->clock_phandle); + qemu_fdt_setprop_string(vms->fdt, nodename, "clock-names", "apb_pclk"); g_free(nodename); } @@ -703,45 +667,45 @@ static Notifier virt_system_powerdown_notifier = { .notify = virt_powerdown_req }; -static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic) +static void create_gpio(const VirtMachineState *vms, qemu_irq *pic) { char *nodename; DeviceState *pl061_dev; - hwaddr base = vbi->memmap[VIRT_GPIO].base; - hwaddr size = vbi->memmap[VIRT_GPIO].size; - int irq = vbi->irqmap[VIRT_GPIO]; + hwaddr base = vms->memmap[VIRT_GPIO].base; + hwaddr size = vms->memmap[VIRT_GPIO].size; + int irq = vms->irqmap[VIRT_GPIO]; const char compat[] = "arm,pl061\0arm,primecell"; pl061_dev = sysbus_create_simple("pl061", base, pic[irq]); - uint32_t phandle = qemu_fdt_alloc_phandle(vbi->fdt); + uint32_t phandle = qemu_fdt_alloc_phandle(vms->fdt); nodename = g_strdup_printf("/pl061@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat)); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#gpio-cells", 2); - qemu_fdt_setprop(vbi->fdt, nodename, "gpio-controller", NULL, 0); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_cell(vms->fdt, nodename, "#gpio-cells", 2); + qemu_fdt_setprop(vms->fdt, nodename, "gpio-controller", NULL, 0); + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_LEVEL_HI); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle); - qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk"); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "phandle", phandle); + qemu_fdt_setprop_cell(vms->fdt, nodename, "clocks", vms->clock_phandle); + qemu_fdt_setprop_string(vms->fdt, nodename, "clock-names", "apb_pclk"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", phandle); gpio_key_dev = sysbus_create_simple("gpio-key", -1, qdev_get_gpio_in(pl061_dev, 3)); - qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys"); - qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys", "compatible", "gpio-keys"); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#size-cells", 0); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#address-cells", 1); + qemu_fdt_add_subnode(vms->fdt, "/gpio-keys"); + qemu_fdt_setprop_string(vms->fdt, "/gpio-keys", "compatible", "gpio-keys"); + qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#size-cells", 0); + qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#address-cells", 1); - qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys/poweroff"); - qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys/poweroff", + qemu_fdt_add_subnode(vms->fdt, "/gpio-keys/poweroff"); + qemu_fdt_setprop_string(vms->fdt, "/gpio-keys/poweroff", "label", "GPIO Key Poweroff"); - qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys/poweroff", "linux,code", + qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys/poweroff", "linux,code", KEY_POWER); - qemu_fdt_setprop_cells(vbi->fdt, "/gpio-keys/poweroff", + qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff", "gpios", phandle, 3, 0); /* connect powerdown request */ @@ -750,10 +714,10 @@ static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic) g_free(nodename); } -static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) +static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic) { int i; - hwaddr size = vbi->memmap[VIRT_MMIO].size; + hwaddr size = vms->memmap[VIRT_MMIO].size; /* We create the transports in forwards order. Since qbus_realize() * prepends (not appends) new child buses, the incrementing loop below will @@ -783,8 +747,8 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) * of disks users must use UUIDs or similar mechanisms. */ for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) { - int irq = vbi->irqmap[VIRT_MMIO] + i; - hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size; + int irq = vms->irqmap[VIRT_MMIO] + i; + hwaddr base = vms->memmap[VIRT_MMIO].base + i * size; sysbus_create_simple("virtio-mmio", base, pic[irq]); } @@ -798,16 +762,16 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic) */ for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) { char *nodename; - int irq = vbi->irqmap[VIRT_MMIO] + i; - hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size; + int irq = vms->irqmap[VIRT_MMIO] + i; + hwaddr base = vms->memmap[VIRT_MMIO].base + i * size; nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "virtio,mmio"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts", + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); g_free(nodename); @@ -870,7 +834,7 @@ static void create_one_flash(const char *name, hwaddr flashbase, } } -static void create_flash(const VirtBoardInfo *vbi, +static void create_flash(const VirtMachineState *vms, MemoryRegion *sysmem, MemoryRegion *secure_sysmem) { @@ -882,8 +846,8 @@ static void create_flash(const VirtBoardInfo *vbi, * If sysmem == secure_sysmem this means there is no separate Secure * address space and both flash devices are generally visible. */ - hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2; - hwaddr flashbase = vbi->memmap[VIRT_FLASH].base; + hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = vms->memmap[VIRT_FLASH].base; char *nodename; create_one_flash("virt.flash0", flashbase, flashsize, @@ -894,41 +858,41 @@ static void create_flash(const VirtBoardInfo *vbi, if (sysmem == secure_sysmem) { /* Report both flash devices as a single node in the DT */ nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, flashbase, 2, flashsize, 2, flashbase + flashsize, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); + qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4); g_free(nodename); } else { /* Report the devices as separate nodes so we can mark one as * only visible to the secure world. */ nodename = g_strdup_printf("/secflash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, flashbase, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4); + qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); g_free(nodename); nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, flashbase + flashsize, 2, flashsize); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4); + qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4); g_free(nodename); } } -static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as) +static FWCfgState *create_fw_cfg(const VirtMachineState *vms, AddressSpace *as) { - hwaddr base = vbi->memmap[VIRT_FW_CFG].base; - hwaddr size = vbi->memmap[VIRT_FW_CFG].size; + hwaddr base = vms->memmap[VIRT_FW_CFG].base; + hwaddr size = vms->memmap[VIRT_FW_CFG].size; FWCfgState *fw_cfg; char *nodename; @@ -936,15 +900,17 @@ static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as) fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "qemu,fw-cfg-mmio"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); g_free(nodename); + return fw_cfg; } -static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, +static void create_pcie_irq_map(const VirtMachineState *vms, + uint32_t gic_phandle, int first_irq, const char *nodename) { int devfn, pin; @@ -971,28 +937,27 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, } } - qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", + qemu_fdt_setprop(vms->fdt, nodename, "interrupt-map", full_irq_map, sizeof(full_irq_map)); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask", + qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupt-map-mask", 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */ 0x7 /* PCI irq */); } -static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, - bool use_highmem) +static void create_pcie(const VirtMachineState *vms, qemu_irq *pic) { - hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base; - hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size; - hwaddr base_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].base; - hwaddr size_mmio_high = vbi->memmap[VIRT_PCIE_MMIO_HIGH].size; - hwaddr base_pio = vbi->memmap[VIRT_PCIE_PIO].base; - hwaddr size_pio = vbi->memmap[VIRT_PCIE_PIO].size; - hwaddr base_ecam = vbi->memmap[VIRT_PCIE_ECAM].base; - hwaddr size_ecam = vbi->memmap[VIRT_PCIE_ECAM].size; + hwaddr base_mmio = vms->memmap[VIRT_PCIE_MMIO].base; + hwaddr size_mmio = vms->memmap[VIRT_PCIE_MMIO].size; + hwaddr base_mmio_high = vms->memmap[VIRT_PCIE_MMIO_HIGH].base; + hwaddr size_mmio_high = vms->memmap[VIRT_PCIE_MMIO_HIGH].size; + hwaddr base_pio = vms->memmap[VIRT_PCIE_PIO].base; + hwaddr size_pio = vms->memmap[VIRT_PCIE_PIO].size; + hwaddr base_ecam = vms->memmap[VIRT_PCIE_ECAM].base; + hwaddr size_ecam = vms->memmap[VIRT_PCIE_ECAM].size; hwaddr base = base_mmio; int nr_pcie_buses = size_ecam / PCIE_MMCFG_SIZE_MIN; - int irq = vbi->irqmap[VIRT_PCIE]; + int irq = vms->irqmap[VIRT_PCIE]; MemoryRegion *mmio_alias; MemoryRegion *mmio_reg; MemoryRegion *ecam_alias; @@ -1023,7 +988,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, mmio_reg, base_mmio, size_mmio); memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); - if (use_highmem) { + if (vms->highmem) { /* Map high MMIO space */ MemoryRegion *high_mmio_alias = g_new0(MemoryRegion, 1); @@ -1054,26 +1019,26 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, } nodename = g_strdup_printf("/pcie@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "pci-host-ecam-generic"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci"); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3); - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); - qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, + qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "pci"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "#address-cells", 3); + qemu_fdt_setprop_cell(vms->fdt, nodename, "#size-cells", 2); + qemu_fdt_setprop_cells(vms->fdt, nodename, "bus-range", 0, nr_pcie_buses - 1); - qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0); + qemu_fdt_setprop(vms->fdt, nodename, "dma-coherent", NULL, 0); - if (vbi->msi_phandle) { - qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", - vbi->msi_phandle); + if (vms->msi_phandle) { + qemu_fdt_setprop_cells(vms->fdt, nodename, "msi-parent", + vms->msi_phandle); } - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base_ecam, 2, size_ecam); - if (use_highmem) { - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", + if (vms->highmem) { + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "ranges", 1, FDT_PCI_RANGE_IOPORT, 2, 0, 2, base_pio, 2, size_pio, 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, @@ -1082,20 +1047,20 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, 2, base_mmio_high, 2, base_mmio_high, 2, size_mmio_high); } else { - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "ranges", 1, FDT_PCI_RANGE_IOPORT, 2, 0, 2, base_pio, 2, size_pio, 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, 2, base_mmio, 2, size_mmio); } - qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1); - create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename); + qemu_fdt_setprop_cell(vms->fdt, nodename, "#interrupt-cells", 1); + create_pcie_irq_map(vms, vms->gic_phandle, irq, nodename); g_free(nodename); } -static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic) +static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic) { DeviceState *dev; SysBusDevice *s; @@ -1103,13 +1068,13 @@ static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic) ARMPlatformBusFDTParams *fdt_params = g_new(ARMPlatformBusFDTParams, 1); MemoryRegion *sysmem = get_system_memory(); - platform_bus_params.platform_bus_base = vbi->memmap[VIRT_PLATFORM_BUS].base; - platform_bus_params.platform_bus_size = vbi->memmap[VIRT_PLATFORM_BUS].size; - platform_bus_params.platform_bus_first_irq = vbi->irqmap[VIRT_PLATFORM_BUS]; + platform_bus_params.platform_bus_base = vms->memmap[VIRT_PLATFORM_BUS].base; + platform_bus_params.platform_bus_size = vms->memmap[VIRT_PLATFORM_BUS].size; + platform_bus_params.platform_bus_first_irq = vms->irqmap[VIRT_PLATFORM_BUS]; platform_bus_params.platform_bus_num_irqs = PLATFORM_BUS_NUM_IRQS; fdt_params->system_params = &platform_bus_params; - fdt_params->binfo = &vbi->bootinfo; + fdt_params->binfo = &vms->bootinfo; fdt_params->intc = "/intc"; /* * register a machine init done notifier that creates the device tree @@ -1136,43 +1101,44 @@ static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic) sysbus_mmio_get_region(s, 0)); } -static void create_secure_ram(VirtBoardInfo *vbi, MemoryRegion *secure_sysmem) +static void create_secure_ram(VirtMachineState *vms, + MemoryRegion *secure_sysmem) { MemoryRegion *secram = g_new(MemoryRegion, 1); char *nodename; - hwaddr base = vbi->memmap[VIRT_SECURE_MEM].base; - hwaddr size = vbi->memmap[VIRT_SECURE_MEM].size; + hwaddr base = vms->memmap[VIRT_SECURE_MEM].base; + hwaddr size = vms->memmap[VIRT_SECURE_MEM].size; memory_region_init_ram(secram, NULL, "virt.secure-ram", size, &error_fatal); vmstate_register_ram_global(secram); memory_region_add_subregion(secure_sysmem, base, secram); nodename = g_strdup_printf("/secram@%" PRIx64, base); - qemu_fdt_add_subnode(vbi->fdt, nodename); - qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "memory"); - qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size); - qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled"); - qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay"); + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "memory"); + qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size); + qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); + qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); g_free(nodename); } static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) { - const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; + const VirtMachineState *board = container_of(binfo, VirtMachineState, + bootinfo); *fdt_size = board->fdt_size; return board->fdt; } -static void virt_build_smbios(VirtGuestInfo *guest_info) +static void virt_build_smbios(VirtMachineState *vms) { - FWCfgState *fw_cfg = guest_info->fw_cfg; uint8_t *smbios_tables, *smbios_anchor; size_t smbios_tables_len, smbios_anchor_len; const char *product = "QEMU Virtual Machine"; - if (!fw_cfg) { + if (!vms->fw_cfg) { return; } @@ -1187,20 +1153,21 @@ static void virt_build_smbios(VirtGuestInfo *guest_info) &smbios_anchor, &smbios_anchor_len); if (smbios_anchor) { - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", + fw_cfg_add_file(vms->fw_cfg, "etc/smbios/smbios-tables", smbios_tables, smbios_tables_len); - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", + fw_cfg_add_file(vms->fw_cfg, "etc/smbios/smbios-anchor", smbios_anchor, smbios_anchor_len); } } static -void virt_guest_info_machine_done(Notifier *notifier, void *data) +void virt_machine_done(Notifier *notifier, void *data) { - VirtGuestInfoState *guest_info_state = container_of(notifier, - VirtGuestInfoState, machine_done); - virt_acpi_setup(&guest_info_state->info); - virt_build_smbios(&guest_info_state->info); + VirtMachineState *vms = container_of(notifier, VirtMachineState, + machine_done); + + virt_acpi_setup(vms); + virt_build_smbios(vms); } static void machvirt_init(MachineState *machine) @@ -1210,13 +1177,9 @@ static void machvirt_init(MachineState *machine) qemu_irq pic[NUM_IRQS]; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *secure_sysmem = NULL; - int gic_version = vms->gic_version; int n, virt_max_cpus; MemoryRegion *ram = g_new(MemoryRegion, 1); const char *cpu_model = machine->cpu_model; - VirtBoardInfo *vbi; - VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); - VirtGuestInfo *guest_info = &guest_info_state->info; char **cpustr; ObjectClass *oc; const char *typename; @@ -1232,14 +1195,14 @@ static void machvirt_init(MachineState *machine) /* We can probe only here because during property set * KVM is not available yet */ - if (!gic_version) { + if (!vms->gic_version) { if (!kvm_enabled()) { error_report("gic-version=host requires KVM"); exit(1); } - gic_version = kvm_arm_vgic_probe(); - if (!gic_version) { + vms->gic_version = kvm_arm_vgic_probe(); + if (!vms->gic_version) { error_report("Unable to determine GIC version supported by host"); exit(1); } @@ -1248,9 +1211,7 @@ static void machvirt_init(MachineState *machine) /* Separate the actual CPU model name from any appended features */ cpustr = g_strsplit(cpu_model, ",", 2); - vbi = find_machine_info(cpustr[0]); - - if (!vbi) { + if (!cpuname_valid(cpustr[0])) { error_report("mach-virt: CPU %s not supported", cpustr[0]); exit(1); } @@ -1262,13 +1223,13 @@ static void machvirt_init(MachineState *machine) * let the boot ROM sort them out. * The usual case is that we do use QEMU's PSCI implementation. */ - vbi->using_psci = !(vms->secure && firmware_loaded); + vms->using_psci = !(vms->secure && firmware_loaded); /* The maximum number of CPUs depends on the GIC version, or on how * many redistributors we can fit into the memory map. */ - if (gic_version == 3) { - virt_max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000; + if (vms->gic_version == 3) { + virt_max_cpus = vms->memmap[VIRT_GIC_REDIST].size / 0x20000; clustersz = GICV3_TARGETLIST_BITS; } else { virt_max_cpus = GIC_NCPU; @@ -1282,9 +1243,9 @@ static void machvirt_init(MachineState *machine) exit(1); } - vbi->smp_cpus = smp_cpus; + vms->smp_cpus = smp_cpus; - if (machine->ram_size > vbi->memmap[VIRT_MEM].size) { + if (machine->ram_size > vms->memmap[VIRT_MEM].size) { error_report("mach-virt: cannot model more than %dGB RAM", RAMLIMIT_GB); exit(1); } @@ -1306,7 +1267,7 @@ static void machvirt_init(MachineState *machine) memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1); } - create_fdt(vbi); + create_fdt(vms); oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]); if (!oc) { @@ -1345,7 +1306,7 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, false, "has_el3", NULL); } - if (vbi->using_psci) { + if (vms->using_psci) { object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit", NULL); @@ -1361,7 +1322,7 @@ static void machvirt_init(MachineState *machine) } if (object_property_find(cpuobj, "reset-cbar", NULL)) { - object_property_set_int(cpuobj, vbi->memmap[VIRT_CPUPERIPHS].base, + object_property_set_int(cpuobj, vms->memmap[VIRT_CPUPERIPHS].base, "reset-cbar", &error_abort); } @@ -1374,62 +1335,55 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, true, "realized", NULL); } - fdt_add_timer_nodes(vbi, gic_version); - fdt_add_cpu_nodes(vbi); - fdt_add_psci_node(vbi); + fdt_add_timer_nodes(vms); + fdt_add_cpu_nodes(vms); + fdt_add_psci_node(vms); memory_region_allocate_system_memory(ram, NULL, "mach-virt.ram", machine->ram_size); - memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram); + memory_region_add_subregion(sysmem, vms->memmap[VIRT_MEM].base, ram); - create_flash(vbi, sysmem, secure_sysmem ? secure_sysmem : sysmem); + create_flash(vms, sysmem, secure_sysmem ? secure_sysmem : sysmem); - create_gic(vbi, pic, gic_version, vms->secure, vmc->no_its); + create_gic(vms, pic); - fdt_add_pmu_nodes(vbi, gic_version); + fdt_add_pmu_nodes(vms); - create_uart(vbi, pic, VIRT_UART, sysmem, serial_hds[0]); + create_uart(vms, pic, VIRT_UART, sysmem, serial_hds[0]); if (vms->secure) { - create_secure_ram(vbi, secure_sysmem); - create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem, serial_hds[1]); + create_secure_ram(vms, secure_sysmem); + create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hds[1]); } - create_rtc(vbi, pic); + create_rtc(vms, pic); - create_pcie(vbi, pic, vms->highmem); + create_pcie(vms, pic); - create_gpio(vbi, pic); + create_gpio(vms, pic); /* Create mmio transports, so the user can create virtio backends * (which will be automatically plugged in to the transports). If * no backend is created the transport will just sit harmlessly idle. */ - create_virtio_devices(vbi, pic); - - create_fw_cfg(vbi, &address_space_memory); - rom_set_fw(fw_cfg_find()); - - guest_info->smp_cpus = smp_cpus; - guest_info->fw_cfg = fw_cfg_find(); - guest_info->memmap = vbi->memmap; - guest_info->irqmap = vbi->irqmap; - guest_info->use_highmem = vms->highmem; - guest_info->gic_version = gic_version; - guest_info->no_its = vmc->no_its; - guest_info_state->machine_done.notify = virt_guest_info_machine_done; - qemu_add_machine_init_done_notifier(&guest_info_state->machine_done); - - vbi->bootinfo.ram_size = machine->ram_size; - vbi->bootinfo.kernel_filename = machine->kernel_filename; - vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline; - vbi->bootinfo.initrd_filename = machine->initrd_filename; - vbi->bootinfo.nb_cpus = smp_cpus; - vbi->bootinfo.board_id = -1; - vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base; - vbi->bootinfo.get_dtb = machvirt_dtb; - vbi->bootinfo.firmware_loaded = firmware_loaded; - arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo); + create_virtio_devices(vms, pic); + + vms->fw_cfg = create_fw_cfg(vms, &address_space_memory); + rom_set_fw(vms->fw_cfg); + + vms->machine_done.notify = virt_machine_done; + qemu_add_machine_init_done_notifier(&vms->machine_done); + + vms->bootinfo.ram_size = machine->ram_size; + vms->bootinfo.kernel_filename = machine->kernel_filename; + vms->bootinfo.kernel_cmdline = machine->kernel_cmdline; + vms->bootinfo.initrd_filename = machine->initrd_filename; + vms->bootinfo.nb_cpus = smp_cpus; + vms->bootinfo.board_id = -1; + vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base; + vms->bootinfo.get_dtb = machvirt_dtb; + vms->bootinfo.firmware_loaded = firmware_loaded; + arm_load_kernel(ARM_CPU(first_cpu), &vms->bootinfo); /* * arm_load_kernel machine init done notifier registration must @@ -1437,7 +1391,7 @@ static void machvirt_init(MachineState *machine) * another notifier is registered which adds platform bus nodes. * Notifiers are executed in registration reverse order. */ - create_platform_bus(vbi, pic); + create_platform_bus(vms, pic); } static bool virt_get_secure(Object *obj, Error **errp) @@ -1525,7 +1479,7 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_2_8_instance_init(Object *obj) +static void virt_2_9_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -1556,12 +1510,36 @@ static void virt_2_8_instance_init(Object *obj) object_property_set_description(obj, "gic-version", "Set GIC version. " "Valid values are 2, 3 and host", NULL); + + vms->memmap = a15memmap; + vms->irqmap = a15irqmap; +} + +static void virt_machine_2_9_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE_AS_LATEST(2, 9) + +#define VIRT_COMPAT_2_8 \ + HW_COMPAT_2_8 + +static void virt_2_8_instance_init(Object *obj) +{ + virt_2_9_instance_init(obj); } static void virt_machine_2_8_options(MachineClass *mc) { + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); + + virt_machine_2_9_options(mc); + SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_8); + /* For 2.8 and earlier we falsely claimed in the DT that + * our timers were edge-triggered, not level-triggered. + */ + vmc->claim_edge_triggered_timers = true; } -DEFINE_VIRT_MACHINE_AS_LATEST(2, 8) +DEFINE_VIRT_MACHINE(2, 8) #define VIRT_COMPAT_2_7 \ HW_COMPAT_2_7 diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 68a92f3184..1607cbdb03 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -220,7 +220,7 @@ static int aer915_send(I2CSlave *i2c, uint8_t data) return 0; } -static void aer915_event(I2CSlave *i2c, enum i2c_event event) +static int aer915_event(I2CSlave *i2c, enum i2c_event event) { AER915State *s = AER915(i2c); @@ -238,6 +238,8 @@ static void aer915_event(I2CSlave *i2c, enum i2c_event event) default: break; } + + return 0; } static int aer915_recv(I2CSlave *slave) @@ -263,12 +265,6 @@ static int aer915_recv(I2CSlave *slave) return retval; } -static int aer915_init(I2CSlave *i2c) -{ - /* Nothing to do. */ - return 0; -} - static VMStateDescription vmstate_aer915_state = { .name = "aer915", .version_id = 1, @@ -285,7 +281,6 @@ static void aer915_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - k->init = aer915_init; k->event = aer915_event; k->recv = aer915_recv; k->send = aer915_send; diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c index 0c6500e96a..f8b5bebfc2 100644 --- a/hw/audio/wm8750.c +++ b/hw/audio/wm8750.c @@ -303,7 +303,7 @@ static void wm8750_reset(I2CSlave *i2c) s->i2c_len = 0; } -static void wm8750_event(I2CSlave *i2c, enum i2c_event event) +static int wm8750_event(I2CSlave *i2c, enum i2c_event event) { WM8750State *s = WM8750(i2c); @@ -321,6 +321,8 @@ static void wm8750_event(I2CSlave *i2c, enum i2c_event event) default: break; } + + return 0; } #define WM8750_LINVOL 0x00 diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index d29ff4cb4f..4c5f8c3590 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -28,6 +28,7 @@ #include "hw/ssi/ssi.h" #include "qemu/bitops.h" #include "qemu/log.h" +#include "qemu/error-report.h" #include "qapi/error.h" #ifndef M25P80_ERR_DEBUG @@ -203,6 +204,7 @@ static const FlashPartInfo known_devices[] = { { INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) }, { INFO("mx66u51235f", 0xc2253a, 0, 64 << 10, 1024, ER_4K | ER_32K) }, { INFO("mx66u1g45g", 0xc2253b, 0, 64 << 10, 2048, ER_4K | ER_32K) }, + { INFO("mx66l1g45g", 0xc2201b, 0, 64 << 10, 2048, ER_4K | ER_32K) }, /* Micron */ { INFO("n25q032a11", 0x20bb16, 0, 64 << 10, 64, ER_4K) }, @@ -376,6 +378,8 @@ typedef enum { MAN_GENERIC, } Manufacturer; +#define M25P80_INTERNAL_DATA_BUFFER_SZ 16 + typedef struct Flash { SSISlave parent_obj; @@ -386,7 +390,7 @@ typedef struct Flash { int page_size; uint8_t state; - uint8_t data[16]; + uint8_t data[M25P80_INTERNAL_DATA_BUFFER_SZ]; uint32_t len; uint32_t pos; uint8_t needed_bytes; @@ -1114,6 +1118,17 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) case STATE_COLLECTING_DATA: case STATE_COLLECTING_VAR_LEN_DATA: + + if (s->len >= M25P80_INTERNAL_DATA_BUFFER_SZ) { + qemu_log_mask(LOG_GUEST_ERROR, + "M25P80: Write overrun internal data buffer. " + "SPI controller (QEMU emulator or guest driver) " + "is misbehaving\n"); + s->len = s->pos = 0; + s->state = STATE_IDLE; + break; + } + s->data[s->len] = (uint8_t)tx; s->len++; @@ -1123,6 +1138,17 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) break; case STATE_READING_DATA: + + if (s->pos >= M25P80_INTERNAL_DATA_BUFFER_SZ) { + qemu_log_mask(LOG_GUEST_ERROR, + "M25P80: Read overrun internal data buffer. " + "SPI controller (QEMU emulator or guest driver) " + "is misbehaving\n"); + s->len = s->pos = 0; + s->state = STATE_IDLE; + break; + } + r = s->data[s->pos]; s->pos++; if (s->pos == s->len) { @@ -1195,7 +1221,7 @@ static const VMStateDescription vmstate_m25p80 = { .pre_save = m25p80_pre_save, .fields = (VMStateField[]) { VMSTATE_UINT8(state, Flash), - VMSTATE_UINT8_ARRAY(data, Flash, 16), + VMSTATE_UINT8_ARRAY(data, Flash, M25P80_INTERNAL_DATA_BUFFER_SZ), VMSTATE_UINT32(len, Flash), VMSTATE_UINT32(pos, Flash), VMSTATE_UINT8(needed_bytes, Flash), diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 62d7a5661d..5f0ee9db00 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -707,6 +707,19 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) int num_devices; Error *local_err = NULL; + if (pfl->sector_len == 0) { + error_setg(errp, "attribute \"sector-length\" not specified or zero."); + return; + } + if (pfl->nb_blocs == 0) { + error_setg(errp, "attribute \"num-blocks\" not specified or zero."); + return; + } + if (pfl->name == NULL) { + error_setg(errp, "attribute \"name\" not specified."); + return; + } + total_len = pfl->sector_len * pfl->nb_blocs; /* These are only used to expose the parameters of each device diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 4f6105cc58..ef71322759 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -600,6 +600,19 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) int ret; Error *local_err = NULL; + if (pfl->sector_len == 0) { + error_setg(errp, "attribute \"sector-length\" not specified or zero."); + return; + } + if (pfl->nb_blocs == 0) { + error_setg(errp, "attribute \"num-blocks\" not specified or zero."); + return; + } + if (pfl->name == NULL) { + error_setg(errp, "attribute \"name\" not specified."); + return; + } + chip_len = pfl->sector_len * pfl->nb_blocs; /* XXX: to be fixed */ #if 0 diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 0c5fd27593..50bb0cbb93 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -588,13 +588,19 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) blk_io_plug(s->blk); - while ((req = virtio_blk_get_request(s, vq))) { - if (virtio_blk_handle_request(req, &mrb)) { - virtqueue_detach_element(req->vq, &req->elem, 0); - virtio_blk_free_request(req); - break; + do { + virtio_queue_set_notification(vq, 0); + + while ((req = virtio_blk_get_request(s, vq))) { + if (virtio_blk_handle_request(req, &mrb)) { + virtqueue_detach_element(req->vq, &req->elem, 0); + virtio_blk_free_request(req); + break; + } } - } + + virtio_queue_set_notification(vq, 1); + } while (!virtio_queue_empty(vq)); if (mrb.num_reqs) { virtio_blk_submit_multireq(s->blk, &mrb); diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 0215d6518d..4dcee571c0 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -138,9 +138,10 @@ static void fifo_trigger_update(void *opaque) { CadenceUARTState *s = opaque; - s->r[R_CISR] |= UART_INTR_TIMEOUT; - - uart_update_status(s); + if (s->r[R_RTOR]) { + s->r[R_CISR] |= UART_INTR_TIMEOUT; + uart_update_status(s); + } } static void uart_rx_reset(CadenceUARTState *s) @@ -502,6 +503,13 @@ static int cadence_uart_post_load(void *opaque, int version_id) { CadenceUARTState *s = opaque; + /* Ensure these two aren't invalid numbers */ + if (s->r[R_BRGR] < 1 || s->r[R_BRGR] & ~0xFFFF || + s->r[R_BDIV] <= 3 || s->r[R_BDIV] & ~0xFF) { + /* Value is invalid, abort */ + return 1; + } + uart_parameters_setup(s); uart_update_status(s); return 0; diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 571c324004..820d1abeb9 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -629,22 +629,26 @@ DeviceState *exynos4210_uart_create(hwaddr addr, return dev; } -static int exynos4210_uart_init(SysBusDevice *dev) +static void exynos4210_uart_init(Object *obj) { + SysBusDevice *dev = SYS_BUS_DEVICE(obj); Exynos4210UartState *s = EXYNOS4210_UART(dev); /* memory mapping */ - memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_uart_ops, s, + memory_region_init_io(&s->iomem, obj, &exynos4210_uart_ops, s, "exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); +} + +static void exynos4210_uart_realize(DeviceState *dev, Error **errp) +{ + Exynos4210UartState *s = EXYNOS4210_UART(dev); qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive, exynos4210_uart_receive, exynos4210_uart_event, s, NULL, true); - - return 0; } static Property exynos4210_uart_properties[] = { @@ -658,9 +662,8 @@ static Property exynos4210_uart_properties[] = { static void exynos4210_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = exynos4210_uart_init; + dc->realize = exynos4210_uart_realize; dc->reset = exynos4210_uart_reset; dc->props = exynos4210_uart_properties; dc->vmsd = &vmstate_exynos4210_uart; @@ -670,6 +673,7 @@ static const TypeInfo exynos4210_uart_info = { .name = TYPE_EXYNOS4210_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210UartState), + .instance_init = exynos4210_uart_init, .class_init = exynos4210_uart_class_init, }; diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c index d3017563f3..68a80b9d64 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -179,7 +179,7 @@ static int ssd0303_send(I2CSlave *i2c, uint8_t data) return 0; } -static void ssd0303_event(I2CSlave *i2c, enum i2c_event event) +static int ssd0303_event(I2CSlave *i2c, enum i2c_event event) { ssd0303_state *s = SSD0303(i2c); @@ -193,6 +193,8 @@ static void ssd0303_event(I2CSlave *i2c, enum i2c_event event) /* Nothing to do. */ break; } + + return 0; } static void ssd0303_update_display(void *opaque) diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c index 23f39de94d..b13ced38fa 100644 --- a/hw/display/virtio-gpu-3d.c +++ b/hw/display/virtio-gpu-3d.c @@ -291,8 +291,11 @@ static void virgl_resource_attach_backing(VirtIOGPU *g, return; } - virgl_renderer_resource_attach_iov(att_rb.resource_id, - res_iovs, att_rb.nr_entries); + ret = virgl_renderer_resource_attach_iov(att_rb.resource_id, + res_iovs, att_rb.nr_entries); + + if (ret != 0) + virtio_gpu_cleanup_mapping_iov(res_iovs, att_rb.nr_entries); } static void virgl_resource_detach_backing(VirtIOGPU *g, @@ -371,8 +374,12 @@ static void virgl_cmd_get_capset(VirtIOGPU *g, virgl_renderer_get_cap_set(gc.capset_id, &max_ver, &max_size); - resp = g_malloc(sizeof(*resp) + max_size); + if (!max_size) { + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + resp = g_malloc(sizeof(*resp) + max_size); resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET; virgl_renderer_fill_caps(gc.capset_id, gc.capset_version, diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 5f32e1aae9..ca88cf478d 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -28,6 +28,8 @@ static struct virtio_gpu_simple_resource* virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); +static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res); + #ifdef CONFIG_VIRGL #include <virglrenderer.h> #define VIRGL(_g, _virgl, _simple, ...) \ @@ -338,10 +340,14 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; return; } - res->image = pixman_image_create_bits(pformat, - c2d.width, - c2d.height, - NULL, 0); + + res->hostmem = PIXMAN_FORMAT_BPP(pformat) * c2d.width * c2d.height; + if (res->hostmem + g->hostmem < g->conf.max_hostmem) { + res->image = pixman_image_create_bits(pformat, + c2d.width, + c2d.height, + NULL, 0); + } if (!res->image) { qemu_log_mask(LOG_GUEST_ERROR, @@ -353,13 +359,16 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, } QTAILQ_INSERT_HEAD(&g->reslist, res, next); + g->hostmem += res->hostmem; } static void virtio_gpu_resource_destroy(VirtIOGPU *g, struct virtio_gpu_simple_resource *res) { pixman_image_unref(res->image); + virtio_gpu_cleanup_mapping(res); QTAILQ_REMOVE(&g->reslist, res, next); + g->hostmem -= res->hostmem; g_free(res); } @@ -705,6 +714,11 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g, return; } + if (res->iov) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + return; + } + ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->addrs, &res->iov); if (ret != 0) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; @@ -1241,6 +1255,8 @@ static const VMStateDescription vmstate_virtio_gpu = { static Property virtio_gpu_properties[] = { DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1), + DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf.max_hostmem, + 256 * 1024 * 1024), #ifdef CONFIG_VIRGL DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags, VIRTIO_GPU_FLAG_VIRGL_ENABLED, true), diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c index 1bd5eaf911..f82e3e6555 100644 --- a/hw/gpio/max7310.c +++ b/hw/gpio/max7310.c @@ -129,7 +129,7 @@ static int max7310_tx(I2CSlave *i2c, uint8_t data) return 0; } -static void max7310_event(I2CSlave *i2c, enum i2c_event event) +static int max7310_event(I2CSlave *i2c, enum i2c_event event) { MAX7310State *s = MAX7310(i2c); s->len = 0; @@ -147,6 +147,8 @@ static void max7310_event(I2CSlave *i2c, enum i2c_event event) default: break; } + + return 0; } static const VMStateDescription vmstate_max7310 = { diff --git a/hw/i2c/core.c b/hw/i2c/core.c index abd4c4cddb..2c1234cdff 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -88,18 +88,26 @@ int i2c_bus_busy(I2CBus *bus) return !QLIST_EMPTY(&bus->current_devs); } +/* TODO: Make this handle multiple masters. */ /* - * Returns non-zero if the address is not valid. If this is called - * again without an intervening i2c_end_transfer(), like in the SMBus - * case where the operation is switched from write to read, this - * function will not rescan the bus and thus cannot fail. + * Start or continue an i2c transaction. When this is called for the + * first time or after an i2c_end_transfer(), if it returns an error + * the bus transaction is terminated (or really never started). If + * this is called after another i2c_start_transfer() without an + * intervening i2c_end_transfer(), and it returns an error, the + * transaction will not be terminated. The caller must do it. + * + * This corresponds with the way real hardware works. The SMBus + * protocol uses a start transfer to switch from write to read mode + * without releasing the bus. If that fails, the bus is still + * in a transaction. */ -/* TODO: Make this handle multiple masters. */ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) { BusChild *kid; I2CSlaveClass *sc; I2CNode *node; + bool bus_scanned = false; if (address == I2C_BROADCAST) { /* @@ -130,6 +138,7 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) } } } + bus_scanned = true; } if (QLIST_EMPTY(&bus->current_devs)) { @@ -137,11 +146,21 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) } QLIST_FOREACH(node, &bus->current_devs, next) { + int rv; + sc = I2C_SLAVE_GET_CLASS(node->elt); /* If the bus is already busy, assume this is a repeated start condition. */ + if (sc->event) { - sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND); + rv = sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND); + if (rv && !bus->broadcast) { + if (bus_scanned) { + /* First call, terminate the transfer. */ + i2c_end_transfer(bus); + } + return rv; + } } } return 0; @@ -260,7 +279,11 @@ static int i2c_slave_qdev_init(DeviceState *dev) I2CSlave *s = I2C_SLAVE(dev); I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s); - return sc->init(s); + if (sc->init) { + return sc->init(s); + } + + return 0; } DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c index 1227212934..66899d7233 100644 --- a/hw/i2c/i2c-ddc.c +++ b/hw/i2c/i2c-ddc.c @@ -230,13 +230,15 @@ static void i2c_ddc_reset(DeviceState *ds) s->reg = 0; } -static void i2c_ddc_event(I2CSlave *i2c, enum i2c_event event) +static int i2c_ddc_event(I2CSlave *i2c, enum i2c_event event) { I2CDDCState *s = I2CDDC(i2c); if (event == I2C_START_SEND) { s->firstbyte = true; } + + return 0; } static int i2c_ddc_rx(I2CSlave *i2c) diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c index 5b4dd3eba4..2d1b79a689 100644 --- a/hw/i2c/smbus.c +++ b/hw/i2c/smbus.c @@ -67,7 +67,7 @@ static void smbus_do_write(SMBusDevice *dev) } } -static void smbus_i2c_event(I2CSlave *s, enum i2c_event event) +static int smbus_i2c_event(I2CSlave *s, enum i2c_event event) { SMBusDevice *dev = SMBUS_DEVICE(s); @@ -148,6 +148,8 @@ static void smbus_i2c_event(I2CSlave *s, enum i2c_event event) break; } } + + return 0; } static int smbus_i2c_recv(I2CSlave *s) @@ -249,7 +251,8 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) } i2c_send(bus, command); if (i2c_start_transfer(bus, addr, 1)) { - assert(0); + i2c_end_transfer(bus); + return -1; } data = i2c_recv(bus); i2c_nack(bus); @@ -276,7 +279,8 @@ int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) } i2c_send(bus, command); if (i2c_start_transfer(bus, addr, 1)) { - assert(0); + i2c_end_transfer(bus); + return -1; } data = i2c_recv(bus); data |= i2c_recv(bus) << 8; @@ -307,7 +311,8 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) } i2c_send(bus, command); if (i2c_start_transfer(bus, addr, 1)) { - assert(0); + i2c_end_transfer(bus); + return -1; } len = i2c_recv(bus); if (len > 32) { diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 9708cdc463..42ecf619d5 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -29,7 +29,7 @@ #include "hw/pci/pci.h" #include "qom/cpu.h" #include "hw/i386/pc.h" -#include "target-i386/cpu.h" +#include "target/i386/cpu.h" #include "hw/timer/hpet.h" #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 01cbaa88d2..df5180b1e0 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -15,7 +15,7 @@ #include "hw/i386/apic_internal.h" #include "hw/pci/msi.h" #include "sysemu/kvm.h" -#include "target-i386/kvm_i386.h" +#include "target/i386/kvm_i386.h" static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic, int reg_id, uint32_t val) diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 0f75dd385a..ef9d560f9c 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -36,6 +36,13 @@ typedef struct KVMClockState { uint64_t clock; bool clock_valid; + + /* whether machine type supports reliable KVM_GET_CLOCK */ + bool mach_use_reliable_get_clock; + + /* whether the 'clock' value was obtained in a host with + * reliable KVM_GET_CLOCK */ + bool clock_is_reliable; } KVMClockState; struct pvclock_vcpu_time_info { @@ -81,6 +88,60 @@ static uint64_t kvmclock_current_nsec(KVMClockState *s) return nsec + time.system_time; } +static void kvm_update_clock(KVMClockState *s) +{ + struct kvm_clock_data data; + int ret; + + ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); + if (ret < 0) { + fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); + abort(); + } + s->clock = data.clock; + + /* If kvm_has_adjust_clock_stable() is false, KVM_GET_CLOCK returns + * essentially CLOCK_MONOTONIC plus a guest-specific adjustment. This + * can drift from the TSC-based value that is computed by the guest, + * so we need to go through kvmclock_current_nsec(). If + * kvm_has_adjust_clock_stable() is true, and the flags contain + * KVM_CLOCK_TSC_STABLE, then KVM_GET_CLOCK returns a TSC-based value + * and kvmclock_current_nsec() is not necessary. + * + * Here, however, we need not check KVM_CLOCK_TSC_STABLE. This is because: + * + * - if the host has disabled the kvmclock master clock, the guest already + * has protection against time going backwards. This "safety net" is only + * absent when kvmclock is stable; + * + * - therefore, we can replace a check like + * + * if last KVM_GET_CLOCK was not reliable then + * read from memory + * + * with + * + * if last KVM_GET_CLOCK was not reliable && masterclock is enabled + * read from memory + * + * However: + * + * - if kvm_has_adjust_clock_stable() returns false, the left side is + * always true (KVM_GET_CLOCK is never reliable), and the right side is + * unknown (because we don't have data.flags). We must assume it's true + * and read from memory. + * + * - if kvm_has_adjust_clock_stable() returns true, the result of the && + * is always false (masterclock is enabled iff KVM_GET_CLOCK is reliable) + * + * So we can just use this instead: + * + * if !kvm_has_adjust_clock_stable() then + * read from memory + */ + s->clock_is_reliable = kvm_has_adjust_clock_stable(); +} + static void kvmclock_vm_state_change(void *opaque, int running, RunState state) { @@ -91,15 +152,21 @@ static void kvmclock_vm_state_change(void *opaque, int running, if (running) { struct kvm_clock_data data = {}; - uint64_t time_at_migration = kvmclock_current_nsec(s); - - s->clock_valid = false; - /* We can't rely on the migrated clock value, just discard it */ - if (time_at_migration) { - s->clock = time_at_migration; + /* + * If the host where s->clock was read did not support reliable + * KVM_GET_CLOCK, read kvmclock value from memory. + */ + if (!s->clock_is_reliable) { + uint64_t pvclock_via_mem = kvmclock_current_nsec(s); + /* We can't rely on the saved clock value, just discard it */ + if (pvclock_via_mem) { + s->clock = pvclock_via_mem; + } } + s->clock_valid = false; + data.clock = s->clock; ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data); if (ret < 0) { @@ -120,8 +187,6 @@ static void kvmclock_vm_state_change(void *opaque, int running, } } } else { - struct kvm_clock_data data; - int ret; if (s->clock_valid) { return; @@ -129,13 +194,7 @@ static void kvmclock_vm_state_change(void *opaque, int running, kvm_synchronize_all_tsc(); - ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); - if (ret < 0) { - fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); - abort(); - } - s->clock = data.clock; - + kvm_update_clock(s); /* * If the VM is stopped, declare the clock state valid to * avoid re-reading it on next vmsave (which would return @@ -149,25 +208,78 @@ static void kvmclock_realize(DeviceState *dev, Error **errp) { KVMClockState *s = KVM_CLOCK(dev); + kvm_update_clock(s); + qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s); } +static bool kvmclock_clock_is_reliable_needed(void *opaque) +{ + KVMClockState *s = opaque; + + return s->mach_use_reliable_get_clock; +} + +static const VMStateDescription kvmclock_reliable_get_clock = { + .name = "kvmclock/clock_is_reliable", + .version_id = 1, + .minimum_version_id = 1, + .needed = kvmclock_clock_is_reliable_needed, + .fields = (VMStateField[]) { + VMSTATE_BOOL(clock_is_reliable, KVMClockState), + VMSTATE_END_OF_LIST() + } +}; + +/* + * When migrating, read the clock just before migration, + * so that the guest clock counts during the events + * between: + * + * * vm_stop() + * * + * * pre_save() + * + * This reduces kvmclock difference on migration from 5s + * to 0.1s (when max_downtime == 5s), because sending the + * final pages of memory (which happens between vm_stop() + * and pre_save()) takes max_downtime. + */ +static void kvmclock_pre_save(void *opaque) +{ + KVMClockState *s = opaque; + + kvm_update_clock(s); +} + static const VMStateDescription kvmclock_vmsd = { .name = "kvmclock", .version_id = 1, .minimum_version_id = 1, + .pre_save = kvmclock_pre_save, .fields = (VMStateField[]) { VMSTATE_UINT64(clock, KVMClockState), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &kvmclock_reliable_get_clock, + NULL } }; +static Property kvmclock_properties[] = { + DEFINE_PROP_BOOL("x-mach-use-reliable-get-clock", KVMClockState, + mach_use_reliable_get_clock, true), + DEFINE_PROP_END_OF_LIST(), +}; + static void kvmclock_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = kvmclock_realize; dc->vmsd = &kvmclock_vmsd; + dc->props = kvmclock_properties; } static const TypeInfo kvmclock_info = { diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index 387caa67d4..f13e23139b 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -109,7 +109,7 @@ static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline) hwaddr p = s->offset_cmdlines; char *b = (char *)s->mb_buf + p; - get_opt_value(b, strlen(cmdline) + 1, cmdline); + memcpy(b, cmdline, strlen(cmdline) + 1); s->offset_cmdlines += strlen(b) + 1; return s->mb_buf_phys + p; } @@ -287,7 +287,8 @@ int load_multiboot(FWCfgState *fw_cfg, mbs.offset_bootloader = mbs.offset_cmdlines + cmdline_len; if (initrd_filename) { - char *next_initrd, not_last; + const char *next_initrd; + char not_last, tmpbuf[strlen(initrd_filename) + 1]; mbs.offset_mods = mbs.mb_buf_size; @@ -296,25 +297,24 @@ int load_multiboot(FWCfgState *fw_cfg, int mb_mod_length; uint32_t offs = mbs.mb_buf_size; - next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename); + next_initrd = get_opt_value(tmpbuf, sizeof(tmpbuf), initrd_filename); not_last = *next_initrd; - *next_initrd = '\0'; /* if a space comes after the module filename, treat everything after that as parameters */ - hwaddr c = mb_add_cmdline(&mbs, initrd_filename); - if ((next_space = strchr(initrd_filename, ' '))) + hwaddr c = mb_add_cmdline(&mbs, tmpbuf); + if ((next_space = strchr(tmpbuf, ' '))) *next_space = '\0'; - mb_debug("multiboot loading module: %s\n", initrd_filename); - mb_mod_length = get_image_size(initrd_filename); + mb_debug("multiboot loading module: %s\n", tmpbuf); + mb_mod_length = get_image_size(tmpbuf); if (mb_mod_length < 0) { - fprintf(stderr, "Failed to open file '%s'\n", initrd_filename); + fprintf(stderr, "Failed to open file '%s'\n", tmpbuf); exit(1); } mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size); mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size); - load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs); + load_image(tmpbuf, (unsigned char *)mbs.mb_buf + offs); mb_add_mod(&mbs, mbs.mb_buf_phys + offs, mbs.mb_buf_phys + offs + mb_mod_length, c); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index a9e64a88e5..25e8586b48 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -400,13 +400,13 @@ static void pc_cmos_init_late(void *opaque) int i, trans; val = 0; - if (ide_get_geometry(arg->idebus[0], 0, - &cylinders, &heads, §ors) >= 0) { + if (arg->idebus[0] && ide_get_geometry(arg->idebus[0], 0, + &cylinders, &heads, §ors) >= 0) { cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors); val |= 0xf0; } - if (ide_get_geometry(arg->idebus[0], 1, - &cylinders, &heads, §ors) >= 0) { + if (arg->idebus[0] && ide_get_geometry(arg->idebus[0], 1, + &cylinders, &heads, §ors) >= 0) { cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors); val |= 0x0f; } @@ -418,7 +418,8 @@ static void pc_cmos_init_late(void *opaque) geometry. It is always such that: 1 <= sects <= 63, 1 <= heads <= 16, 1 <= cylinders <= 16383. The BIOS geometry can be different if a translation is done. */ - if (ide_get_geometry(arg->idebus[i / 2], i % 2, + if (arg->idebus[i / 2] && + ide_get_geometry(arg->idebus[i / 2], i % 2, &cylinders, &heads, §ors) >= 0) { trans = ide_get_bios_chs_trans(arg->idebus[i / 2], i % 2) - 1; assert((trans & ~3) == 0); @@ -1535,6 +1536,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, bool no_vmport, + bool has_pit, uint32_t hpet_irqs) { int i; @@ -1588,7 +1590,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_register_boot_set(pc_boot_set, *rtc_state); - if (!xen_enabled()) { + if (!xen_enabled() && has_pit) { if (kvm_pit_in_kernel()) { pit = kvm_pit_init(isa_bus, 0x40); } else { @@ -2158,6 +2160,48 @@ static void pc_machine_set_nvdimm(Object *obj, bool value, Error **errp) pcms->acpi_nvdimm_state.is_enabled = value; } +static bool pc_machine_get_smbus(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->smbus; +} + +static void pc_machine_set_smbus(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->smbus = value; +} + +static bool pc_machine_get_sata(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->sata; +} + +static void pc_machine_set_sata(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->sata = value; +} + +static bool pc_machine_get_pit(Object *obj, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + return pcms->pit; +} + +static void pc_machine_set_pit(Object *obj, bool value, Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + + pcms->pit = value; +} + static void pc_machine_initfn(Object *obj) { PCMachineState *pcms = PC_MACHINE(obj); @@ -2169,6 +2213,9 @@ static void pc_machine_initfn(Object *obj) pcms->acpi_nvdimm_state.is_enabled = false; /* acpi build is enabled by default if machine supports it */ pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; + pcms->smbus = true; + pcms->sata = true; + pcms->pit = true; } static void pc_machine_reset(void) @@ -2329,6 +2376,15 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, PC_MACHINE_NVDIMM, pc_machine_get_nvdimm, pc_machine_set_nvdimm, &error_abort); + + object_class_property_add_bool(oc, PC_MACHINE_SMBUS, + pc_machine_get_smbus, pc_machine_set_smbus, &error_abort); + + object_class_property_add_bool(oc, PC_MACHINE_SATA, + pc_machine_get_sata, pc_machine_set_sata, &error_abort); + + object_class_property_add_bool(oc, PC_MACHINE_PIT, + pc_machine_get_pit, pc_machine_set_pit, &error_abort); } static const TypeInfo pc_machine_info = { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index a54a468c0a..5e1adbe53c 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -235,7 +235,7 @@ static void pc_init1(MachineState *machine, /* init basic PC hardware */ pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true, - (pcms->vmport != ON_OFF_AUTO_ON), 0x4); + (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, 0x4); pc_nic_init(isa_bus, pci_bus); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index b40d19ee00..d042fe0843 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -227,32 +227,39 @@ static void pc_q35_init(MachineState *machine) /* init basic PC hardware */ pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy, - (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104); + (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, + 0xff0104); /* connect pm stuff to lpc */ ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms)); - /* ahci and SATA device, for q35 1 ahci controller is built-in */ - ahci = pci_create_simple_multifunction(host_bus, - PCI_DEVFN(ICH9_SATA1_DEV, - ICH9_SATA1_FUNC), - true, "ich9-ahci"); - idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); - idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); - g_assert(MAX_SATA_PORTS == ICH_AHCI(ahci)->ahci.ports); - ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports); - ahci_ide_create_devs(ahci, hd); + if (pcms->sata) { + /* ahci and SATA device, for q35 1 ahci controller is built-in */ + ahci = pci_create_simple_multifunction(host_bus, + PCI_DEVFN(ICH9_SATA1_DEV, + ICH9_SATA1_FUNC), + true, "ich9-ahci"); + idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); + g_assert(MAX_SATA_PORTS == ICH_AHCI(ahci)->ahci.ports); + ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports); + ahci_ide_create_devs(ahci, hd); + } else { + idebus[0] = idebus[1] = NULL; + } if (machine_usb(machine)) { /* Should we create 6 UHCI according to ich9 spec? */ ehci_create_ich9_with_companions(host_bus, 0x1d); } - /* TODO: Populate SPD eeprom data. */ - smbus_eeprom_init(ich9_smb_init(host_bus, - PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), - 0xb100), - 8, NULL, 0); + if (pcms->smbus) { + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(ich9_smb_init(host_bus, + PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), + 0xb100), + 8, NULL, 0); + } pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c index 539682cac8..2340523da0 100644 --- a/hw/input/lm832x.c +++ b/hw/input/lm832x.c @@ -383,7 +383,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value) } } -static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event) +static int lm_i2c_event(I2CSlave *i2c, enum i2c_event event) { LM823KbdState *s = LM8323(i2c); @@ -397,6 +397,8 @@ static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event) default: break; } + + return 0; } static int lm_i2c_rx(I2CSlave *i2c) diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index 8a6c647219..f0c967b304 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -54,6 +54,7 @@ static uint32_t gicd_int_pending(GICv3State *s, int irq) * + the PENDING latch is set OR it is level triggered and the input is 1 * + its ENABLE bit is set * + the GICD enable bit for its group is set + * + its ACTIVE bit is not set (otherwise it would be Active+Pending) * Conveniently we can bulk-calculate this with bitwise operations. */ uint32_t pend, grpmask; @@ -63,9 +64,11 @@ static uint32_t gicd_int_pending(GICv3State *s, int irq) uint32_t group = *gic_bmp_ptr32(s->group, irq); uint32_t grpmod = *gic_bmp_ptr32(s->grpmod, irq); uint32_t enable = *gic_bmp_ptr32(s->enabled, irq); + uint32_t active = *gic_bmp_ptr32(s->active, irq); pend = pending | (~edge_trigger & level); pend &= enable; + pend &= ~active; if (s->gicd_ctlr & GICD_CTLR_DS) { grpmod = 0; @@ -96,12 +99,14 @@ static uint32_t gicr_int_pending(GICv3CPUState *cs) * + the PENDING latch is set OR it is level triggered and the input is 1 * + its ENABLE bit is set * + the GICD enable bit for its group is set + * + its ACTIVE bit is not set (otherwise it would be Active+Pending) * Conveniently we can bulk-calculate this with bitwise operations. */ uint32_t pend, grpmask, grpmod; pend = cs->gicr_ipendr0 | (~cs->edge_trigger & cs->level); pend &= cs->gicr_ienabler0; + pend &= ~cs->gicr_iactiver0; if (cs->gic->gicd_ctlr & GICD_CTLR_DS) { grpmod = 0; diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 0f8c4b86e0..0aa9b9ca66 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -204,7 +204,8 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) /* The CPU mp-affinity property is in MPIDR register format; squash * the affinity bytes into 32 bits as the GICR_TYPER has them. */ - cpu_affid = (cpu_affid & 0xFF00000000ULL >> 8) | (cpu_affid & 0xFFFFFF); + cpu_affid = ((cpu_affid & 0xFF00000000ULL) >> 8) | + (cpu_affid & 0xFFFFFF); s->cpu[i].gicr_typer = (cpu_affid << 32) | (1 << 24) | (i << 8) | diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index bca30c49da..35e8eb30fc 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -1118,35 +1118,35 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 3, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_bpr[GICV3_G0]), + .readfn = icc_bpr_read, .writefn = icc_bpr_write, }, { .name = "ICC_AP0R0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 4, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][0]), + .readfn = icc_ap_read, .writefn = icc_ap_write, }, { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][1]), + .readfn = icc_ap_read, .writefn = icc_ap_write, }, { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][2]), + .readfn = icc_ap_read, .writefn = icc_ap_write, }, { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][3]), + .readfn = icc_ap_read, .writefn = icc_ap_write, }, /* All the ICC_AP1R*_EL1 registers are banked */ @@ -1275,7 +1275,7 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 6, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_igrpen[GICV3_G0]), + .readfn = icc_igrpen_read, .writefn = icc_igrpen_write, }, /* This register is banked */ @@ -1299,7 +1299,6 @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 4, .type = ARM_CP_IO | ARM_CP_NO_RAW, .access = PL3_RW, - .fieldoffset = offsetof(GICv3CPUState, icc_ctlr_el3), .readfn = icc_ctlr_el3_read, .writefn = icc_ctlr_el3_write, }, diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index fd9208fde0..ea7ea0bce8 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -30,7 +30,7 @@ #include "hw/i386/ioapic_internal.h" #include "include/hw/pci/msi.h" #include "sysemu/kvm.h" -#include "target-i386/cpu.h" +#include "target/i386/cpu.h" #include "hw/i386/apic-msidef.h" #include "hw/i386/x86-iommu.h" diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index b1f3e6f6b8..95022d3607 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -86,7 +86,7 @@ #define BMC_DEV_ID TO_REG(0x1A4) #define PROT_KEY_UNLOCK 0x1688A8A8 -#define SCU_IO_REGION_SIZE 0x20000 +#define SCU_IO_REGION_SIZE 0x1000 static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { [SYS_RST_CTRL] = 0xFFCFFEDCU, @@ -231,6 +231,7 @@ static void aspeed_scu_reset(DeviceState *dev) switch (s->silicon_rev) { case AST2400_A0_SILICON_REV: + case AST2400_A1_SILICON_REV: reset = ast2400_a0_resets; break; case AST2500_A0_SILICON_REV: @@ -249,6 +250,7 @@ static void aspeed_scu_reset(DeviceState *dev) static uint32_t aspeed_silicon_revs[] = { AST2400_A0_SILICON_REV, + AST2400_A1_SILICON_REV, AST2500_A0_SILICON_REV, AST2500_A1_SILICON_REV, }; diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index 8830dc084c..5f3ac0b6f6 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -119,6 +119,7 @@ static void aspeed_sdmc_write(void *opaque, hwaddr addr, uint64_t data, /* Make sure readonly bits are kept */ switch (s->silicon_rev) { case AST2400_A0_SILICON_REV: + case AST2400_A1_SILICON_REV: data &= ~ASPEED_SDMC_READONLY_MASK; break; case AST2500_A0_SILICON_REV: @@ -193,6 +194,7 @@ static void aspeed_sdmc_reset(DeviceState *dev) /* Set ram size bit and defaults values */ switch (s->silicon_rev) { case AST2400_A0_SILICON_REV: + case AST2400_A1_SILICON_REV: s->regs[R_CONF] |= ASPEED_SDMC_VGA_COMPAT | ASPEED_SDMC_DRAM_SIZE(s->ram_bits); @@ -224,6 +226,7 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp) switch (s->silicon_rev) { case AST2400_A0_SILICON_REV: + case AST2400_A1_SILICON_REV: s->ram_bits = ast2400_rambits(s); break; case AST2500_A0_SILICON_REV: diff --git a/hw/misc/hyperv_testdev.c b/hw/misc/hyperv_testdev.c index 6cae9e9010..dbd7cdda07 100644 --- a/hw/misc/hyperv_testdev.c +++ b/hw/misc/hyperv_testdev.c @@ -17,7 +17,7 @@ #include "hw/qdev.h" #include "hw/isa/isa.h" #include "sysemu/kvm.h" -#include "target-i386/hyperv.h" +#include "target/i386/hyperv.h" #include "kvm_i386.h" #define HV_TEST_DEV_MAX_SINT_ROUTES 64 diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index f5c2472b5b..04e83787d4 100644 --- a/hw/misc/tmp105.c +++ b/hw/misc/tmp105.c @@ -176,7 +176,7 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data) return 0; } -static void tmp105_event(I2CSlave *i2c, enum i2c_event event) +static int tmp105_event(I2CSlave *i2c, enum i2c_event event) { TMP105State *s = TMP105(i2c); @@ -185,6 +185,7 @@ static void tmp105_event(I2CSlave *i2c, enum i2c_event event) } s->len = 0; + return 0; } static int tmp105_post_load(void *opaque, int version_id) diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index 54c01275d4..d0f93eebfc 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -358,25 +358,24 @@ void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr) /* Save flags before BD update */ bd_flags = bd.flags; - if (bd_flags & BD_TX_READY) { - process_tx_bd(etsec, &bd); - - /* Write back BD after update */ - write_buffer_descriptor(etsec, bd_addr, &bd); + if (!(bd_flags & BD_TX_READY)) { + break; } + process_tx_bd(etsec, &bd); + /* Write back BD after update */ + write_buffer_descriptor(etsec, bd_addr, &bd); + /* Wrap or next BD */ if (bd_flags & BD_WRAP) { bd_addr = ring_base; } else { bd_addr += sizeof(eTSEC_rxtx_bd); } + } while (TRUE); - } while (bd_addr != ring_base); - - bd_addr = ring_base; - - /* Save the Buffer Descriptor Pointers to current bd */ + /* Save the Buffer Descriptor Pointers to last bd that was not + * succesfully closed */ etsec->regs[TBPTR0 + ring_nbr].value = bd_addr; /* Set transmit halt THLTx */ diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index f05e59c85f..671c7e48c6 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -1205,6 +1205,20 @@ static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) s->RxBufAddr = 0; } +static void rtl8139_reset_phy(RTL8139State *s) +{ + s->BasicModeStatus = 0x7809; + s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ + /* preserve link state */ + s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04; + + s->NWayAdvert = 0x05e1; /* all modes, full duplex */ + s->NWayLPAR = 0x05e1; /* all modes, full duplex */ + s->NWayExpansion = 0x0001; /* autonegotiation supported */ + + s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; +} + static void rtl8139_reset(DeviceState *d) { RTL8139State *s = RTL8139(d); @@ -1256,25 +1270,14 @@ static void rtl8139_reset(DeviceState *d) s->Config3 = 0x1; /* fast back-to-back compatible */ s->Config5 = 0x0; - s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; - s->CpCmd = 0x0; /* reset C+ mode */ s->cplus_enabled = 0; - // s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation // s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex s->BasicModeCtrl = 0x1000; // autonegotiation - s->BasicModeStatus = 0x7809; - //s->BasicModeStatus |= 0x0040; /* UTP medium */ - s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ - /* preserve link state */ - s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04; - - s->NWayAdvert = 0x05e1; /* all modes, full duplex */ - s->NWayLPAR = 0x05e1; /* all modes, full duplex */ - s->NWayExpansion = 0x0001; /* autonegotiation supported */ + rtl8139_reset_phy(s); /* also reset timer and disable timer interrupt */ s->TCTR = 0; @@ -1469,7 +1472,7 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val); /* mask unwritable bits */ - uint32_t mask = 0x4cff; + uint32_t mask = 0xccff; if (1 || !rtl8139_config_writable(s)) { @@ -1479,6 +1482,11 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) mask |= 0x0100; } + if (val & 0x8000) { + /* Reset PHY */ + rtl8139_reset_phy(s); + } + val = SET_MASKED(val, mask, s->BasicModeCtrl); s->BasicModeCtrl = val; diff --git a/hw/ppc/fdt.c b/hw/ppc/fdt.c index e67d60d03c..38a7234b46 100644 --- a/hw/ppc/fdt.c +++ b/hw/ppc/fdt.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "target-ppc/cpu.h" +#include "target/ppc/cpu.h" #include "hw/ppc/fdt.h" diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 9df7b25315..83597fe92b 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -22,7 +22,7 @@ #include "sysemu/sysemu.h" #include "sysemu/numa.h" #include "hw/hw.h" -#include "target-ppc/cpu.h" +#include "target/ppc/cpu.h" #include "qemu/log.h" #include "hw/ppc/fdt.h" #include "hw/ppc/ppc.h" diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 76ce854b0c..d79d530b48 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -20,7 +20,7 @@ #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qemu/log.h" -#include "target-ppc/cpu.h" +#include "target/ppc/cpu.h" #include "hw/ppc/ppc.h" #include "hw/ppc/pnv.h" #include "hw/ppc/pnv_core.h" diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index 0e2117f0f5..78db52415b 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "sysemu/sysemu.h" -#include "target-ppc/cpu.h" +#include "target/ppc/cpu.h" #include "qapi/error.h" #include "qemu/log.h" diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 8da271872f..b82af4f086 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -21,7 +21,7 @@ #include "hw/hw.h" #include "qemu/log.h" #include "sysemu/kvm.h" -#include "target-ppc/cpu.h" +#include "target/ppc/cpu.h" #include "hw/sysbus.h" #include "hw/ppc/fdt.h" diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index e0c14f6b77..c18632bbff 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -8,14 +8,14 @@ */ #include "hw/cpu/core.h" #include "hw/ppc/spapr_cpu_core.h" -#include "target-ppc/cpu.h" +#include "target/ppc/cpu.h" #include "hw/ppc/spapr.h" #include "hw/boards.h" #include "qapi/error.h" #include "sysemu/cpus.h" -#include "target-ppc/kvm_ppc.h" +#include "target/ppc/kvm_ppc.h" #include "hw/ppc/ppc.h" -#include "target-ppc/mmu-hash64.h" +#include "target/ppc/mmu-hash64.h" #include "sysemu/numa.h" static void spapr_cpu_reset(void *opaque) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index a96319138a..bdd1e5f86c 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2157,6 +2157,13 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) DPRINTF("Write %s(sector %" PRId64 ", count %u)\n", (command & 0xe) == 0xe ? "And Verify " : "", r->req.cmd.lba, len); + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: + /* We get here only for BYTCHK == 0x01 and only for scsi-block. + * As far as DMA is concerned, we can treat it the same as a write; + * scsi_block_do_sgio will send VERIFY commands. + */ if (r->req.cmd.buf[1] & 0xe0) { goto illegal_request; } @@ -2712,7 +2719,7 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) case WRITE_VERIFY_16: /* MMC writing cannot be done via DMA helpers, because it sometimes * involves writing beyond the maximum LBA or to negative LBA (lead-in). - * We might use scsi_disk_dma_reqops as long as no writing commands are + * We might use scsi_block_dma_reqops as long as no writing commands are * seen, but performance usually isn't paramount on optical media. So, * just make scsi-block operate the same as scsi-generic for them. */ diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 10fd687193..204e14f237 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -420,6 +420,20 @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) } } +static inline void virtio_scsi_acquire(VirtIOSCSI *s) +{ + if (s->ctx) { + aio_context_acquire(s->ctx); + } +} + +static inline void virtio_scsi_release(VirtIOSCSI *s) +{ + if (s->ctx) { + aio_context_release(s->ctx); + } +} + void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; @@ -578,26 +592,32 @@ static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req, *next; - int ret; + int ret = 0; QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); - while ((req = virtio_scsi_pop_req(s, vq))) { - ret = virtio_scsi_handle_cmd_req_prepare(s, req); - if (!ret) { - QTAILQ_INSERT_TAIL(&reqs, req, next); - } else if (ret == -EINVAL) { - /* The device is broken and shouldn't process any request */ - while (!QTAILQ_EMPTY(&reqs)) { - req = QTAILQ_FIRST(&reqs); - QTAILQ_REMOVE(&reqs, req, next); - blk_io_unplug(req->sreq->dev->conf.blk); - scsi_req_unref(req->sreq); - virtqueue_detach_element(req->vq, &req->elem, 0); - virtio_scsi_free_req(req); + do { + virtio_queue_set_notification(vq, 0); + + while ((req = virtio_scsi_pop_req(s, vq))) { + ret = virtio_scsi_handle_cmd_req_prepare(s, req); + if (!ret) { + QTAILQ_INSERT_TAIL(&reqs, req, next); + } else if (ret == -EINVAL) { + /* The device is broken and shouldn't process any request */ + while (!QTAILQ_EMPTY(&reqs)) { + req = QTAILQ_FIRST(&reqs); + QTAILQ_REMOVE(&reqs, req, next); + blk_io_unplug(req->sreq->dev->conf.blk); + scsi_req_unref(req->sreq); + virtqueue_detach_element(req->vq, &req->elem, 0); + virtio_scsi_free_req(req); + } } } - } + + virtio_queue_set_notification(vq, 1); + } while (ret != -EINVAL && !virtio_queue_empty(vq)); QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { virtio_scsi_handle_cmd_req_submit(s, req); @@ -691,10 +711,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, return; } - if (s->dataplane_started) { - assert(s->ctx); - aio_context_acquire(s->ctx); - } + virtio_scsi_acquire(s); req = virtio_scsi_pop_req(s, vs->event_vq); if (!req) { @@ -730,9 +747,7 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, } virtio_scsi_complete_req(req); out: - if (s->dataplane_started) { - aio_context_release(s->ctx); - } + virtio_scsi_release(s); } void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) @@ -778,9 +793,9 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { return; } - aio_context_acquire(s->ctx); + virtio_scsi_acquire(s); blk_set_aio_context(sd->conf.blk, s->ctx); - aio_context_release(s->ctx); + virtio_scsi_release(s); } diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c index 14d4007c1c..fd00cc5ea2 100644 --- a/hw/sh4/shix.c +++ b/hw/sh4/shix.c @@ -25,7 +25,7 @@ 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 + More information in target/sh4/README.sh4 */ #include "qemu/osdep.h" #include "qapi/error.h" diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 6e8403ebc2..78f5aed532 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -253,7 +253,8 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to change CS0 start address to 0x%" HWADDR_PRIx "\n", s->ctrl->name, seg.addr); - return; + seg.addr = s->ctrl->flash_window_base; + new = aspeed_smc_segment_to_reg(&seg); } /* @@ -267,8 +268,10 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, s->ctrl->segments[cs].size) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to change CS%d end address to 0x%" - HWADDR_PRIx "\n", s->ctrl->name, cs, seg.addr); - return; + HWADDR_PRIx "\n", s->ctrl->name, cs, seg.addr + seg.size); + seg.size = s->ctrl->segments[cs].addr + s->ctrl->segments[cs].size - + seg.addr; + new = aspeed_smc_segment_to_reg(&seg); } /* Keep the segment in the overall flash window */ @@ -281,16 +284,14 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, } /* Check start address vs. alignment */ - if (seg.addr % seg.size) { + if (seg.size && !QEMU_IS_ALIGNED(seg.addr, seg.size)) { qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is not " "aligned : [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", s->ctrl->name, cs, seg.addr, seg.addr + seg.size); } - /* And segments should not overlap */ - if (aspeed_smc_flash_overlap(s, &seg, cs)) { - return; - } + /* And segments should not overlap (in the specs) */ + aspeed_smc_flash_overlap(s, &seg, cs); /* All should be fine now to move the region */ memory_region_transaction_begin(); diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index e4e395fa67..b66505ca49 100644 --- a/hw/ssi/imx_spi.c +++ b/hw/ssi/imx_spi.c @@ -320,9 +320,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value, TYPE_IMX_SPI, __func__); break; case ECSPI_TXDATA: - case ECSPI_MSGDATA: - /* Is there any difference between TXDATA and MSGDATA ? */ - /* I'll have to look in the linux driver */ if (!imx_spi_is_enabled(s)) { /* Ignore writes if device is disabled */ break; @@ -380,6 +377,14 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value, } break; + case ECSPI_MSGDATA: + /* it is not clear from the spec what MSGDATA is for */ + /* Anyway it is not used by Linux driver */ + /* So for now we just ignore it */ + qemu_log_mask(LOG_UNIMP, + "[%s]%s: Trying to write to MSGDATA, ignoring\n", + TYPE_IMX_SPI, __func__); + break; default: s->regs[index] = value; diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c index 0112949e23..3849b74a68 100644 --- a/hw/timer/ds1338.c +++ b/hw/timer/ds1338.c @@ -94,7 +94,7 @@ static void inc_regptr(DS1338State *s) } } -static void ds1338_event(I2CSlave *i2c, enum i2c_event event) +static int ds1338_event(I2CSlave *i2c, enum i2c_event event) { DS1338State *s = DS1338(i2c); @@ -113,6 +113,8 @@ static void ds1338_event(I2CSlave *i2c, enum i2c_event event) default: break; } + + return 0; } static int ds1338_recv(I2CSlave *i2c) @@ -198,11 +200,6 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) return 0; } -static int ds1338_init(I2CSlave *i2c) -{ - return 0; -} - static void ds1338_reset(DeviceState *dev) { DS1338State *s = DS1338(dev); @@ -220,7 +217,6 @@ static void ds1338_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - k->init = ds1338_init; k->event = ds1338_event; k->recv = ds1338_recv; k->send = ds1338_send; diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c index 7ba4e9a7c9..b8d914e49b 100644 --- a/hw/timer/twl92230.c +++ b/hw/timer/twl92230.c @@ -713,12 +713,14 @@ static void menelaus_write(void *opaque, uint8_t addr, uint8_t value) } } -static void menelaus_event(I2CSlave *i2c, enum i2c_event event) +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) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 1af2de2714..d40711a31d 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -87,8 +87,8 @@ struct VirtQueue /* Last used index value we have signalled on */ bool signalled_used_valid; - /* Notification enabled? */ - bool notification; + /* Nested host->guest notification disabled counter */ + unsigned int notification_disabled; uint16_t queue_index; @@ -201,7 +201,7 @@ static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val) { hwaddr pa; - if (!vq->notification) { + if (vq->notification_disabled) { return; } pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]); @@ -210,7 +210,13 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val) void virtio_queue_set_notification(VirtQueue *vq, int enable) { - vq->notification = enable; + if (enable) { + assert(vq->notification_disabled > 0); + vq->notification_disabled--; + } else { + vq->notification_disabled++; + } + if (virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) { vring_set_avail_event(vq, vring_avail_idx(vq)); } else if (enable) { @@ -959,7 +965,7 @@ void virtio_reset(void *opaque) virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR); vdev->vq[i].signalled_used = 0; vdev->vq[i].signalled_used_valid = false; - vdev->vq[i].notification = true; + vdev->vq[i].notification_disabled = 0; vdev->vq[i].vring.num = vdev->vq[i].vring.num_default; vdev->vq[i].inuse = 0; } @@ -1770,7 +1776,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) vdev->vq[i].vring.desc = qemu_get_be64(f); qemu_get_be16s(f, &vdev->vq[i].last_avail_idx); vdev->vq[i].signalled_used_valid = false; - vdev->vq[i].notification = true; + vdev->vq[i].notification_disabled = 0; if (vdev->vq[i].vring.desc) { /* XXX virtio-1 devices */ @@ -2047,15 +2053,47 @@ static void virtio_queue_host_notifier_aio_read(EventNotifier *n) } } +static void virtio_queue_host_notifier_aio_poll_begin(EventNotifier *n) +{ + VirtQueue *vq = container_of(n, VirtQueue, host_notifier); + + virtio_queue_set_notification(vq, 0); +} + +static bool virtio_queue_host_notifier_aio_poll(void *opaque) +{ + EventNotifier *n = opaque; + VirtQueue *vq = container_of(n, VirtQueue, host_notifier); + + if (virtio_queue_empty(vq)) { + return false; + } + + virtio_queue_notify_aio_vq(vq); + return true; +} + +static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n) +{ + VirtQueue *vq = container_of(n, VirtQueue, host_notifier); + + /* Caller polls once more after this to catch requests that race with us */ + virtio_queue_set_notification(vq, 1); +} + void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, VirtIOHandleOutput handle_output) { if (handle_output) { vq->handle_aio_output = handle_output; aio_set_event_notifier(ctx, &vq->host_notifier, true, - virtio_queue_host_notifier_aio_read); + virtio_queue_host_notifier_aio_read, + virtio_queue_host_notifier_aio_poll); + aio_set_event_notifier_poll(ctx, &vq->host_notifier, + virtio_queue_host_notifier_aio_poll_begin, + virtio_queue_host_notifier_aio_poll_end); } else { - aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL); + aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL); /* Test and clear notifier before after disabling event, * in case poll callback didn't have time to run. */ virtio_queue_host_notifier_aio_read(&vq->host_notifier); diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index a83d951213..49b3cd188a 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -428,6 +428,14 @@ static void i6300esb_realize(PCIDevice *dev, Error **errp) /* qemu_register_coalesced_mmio (addr, 0x10); ? */ } +static void i6300esb_exit(PCIDevice *dev) +{ + I6300State *d = WATCHDOG_I6300ESB_DEVICE(dev); + + timer_del(d->timer); + timer_free(d->timer); +} + static WatchdogTimerModel model = { .wdt_name = "i6300esb", .wdt_description = "Intel 6300ESB", @@ -441,6 +449,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data) k->config_read = i6300esb_config_read; k->config_write = i6300esb_config_write; k->realize = i6300esb_realize; + k->exit = i6300esb_exit; k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_ESB_9; k->class_id = PCI_CLASS_SYSTEM_OTHER; diff --git a/include/block/aio.h b/include/block/aio.h index c7ae27c91c..4dca54d9c7 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -44,6 +44,7 @@ void qemu_aio_ref(void *p); typedef struct AioHandler AioHandler; typedef void QEMUBHFunc(void *opaque); +typedef bool AioPollFn(void *opaque); typedef void IOHandler(void *opaque); struct ThreadPool; @@ -130,6 +131,18 @@ struct AioContext { int external_disable_cnt; + /* Number of AioHandlers without .io_poll() */ + int poll_disable_cnt; + + /* Polling mode parameters */ + int64_t poll_ns; /* current polling time in nanoseconds */ + int64_t poll_max_ns; /* maximum polling time in nanoseconds */ + int64_t poll_grow; /* polling time growth factor */ + int64_t poll_shrink; /* polling time shrink factor */ + + /* Are we in polling mode or monitoring file descriptors? */ + bool poll_started; + /* epoll(7) state used when built with CONFIG_EPOLL */ int epollfd; bool epoll_enabled; @@ -195,8 +208,8 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque); * aio_notify: Force processing of pending events. * * Similar to signaling a condition variable, aio_notify forces - * aio_wait to exit, so that the next call will re-examine pending events. - * The caller of aio_notify will usually call aio_wait again very soon, + * aio_poll to exit, so that the next call will re-examine pending events. + * The caller of aio_notify will usually call aio_poll again very soon, * or go through another iteration of the GLib main loop. Hence, aio_notify * also has the side effect of recalculating the sets of file descriptors * that the main loop waits for. @@ -295,8 +308,12 @@ bool aio_pending(AioContext *ctx); /* Dispatch any pending callbacks from the GSource attached to the AioContext. * * This is used internally in the implementation of the GSource. + * + * @dispatch_fds: true to process fds, false to skip them + * (can be used as an optimization by callers that know there + * are no fds ready) */ -bool aio_dispatch(AioContext *ctx); +bool aio_dispatch(AioContext *ctx, bool dispatch_fds); /* Progress in completing AIO work to occur. This can issue new pending * aio as a result of executing I/O completion or bh callbacks. @@ -325,8 +342,17 @@ void aio_set_fd_handler(AioContext *ctx, bool is_external, IOHandler *io_read, IOHandler *io_write, + AioPollFn *io_poll, void *opaque); +/* Set polling begin/end callbacks for a file descriptor that has already been + * registered with aio_set_fd_handler. Do nothing if the file descriptor is + * not registered. + */ +void aio_set_fd_poll(AioContext *ctx, int fd, + IOHandler *io_poll_begin, + IOHandler *io_poll_end); + /* Register an event notifier and associated callbacks. Behaves very similarly * to event_notifier_set_handler. Unlike event_notifier_set_handler, these callbacks * will be invoked when using aio_poll(). @@ -337,7 +363,17 @@ void aio_set_fd_handler(AioContext *ctx, void aio_set_event_notifier(AioContext *ctx, EventNotifier *notifier, bool is_external, - EventNotifierHandler *io_read); + EventNotifierHandler *io_read, + AioPollFn *io_poll); + +/* Set polling begin/end callbacks for an event notifier that has already been + * registered with aio_set_event_notifier. Do nothing if the event notifier is + * not registered. + */ +void aio_set_event_notifier_poll(AioContext *ctx, + EventNotifier *notifier, + EventNotifierHandler *io_poll_begin, + EventNotifierHandler *io_poll_end); /* Return a GSource that lets the main loop poll the file descriptors attached * to this AioContext. @@ -474,4 +510,17 @@ static inline bool aio_context_in_iothread(AioContext *ctx) */ void aio_context_setup(AioContext *ctx); +/** + * aio_context_set_poll_params: + * @ctx: the aio context + * @max_ns: how long to busy poll for, in nanoseconds + * @grow: polling time growth factor + * @shrink: polling time shrink factor + * + * Poll mode can be disabled by setting poll_max_ns to 0. + */ +void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, + int64_t grow, int64_t shrink, + Error **errp); + #endif diff --git a/include/block/block_int.h b/include/block/block_int.h index 83a423c580..4e4562d444 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -184,7 +184,7 @@ struct BlockDriver { /* * Flushes all data that was already written to the OS all the way down to - * the disk (for example raw-posix calls fsync()). + * the disk (for example file-posix.c calls fsync()). */ int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index e9004e5798..ffe43d5654 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -186,6 +186,29 @@ void address_space_stl(AddressSpace *as, hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result); + +uint32_t lduw_phys_cached(MemoryRegionCache *cache, hwaddr addr); +uint32_t ldl_phys_cached(MemoryRegionCache *cache, hwaddr addr); +uint64_t ldq_phys_cached(MemoryRegionCache *cache, hwaddr addr); +void stl_phys_notdirty_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +void stw_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +void stl_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +void stq_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val); + +uint32_t address_space_lduw_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +uint32_t address_space_ldl_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +uint64_t address_space_ldq_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stl_notdirty_cached(MemoryRegionCache *cache, hwaddr addr, + uint32_t val, MemTxAttrs attrs, MemTxResult *result); +void address_space_stw_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stl_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stq_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val, + MemTxAttrs attrs, MemTxResult *result); #endif /* page related stuff */ diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index cffdc130e6..bd15853e51 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -94,21 +94,6 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr); */ void qemu_flush_coalesced_mmio_buffer(void); -uint32_t ldub_phys(AddressSpace *as, hwaddr addr); -uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr); -uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr); -uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr); -uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr); -uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr); -uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr); -void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val); -void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val); -void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val); -void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val); -void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val); -void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val); -void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val); - void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr, const uint8_t *buf, int len); void cpu_flush_icache_range(hwaddr start, int len); diff --git a/include/exec/memory.h b/include/exec/memory.h index 9728a2fb1a..64560f61b4 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1404,6 +1404,140 @@ void address_space_stq_le(AddressSpace *as, hwaddr addr, uint64_t val, void address_space_stq_be(AddressSpace *as, hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result); +uint32_t ldub_phys(AddressSpace *as, hwaddr addr); +uint32_t lduw_le_phys(AddressSpace *as, hwaddr addr); +uint32_t lduw_be_phys(AddressSpace *as, hwaddr addr); +uint32_t ldl_le_phys(AddressSpace *as, hwaddr addr); +uint32_t ldl_be_phys(AddressSpace *as, hwaddr addr); +uint64_t ldq_le_phys(AddressSpace *as, hwaddr addr); +uint64_t ldq_be_phys(AddressSpace *as, hwaddr addr); +void stb_phys(AddressSpace *as, hwaddr addr, uint32_t val); +void stw_le_phys(AddressSpace *as, hwaddr addr, uint32_t val); +void stw_be_phys(AddressSpace *as, hwaddr addr, uint32_t val); +void stl_le_phys(AddressSpace *as, hwaddr addr, uint32_t val); +void stl_be_phys(AddressSpace *as, hwaddr addr, uint32_t val); +void stq_le_phys(AddressSpace *as, hwaddr addr, uint64_t val); +void stq_be_phys(AddressSpace *as, hwaddr addr, uint64_t val); + +struct MemoryRegionCache { + hwaddr xlat; + void *ptr; + hwaddr len; + MemoryRegion *mr; + bool is_write; +}; + +/* address_space_cache_init: prepare for repeated access to a physical + * memory region + * + * @cache: #MemoryRegionCache to be filled + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @len: length of buffer + * @is_write: indicates the transfer direction + * + * Will only work with RAM, and may map a subset of the requested range by + * returning a value that is less than @len. On failure, return a negative + * errno value. + * + * Because it only works with RAM, this function can be used for + * read-modify-write operations. In this case, is_write should be %true. + * + * Note that addresses passed to the address_space_*_cached functions + * are relative to @addr. + */ +int64_t address_space_cache_init(MemoryRegionCache *cache, + AddressSpace *as, + hwaddr addr, + hwaddr len, + bool is_write); + +/** + * address_space_cache_invalidate: complete a write to a #MemoryRegionCache + * + * @cache: The #MemoryRegionCache to operate on. + * @addr: The first physical address that was written, relative to the + * address that was passed to @address_space_cache_init. + * @access_len: The number of bytes that were written starting at @addr. + */ +void address_space_cache_invalidate(MemoryRegionCache *cache, + hwaddr addr, + hwaddr access_len); + +/** + * address_space_cache_destroy: free a #MemoryRegionCache + * + * @cache: The #MemoryRegionCache whose memory should be released. + */ +void address_space_cache_destroy(MemoryRegionCache *cache); + +/* address_space_ld*_cached: load from a cached #MemoryRegion + * address_space_st*_cached: store into a cached #MemoryRegion + * + * These functions perform a load or store of the byte, word, + * longword or quad to the specified address. The address is + * a physical address in the AddressSpace, but it must lie within + * a #MemoryRegion that was mapped with address_space_cache_init. + * + * The _le suffixed functions treat the data as little endian; + * _be indicates big endian; no suffix indicates "same endianness + * as guest CPU". + * + * The "guest CPU endianness" accessors are deprecated for use outside + * target-* code; devices should be CPU-agnostic and use either the LE + * or the BE accessors. + * + * @cache: previously initialized #MemoryRegionCache to be accessed + * @addr: address within the address space + * @val: data value, for stores + * @attrs: memory transaction attributes + * @result: location to write the success/failure of the transaction; + * if NULL, this information is discarded + */ +uint32_t address_space_ldub_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +uint32_t address_space_lduw_le_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +uint32_t address_space_lduw_be_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +uint32_t address_space_ldl_le_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +uint32_t address_space_ldl_be_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +uint64_t address_space_ldq_le_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +uint64_t address_space_ldq_be_cached(MemoryRegionCache *cache, hwaddr addr, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stb_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stw_le_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stw_be_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stl_le_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stl_be_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stq_le_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val, + MemTxAttrs attrs, MemTxResult *result); +void address_space_stq_be_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val, + MemTxAttrs attrs, MemTxResult *result); + +uint32_t ldub_phys_cached(MemoryRegionCache *cache, hwaddr addr); +uint32_t lduw_le_phys_cached(MemoryRegionCache *cache, hwaddr addr); +uint32_t lduw_be_phys_cached(MemoryRegionCache *cache, hwaddr addr); +uint32_t ldl_le_phys_cached(MemoryRegionCache *cache, hwaddr addr); +uint32_t ldl_be_phys_cached(MemoryRegionCache *cache, hwaddr addr); +uint64_t ldq_le_phys_cached(MemoryRegionCache *cache, hwaddr addr); +uint64_t ldq_be_phys_cached(MemoryRegionCache *cache, hwaddr addr); +void stb_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +void stw_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +void stw_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +void stl_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +void stl_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val); +void stq_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val); +void stq_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val); + /* address_space_translate: translate an address range into an address space * into a MemoryRegion and an address range into that section. Should be * called from an RCU critical section, to avoid that the last reference @@ -1529,6 +1663,38 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, return result; } +/** + * address_space_read_cached: read from a cached RAM region + * + * @cache: Cached region to be addressed + * @addr: address relative to the base of the RAM region + * @buf: buffer with the data transferred + * @len: length of the data transferred + */ +static inline void +address_space_read_cached(MemoryRegionCache *cache, hwaddr addr, + void *buf, int len) +{ + assert(addr < cache->len && len <= cache->len - addr); + memcpy(buf, cache->ptr + addr, len); +} + +/** + * address_space_write_cached: write to a cached RAM region + * + * @cache: Cached region to be addressed + * @addr: address relative to the base of the RAM region + * @buf: buffer with the data transferred + * @len: length of the data transferred + */ +static inline void +address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, + void *buf, int len) +{ + assert(addr < cache->len && len <= cache->len - addr); + memcpy(cache->ptr + addr, buf, len); +} + #endif #endif diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 154f3b82f6..d43ec005cb 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -191,10 +191,8 @@ struct AcpiFadtDescriptorRev5_1 { typedef struct AcpiFadtDescriptorRev5_1 AcpiFadtDescriptorRev5_1; -enum { - ACPI_FADT_ARM_USE_PSCI_G_0_2 = 0, - ACPI_FADT_ARM_PSCI_USE_HVC = 1, -}; +#define ACPI_FADT_ARM_PSCI_COMPLIANT (1 << 0) +#define ACPI_FADT_ARM_PSCI_USE_HVC (1 << 1) /* * Serial Port Console Redirection Table (SPCR), Rev. 1.02 @@ -290,7 +288,7 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable; #define ACPI_APIC_XRUPT_SOURCE 8 #define ACPI_APIC_LOCAL_X2APIC 9 #define ACPI_APIC_LOCAL_X2APIC_NMI 10 -#define ACPI_APIC_GENERIC_INTERRUPT 11 +#define ACPI_APIC_GENERIC_CPU_INTERFACE 11 #define ACPI_APIC_GENERIC_DISTRIBUTOR 12 #define ACPI_APIC_GENERIC_MSI_FRAME 13 #define ACPI_APIC_GENERIC_REDISTRIBUTOR 14 @@ -361,7 +359,7 @@ struct AcpiMadtLocalX2ApicNmi { } QEMU_PACKED; typedef struct AcpiMadtLocalX2ApicNmi AcpiMadtLocalX2ApicNmi; -struct AcpiMadtGenericInterrupt { +struct AcpiMadtGenericCpuInterface { ACPI_SUB_HEADER_DEF uint16_t reserved; uint32_t cpu_interface_number; @@ -378,7 +376,10 @@ struct AcpiMadtGenericInterrupt { uint64_t arm_mpidr; } QEMU_PACKED; -typedef struct AcpiMadtGenericInterrupt AcpiMadtGenericInterrupt; +typedef struct AcpiMadtGenericCpuInterface AcpiMadtGenericCpuInterface; + +/* GICC CPU Interface Flags */ +#define ACPI_MADT_GICC_ENABLED 1 struct AcpiMadtGenericDistributor { ACPI_SUB_HEADER_DEF @@ -427,21 +428,9 @@ typedef struct AcpiMadtGenericTranslator AcpiMadtGenericTranslator; /* * Generic Timer Description Table (GTDT) */ - -#define ACPI_GTDT_INTERRUPT_MODE (1 << 0) -#define ACPI_GTDT_INTERRUPT_POLARITY (1 << 1) -#define ACPI_GTDT_ALWAYS_ON (1 << 2) - -/* Triggering */ - -#define ACPI_LEVEL_SENSITIVE ((uint8_t) 0x00) -#define ACPI_EDGE_SENSITIVE ((uint8_t) 0x01) - -/* Polarity */ - -#define ACPI_ACTIVE_HIGH ((uint8_t) 0x00) -#define ACPI_ACTIVE_LOW ((uint8_t) 0x01) -#define ACPI_ACTIVE_BOTH ((uint8_t) 0x02) +#define ACPI_GTDT_INTERRUPT_MODE_LEVEL (0 << 0) +#define ACPI_GTDT_INTERRUPT_MODE_EDGE (1 << 0) +#define ACPI_GTDT_CAP_ALWAYS_ON (1 << 2) struct AcpiGenericTimerTable { ACPI_TABLE_HEADER_DEF diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h index aeeebfed90..c175c0e999 100644 --- a/include/hw/arm/arm.h +++ b/include/hw/arm/arm.h @@ -12,7 +12,7 @@ #define HW_ARM_H #include "exec/memory.h" -#include "target-arm/cpu-qom.h" +#include "target/arm/cpu-qom.h" #include "hw/irq.h" #include "qemu/notify.h" diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 5406b498d7..1ab5deaa08 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -27,8 +27,9 @@ typedef struct AspeedSoCState { DeviceState parent; /*< public >*/ - ARMCPU *cpu; + ARMCPU cpu; MemoryRegion iomem; + MemoryRegion sram; AspeedVICState vic; AspeedTimerCtrlState timerctrl; AspeedI2CState i2c; @@ -46,6 +47,7 @@ typedef struct AspeedSoCInfo { const char *cpu_model; uint32_t silicon_rev; hwaddr sdram_base; + uint64_t sram_size; int spis_num; const hwaddr *spi_bases; const char *fmc_typename; diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h index 29fef8bfa1..76bb6d4203 100644 --- a/include/hw/arm/exynos4210.h +++ b/include/hw/arm/exynos4210.h @@ -27,7 +27,7 @@ #include "qemu-common.h" #include "exec/memory.h" -#include "target-arm/cpu-qom.h" +#include "target/arm/cpu-qom.h" #define EXYNOS4210_NCPUS 2 diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h index f026c8df57..f25870b718 100644 --- a/include/hw/arm/omap.h +++ b/include/hw/arm/omap.h @@ -20,7 +20,7 @@ #include "exec/memory.h" # define hw_omap_h "omap.h" #include "hw/irq.h" -#include "target-arm/cpu-qom.h" +#include "target/arm/cpu-qom.h" # define OMAP_EMIFS_BASE 0x00000000 # define OMAP2_Q0_BASE 0x00000000 diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h index 191e068184..0df1199caa 100644 --- a/include/hw/arm/pxa.h +++ b/include/hw/arm/pxa.h @@ -11,7 +11,7 @@ #define PXA_H #include "exec/memory.h" -#include "target-arm/cpu-qom.h" +#include "target/arm/cpu-qom.h" /* Interrupt numbers */ # define PXA2XX_PIC_SSP3 0 diff --git a/include/hw/arm/virt-acpi-build.h b/include/hw/arm/virt-acpi-build.h deleted file mode 100644 index f5ec749b8f..0000000000 --- a/include/hw/arm/virt-acpi-build.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD. - * - * Author: Shannon Zhao <zhaoshenglong@huawei.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef QEMU_VIRT_ACPI_BUILD_H -#define QEMU_VIRT_ACPI_BUILD_H - -#include "qemu-common.h" -#include "hw/arm/virt.h" -#include "qemu/notify.h" - -#define ACPI_GICC_ENABLED 1 - -typedef struct VirtGuestInfo { - int smp_cpus; - FWCfgState *fw_cfg; - const MemMapEntry *memmap; - const int *irqmap; - bool use_highmem; - int gic_version; - bool no_its; -} VirtGuestInfo; - - -typedef struct VirtGuestInfoState { - VirtGuestInfo info; - Notifier machine_done; -} VirtGuestInfoState; - -void virt_acpi_setup(VirtGuestInfo *guest_info); - -#endif diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index 9650193253..eb1c63d688 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -32,6 +32,9 @@ #include "qemu-common.h" #include "exec/hwaddr.h" +#include "qemu/notify.h" +#include "hw/boards.h" +#include "hw/arm/arm.h" #define NUM_GICV2M_SPIS 64 #define NUM_VIRTIO_TRANSPORTS 32 @@ -74,5 +77,41 @@ typedef struct MemMapEntry { hwaddr size; } MemMapEntry; +typedef struct { + MachineClass parent; + bool disallow_affinity_adjustment; + bool no_its; + bool no_pmu; + bool claim_edge_triggered_timers; +} VirtMachineClass; -#endif +typedef struct { + MachineState parent; + Notifier machine_done; + FWCfgState *fw_cfg; + bool secure; + bool highmem; + int32_t gic_version; + struct arm_boot_info bootinfo; + const MemMapEntry *memmap; + const int *irqmap; + int smp_cpus; + void *fdt; + int fdt_size; + uint32_t clock_phandle; + uint32_t gic_phandle; + uint32_t msi_phandle; + bool using_psci; +} VirtMachineState; + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ + OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE) +#define VIRT_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE) +#define VIRT_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) + +void virt_acpi_setup(VirtMachineState *vms); + +#endif /* QEMU_ARM_VIRT_H */ diff --git a/include/hw/compat.h b/include/hw/compat.h index 8dfc7a38c0..4fe44d1c7a 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -1,6 +1,9 @@ #ifndef HW_COMPAT_H #define HW_COMPAT_H +#define HW_COMPAT_2_8 \ + /* empty */ + #define HW_COMPAT_2_7 \ {\ .driver = "virtio-pci",\ diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index c4085aa366..2ce611d4c8 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -32,14 +32,22 @@ typedef struct I2CSlaveClass /* Callbacks provided by the device. */ int (*init)(I2CSlave *dev); - /* Master to slave. */ + /* Master to slave. Returns non-zero for a NAK, 0 for success. */ int (*send)(I2CSlave *s, uint8_t data); - /* Slave to master. */ + /* + * Slave to master. This cannot fail, the device should always + * return something here. Negative values probably result in 0xff + * and a possible log from the driver, and shouldn't be used. + */ int (*recv)(I2CSlave *s); - /* Notify the slave of a bus state change. */ - void (*event)(I2CSlave *s, enum i2c_event event); + /* + * Notify the slave of a bus state change. For start event, + * returns non-zero to NAK an operation. For other events the + * return code is not used and should be zero. + */ + int (*event)(I2CSlave *s, enum i2c_event event); } I2CSlaveClass; struct I2CSlave diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 4b74130559..b22e699c46 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -63,6 +63,9 @@ struct PCMachineState { AcpiNVDIMMState acpi_nvdimm_state; bool acpi_build_enabled; + bool smbus; + bool sata; + bool pit; /* RAM information (sizes, addresses, configuration): */ ram_addr_t below_4g_mem_size, above_4g_mem_size; @@ -88,6 +91,9 @@ struct PCMachineState { #define PC_MACHINE_VMPORT "vmport" #define PC_MACHINE_SMM "smm" #define PC_MACHINE_NVDIMM "nvdimm" +#define PC_MACHINE_SMBUS "smbus" +#define PC_MACHINE_SATA "sata" +#define PC_MACHINE_PIT "pit" /** * PCMachineClass: @@ -260,6 +266,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, bool create_fdctrl, bool no_vmport, + bool has_pit, uint32_t hpet_irqs); void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); void pc_cmos_init(PCMachineState *pcms, @@ -372,6 +379,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); #define PC_COMPAT_2_7 \ HW_COMPAT_2_7 \ {\ + .driver = "kvmclock",\ + .property = "x-mach-use-reliable-get-clock",\ + .value = "off",\ + },\ + {\ .driver = TYPE_X86_CPU,\ .property = "l3-cache",\ .value = "off",\ diff --git a/include/hw/m68k/mcf.h b/include/hw/m68k/mcf.h index 0f0d2288e6..fdae229502 100644 --- a/include/hw/m68k/mcf.h +++ b/include/hw/m68k/mcf.h @@ -2,7 +2,7 @@ #define HW_MCF_H /* Motorola ColdFire device prototypes. */ -#include "target-m68k/cpu-qom.h" +#include "target/m68k/cpu-qom.h" struct MemoryRegion; diff --git a/include/hw/mips/cpudevs.h b/include/hw/mips/cpudevs.h index 8673daa39d..698339b83e 100644 --- a/include/hw/mips/cpudevs.h +++ b/include/hw/mips/cpudevs.h @@ -1,7 +1,7 @@ #ifndef HW_MIPS_CPUDEVS_H #define HW_MIPS_CPUDEVS_H -#include "target-mips/cpu-qom.h" +#include "target/mips/cpu-qom.h" /* Definitions for MIPS CPU internal devices. */ diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h index 14ffc43de8..bd4ac013f9 100644 --- a/include/hw/misc/aspeed_scu.h +++ b/include/hw/misc/aspeed_scu.h @@ -32,6 +32,7 @@ typedef struct AspeedSCUState { } AspeedSCUState; #define AST2400_A0_SILICON_REV 0x02000303U +#define AST2400_A1_SILICON_REV 0x02010303U #define AST2500_A0_SILICON_REV 0x04000303U #define AST2500_A1_SILICON_REV 0x04010303U diff --git a/include/hw/ppc/fdt.h b/include/hw/ppc/fdt.h index 0cabb6af04..bd5b0a8c3d 100644 --- a/include/hw/ppc/fdt.h +++ b/include/hw/ppc/fdt.h @@ -11,7 +11,7 @@ #define PPC_FDT_H #include "qemu/error-report.h" -#include "target-ppc/cpu-qom.h" +#include "target/ppc/cpu-qom.h" #define _FDT(exp) \ do { \ diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h index 00c1fb1e72..4e7fe110d6 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -1,7 +1,7 @@ #ifndef HW_PPC_H #define HW_PPC_H -#include "target-ppc/cpu-qom.h" +#include "target/ppc/cpu-qom.h" void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h index 283969bafb..50292f48b1 100644 --- a/include/hw/ppc/spapr_cpu_core.h +++ b/include/hw/ppc/spapr_cpu_core.h @@ -11,7 +11,7 @@ #include "hw/qdev.h" #include "hw/cpu/core.h" -#include "target-ppc/cpu-qom.h" +#include "target/ppc/cpu-qom.h" #define TYPE_SPAPR_CPU_CORE "spapr-cpu-core" #define SPAPR_CPU_CORE(obj) \ diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h index 070312d921..e59b9e7c45 100644 --- a/include/hw/sh4/sh.h +++ b/include/hw/sh4/sh.h @@ -3,7 +3,7 @@ /* Definitions for SH board emulation. */ #include "hw/sh4/sh_intc.h" -#include "target-sh4/cpu-qom.h" +#include "target/sh4/cpu-qom.h" #define A7ADDR(x) ((x) & 0x1fffffff) #define P4ADDR(x) ((x) | 0xe0000000) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 20d1cd683a..f3a98a3261 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -38,6 +38,7 @@ struct virtio_gpu_simple_resource { unsigned int iov_cnt; uint32_t scanout_bitmask; pixman_image_t *image; + uint64_t hostmem; QTAILQ_ENTRY(virtio_gpu_simple_resource) next; }; @@ -68,6 +69,7 @@ enum virtio_gpu_conf_flags { (_cfg.flags & (1 << VIRTIO_GPU_FLAG_STATS_ENABLED)) struct virtio_gpu_conf { + uint64_t max_hostmem; uint32_t max_outputs; uint32_t flags; }; @@ -103,6 +105,7 @@ typedef struct VirtIOGPU { struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUTS]; struct virtio_gpu_conf conf; + uint64_t hostmem; int enabled_output_bitmask; struct virtio_gpu_config virtio_config; diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index e6a60d55fd..12584ed1b7 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -71,6 +71,12 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque); void qemu_coroutine_enter(Coroutine *coroutine); /** + * Transfer control to a coroutine if it's not active (i.e. part of the call + * stack of the running coroutine). Otherwise, do nothing. + */ +void qemu_coroutine_enter_if_inactive(Coroutine *co); + +/** * Transfer control back to a coroutine's caller * * This function does not return until the coroutine is re-entered using diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 470f600bbc..a9d4f23cd9 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -238,7 +238,7 @@ bool qemu_mutex_iothread_locked(void); * qemu_mutex_lock_iothread: Lock the main loop mutex. * * This function locks the main loop mutex. The mutex is taken by - * qemu_init_main_loop and always taken except while waiting on + * main() in vl.c and always taken except while waiting on * external events (such as with select). The mutex should be taken * by threads other than the main loop thread when calling * qemu_bh_new(), qemu_set_fd_handler() and basically all other @@ -253,7 +253,7 @@ void qemu_mutex_lock_iothread(void); * qemu_mutex_unlock_iothread: Unlock the main loop mutex. * * This function unlocks the main loop mutex. The mutex is taken by - * qemu_init_main_loop and always taken except while waiting on + * main() in vl.c and always taken except while waiting on * external events (such as with select). The mutex should be unlocked * as soon as possible by threads other than the main loop thread, * because it prevents the main loop from processing callbacks, diff --git a/include/qemu/timer.h b/include/qemu/timer.h index bdfae004e4..9abed51ae8 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -133,7 +133,7 @@ bool qemu_clock_has_timers(QEMUClockType type); * @type: the clock type * * Determines whether a clock's default timer list - * has an expired clock. + * has an expired timer. * * Returns: true if the clock's default timer list has * an expired timer diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 1b8c30a7a0..9a8bcbde36 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -45,6 +45,7 @@ typedef struct MachineState MachineState; typedef struct MemoryListener MemoryListener; typedef struct MemoryMappingList MemoryMappingList; typedef struct MemoryRegion MemoryRegion; +typedef struct MemoryRegionCache MemoryRegionCache; typedef struct MemoryRegionSection MemoryRegionSection; typedef struct MigrationIncomingState MigrationIncomingState; typedef struct MigrationParams MigrationParams; diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h index 7361a16b50..b472b8530c 100644 --- a/include/standard-headers/linux/input.h +++ b/include/standard-headers/linux/input.h @@ -245,6 +245,7 @@ struct input_mask { #define BUS_SPI 0x1C #define BUS_RMI 0x1D #define BUS_CEC 0x1E +#define BUS_INTEL_ISHTP 0x1F /* * MT_TOOL types diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index 404095124a..e5a2e68b22 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -612,6 +612,8 @@ */ #define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ #define PCI_EXP_DEVCAP2_ARI 0x00000020 /* Alternative Routing-ID */ +#define PCI_EXP_DEVCAP2_ATOMIC_ROUTE 0x00000040 /* Atomic Op routing */ +#define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* Atomic 64-bit compare */ #define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */ #define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */ #define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */ @@ -619,6 +621,7 @@ #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ #define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */ #define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */ +#define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040 /* Set Atomic requests */ #define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100 /* Allow IDO for requests */ #define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200 /* Allow IDO for completions */ #define PCI_EXP_DEVCTL2_LTR_EN 0x0400 /* Enable LTR mechanism */ @@ -671,7 +674,8 @@ #define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */ #define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */ #define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */ -#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DPC +#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */ +#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM #define PCI_EXT_CAP_DSN_SIZEOF 12 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 @@ -964,4 +968,13 @@ #define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */ +/* Precision Time Measurement */ +#define PCI_PTM_CAP 0x04 /* PTM Capability */ +#define PCI_PTM_CAP_REQ 0x00000001 /* Requester capable */ +#define PCI_PTM_CAP_ROOT 0x00000004 /* Root capable */ +#define PCI_PTM_GRANULARITY_MASK 0x0000FF00 /* Clock granularity */ +#define PCI_PTM_CTRL 0x08 /* PTM Control */ +#define PCI_PTM_CTRL_ENABLE 0x00000001 /* PTM enable */ +#define PCI_PTM_CTRL_ROOT 0x00000002 /* Root select */ + #endif /* LINUX_PCI_REGS_H */ diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h index 68ac2de83a..e6da1a4087 100644 --- a/include/sysemu/iothread.h +++ b/include/sysemu/iothread.h @@ -28,6 +28,11 @@ typedef struct { QemuCond init_done_cond; /* is thread initialization done? */ bool stopping; int thread_id; + + /* AioContext poll parameters */ + int64_t poll_max_ns; + int64_t poll_grow; + int64_t poll_shrink; } IOThread; #define IOTHREAD(obj) \ diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index f80d6d28e8..abb35ca8c9 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -39,6 +39,8 @@ enum ReplayCheckpoint { }; typedef enum ReplayCheckpoint ReplayCheckpoint; +typedef struct ReplayNetState ReplayNetState; + extern ReplayMode replay_mode; /* Replay process control functions */ @@ -137,4 +139,14 @@ void replay_char_read_all_save_error(int res); /*! Writes character read_all execution result into the replay log. */ void replay_char_read_all_save_buf(uint8_t *buf, int offset); +/* Network */ + +/*! Registers replay network filter attached to some backend. */ +ReplayNetState *replay_register_net(NetFilterState *nfs); +/*! Unregisters replay network filter. */ +void replay_unregister_net(ReplayNetState *rns); +/*! Called to write network packet to the replay log. */ +void replay_net_packet_event(ReplayNetState *rns, unsigned flags, + const struct iovec *iov, int iovcnt); + #endif diff --git a/iohandler.c b/iohandler.c index f2fc8a9bd6..eb625d93dd 100644 --- a/iohandler.c +++ b/iohandler.c @@ -63,7 +63,7 @@ void qemu_set_fd_handler(int fd, { iohandler_init(); aio_set_fd_handler(iohandler_ctx, fd, false, - fd_read, fd_write, opaque); + fd_read, fd_write, NULL, opaque); } /* reaping of zombies. right now we're not passing the status to diff --git a/iothread.c b/iothread.c index bd70344811..7bedde87e9 100644 --- a/iothread.c +++ b/iothread.c @@ -98,6 +98,18 @@ static void iothread_complete(UserCreatable *obj, Error **errp) return; } + aio_context_set_poll_params(iothread->ctx, + iothread->poll_max_ns, + iothread->poll_grow, + iothread->poll_shrink, + &local_error); + if (local_error) { + error_propagate(errp, local_error); + aio_context_unref(iothread->ctx); + iothread->ctx = NULL; + return; + } + qemu_mutex_init(&iothread->init_done_lock); qemu_cond_init(&iothread->init_done_cond); @@ -120,10 +132,82 @@ static void iothread_complete(UserCreatable *obj, Error **errp) qemu_mutex_unlock(&iothread->init_done_lock); } +typedef struct { + const char *name; + ptrdiff_t offset; /* field's byte offset in IOThread struct */ +} PollParamInfo; + +static PollParamInfo poll_max_ns_info = { + "poll-max-ns", offsetof(IOThread, poll_max_ns), +}; +static PollParamInfo poll_grow_info = { + "poll-grow", offsetof(IOThread, poll_grow), +}; +static PollParamInfo poll_shrink_info = { + "poll-shrink", offsetof(IOThread, poll_shrink), +}; + +static void iothread_get_poll_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + IOThread *iothread = IOTHREAD(obj); + PollParamInfo *info = opaque; + int64_t *field = (void *)iothread + info->offset; + + visit_type_int64(v, name, field, errp); +} + +static void iothread_set_poll_param(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp) +{ + IOThread *iothread = IOTHREAD(obj); + PollParamInfo *info = opaque; + int64_t *field = (void *)iothread + info->offset; + Error *local_err = NULL; + int64_t value; + + visit_type_int64(v, name, &value, &local_err); + if (local_err) { + goto out; + } + + if (value < 0) { + error_setg(&local_err, "%s value must be in range [0, %"PRId64"]", + info->name, INT64_MAX); + goto out; + } + + *field = value; + + if (iothread->ctx) { + aio_context_set_poll_params(iothread->ctx, + iothread->poll_max_ns, + iothread->poll_grow, + iothread->poll_shrink, + &local_err); + } + +out: + error_propagate(errp, local_err); +} + static void iothread_class_init(ObjectClass *klass, void *class_data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); ucc->complete = iothread_complete; + + object_class_property_add(klass, "poll-max-ns", "int", + iothread_get_poll_param, + iothread_set_poll_param, + NULL, &poll_max_ns_info, &error_abort); + object_class_property_add(klass, "poll-grow", "int", + iothread_get_poll_param, + iothread_set_poll_param, + NULL, &poll_grow_info, &error_abort); + object_class_property_add(klass, "poll-shrink", "int", + iothread_get_poll_param, + iothread_set_poll_param, + NULL, &poll_shrink_info, &error_abort); } static const TypeInfo iothread_info = { diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h index 541268c946..2fb7859465 100644 --- a/linux-headers/asm-arm/kvm.h +++ b/linux-headers/asm-arm/kvm.h @@ -84,6 +84,13 @@ struct kvm_regs { #define KVM_VGIC_V2_DIST_SIZE 0x1000 #define KVM_VGIC_V2_CPU_SIZE 0x2000 +/* Supported VGICv3 address types */ +#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 +#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 + +#define KVM_VGIC_V3_DIST_SIZE SZ_64K +#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) + #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ #define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */ diff --git a/linux-headers/asm-x86/unistd_32.h b/linux-headers/asm-x86/unistd_32.h index abeaf40d37..d45ea28e15 100644 --- a/linux-headers/asm-x86/unistd_32.h +++ b/linux-headers/asm-x86/unistd_32.h @@ -377,5 +377,8 @@ #define __NR_copy_file_range 377 #define __NR_preadv2 378 #define __NR_pwritev2 379 +#define __NR_pkey_mprotect 380 +#define __NR_pkey_alloc 381 +#define __NR_pkey_free 382 #endif /* _ASM_X86_UNISTD_32_H */ diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h index 73c3d1f66a..e22db9171e 100644 --- a/linux-headers/asm-x86/unistd_64.h +++ b/linux-headers/asm-x86/unistd_64.h @@ -330,5 +330,8 @@ #define __NR_copy_file_range 326 #define __NR_preadv2 327 #define __NR_pwritev2 328 +#define __NR_pkey_mprotect 329 +#define __NR_pkey_alloc 330 +#define __NR_pkey_free 331 #endif /* _ASM_X86_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h index e5aea761f8..84e58b202d 100644 --- a/linux-headers/asm-x86/unistd_x32.h +++ b/linux-headers/asm-x86/unistd_x32.h @@ -283,6 +283,9 @@ #define __NR_membarrier (__X32_SYSCALL_BIT + 324) #define __NR_mlock2 (__X32_SYSCALL_BIT + 325) #define __NR_copy_file_range (__X32_SYSCALL_BIT + 326) +#define __NR_pkey_mprotect (__X32_SYSCALL_BIT + 329) +#define __NR_pkey_alloc (__X32_SYSCALL_BIT + 330) +#define __NR_pkey_free (__X32_SYSCALL_BIT + 331) #define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512) #define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513) #define __NR_ioctl (__X32_SYSCALL_BIT + 514) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 4806e069e7..bb0ed71223 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -972,12 +972,19 @@ struct kvm_irqfd { __u8 pad[16]; }; +/* For KVM_CAP_ADJUST_CLOCK */ + +/* Do not use 1, KVM_CHECK_EXTENSION returned it before we had flags. */ +#define KVM_CLOCK_TSC_STABLE 2 + struct kvm_clock_data { __u64 clock; __u32 flags; __u32 pad[9]; }; +/* For KVM_CAP_SW_TLB */ + #define KVM_MMU_FSL_BOOKE_NOHV 0 #define KVM_MMU_FSL_BOOKE_HV 1 diff --git a/linux-user/main.c b/linux-user/main.c index 75b199f274..c1d5eb4d6f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2864,6 +2864,13 @@ void cpu_loop(CPUM68KState *env) info._sifields._sigfault._addr = env->pc; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; + case EXCP_DIV0: + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_INTDIV; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; case EXCP_TRAP0: { abi_long ret; diff --git a/memory_ldst.inc.c b/memory_ldst.inc.c new file mode 100644 index 0000000000..5dbff9cef8 --- /dev/null +++ b/memory_ldst.inc.c @@ -0,0 +1,709 @@ +/* + * Physical memory access templates + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2015 Linaro, Inc. + * Copyright (c) 2016 Red Hat, Inc. + * + * 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/>. + */ + +/* warning: addr must be aligned */ +static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result, + enum device_endian endian) +{ + uint8_t *ptr; + uint64_t val; + MemoryRegion *mr; + hwaddr l = 4; + hwaddr addr1; + MemTxResult r; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, false); + if (l < 4 || !IS_DIRECT(mr, false)) { + release_lock |= prepare_mmio_access(mr); + + /* I/O case */ + r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs); +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap32(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap32(val); + } +#endif + } else { + /* RAM case */ + ptr = MAP_RAM(mr, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = ldl_le_p(ptr); + break; + case DEVICE_BIG_ENDIAN: + val = ldl_be_p(ptr); + break; + default: + val = ldl_p(ptr); + break; + } + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); + return val; +} + +uint32_t glue(address_space_ldl, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_NATIVE_ENDIAN); +} + +uint32_t glue(address_space_ldl_le, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_LITTLE_ENDIAN); +} + +uint32_t glue(address_space_ldl_be, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_BIG_ENDIAN); +} + +uint32_t glue(ldl_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_ldl, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint32_t glue(ldl_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_ldl_le, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint32_t glue(ldl_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_ldl_be, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +/* warning: addr must be aligned */ +static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result, + enum device_endian endian) +{ + uint8_t *ptr; + uint64_t val; + MemoryRegion *mr; + hwaddr l = 8; + hwaddr addr1; + MemTxResult r; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, false); + if (l < 8 || !IS_DIRECT(mr, false)) { + release_lock |= prepare_mmio_access(mr); + + /* I/O case */ + r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs); +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap64(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap64(val); + } +#endif + } else { + /* RAM case */ + ptr = MAP_RAM(mr, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = ldq_le_p(ptr); + break; + case DEVICE_BIG_ENDIAN: + val = ldq_be_p(ptr); + break; + default: + val = ldq_p(ptr); + break; + } + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); + return val; +} + +uint64_t glue(address_space_ldq, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_NATIVE_ENDIAN); +} + +uint64_t glue(address_space_ldq_le, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_LITTLE_ENDIAN); +} + +uint64_t glue(address_space_ldq_be, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_BIG_ENDIAN); +} + +uint64_t glue(ldq_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_ldq, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint64_t glue(ldq_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_ldq_le, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint64_t glue(ldq_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_ldq_be, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + uint8_t *ptr; + uint64_t val; + MemoryRegion *mr; + hwaddr l = 1; + hwaddr addr1; + MemTxResult r; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, false); + if (!IS_DIRECT(mr, false)) { + release_lock |= prepare_mmio_access(mr); + + /* I/O case */ + r = memory_region_dispatch_read(mr, addr1, &val, 1, attrs); + } else { + /* RAM case */ + ptr = MAP_RAM(mr, addr1); + val = ldub_p(ptr); + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); + return val; +} + +uint32_t glue(ldub_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_ldub, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +/* warning: addr must be aligned */ +static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result, + enum device_endian endian) +{ + uint8_t *ptr; + uint64_t val; + MemoryRegion *mr; + hwaddr l = 2; + hwaddr addr1; + MemTxResult r; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, false); + if (l < 2 || !IS_DIRECT(mr, false)) { + release_lock |= prepare_mmio_access(mr); + + /* I/O case */ + r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs); +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap16(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap16(val); + } +#endif + } else { + /* RAM case */ + ptr = MAP_RAM(mr, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + val = lduw_le_p(ptr); + break; + case DEVICE_BIG_ENDIAN: + val = lduw_be_p(ptr); + break; + default: + val = lduw_p(ptr); + break; + } + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); + return val; +} + +uint32_t glue(address_space_lduw, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_NATIVE_ENDIAN); +} + +uint32_t glue(address_space_lduw_le, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_LITTLE_ENDIAN); +} + +uint32_t glue(address_space_lduw_be, SUFFIX)(ARG1_DECL, + hwaddr addr, MemTxAttrs attrs, MemTxResult *result) +{ + return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result, + DEVICE_BIG_ENDIAN); +} + +uint32_t glue(lduw_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_lduw, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint32_t glue(lduw_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_lduw_le, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +uint32_t glue(lduw_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr) +{ + return glue(address_space_lduw_be, SUFFIX)(ARG1, addr, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +/* warning: addr must be aligned. The ram page is not masked as dirty + and the code inside is not invalidated. It is useful if the dirty + bits are used to track modified PTEs */ +void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) +{ + uint8_t *ptr; + MemoryRegion *mr; + hwaddr l = 4; + hwaddr addr1; + MemTxResult r; + uint8_t dirty_log_mask; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); + if (l < 4 || !IS_DIRECT(mr, true)) { + release_lock |= prepare_mmio_access(mr); + + r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); + } else { + ptr = MAP_RAM(mr, addr1); + stl_p(ptr, val); + + dirty_log_mask = memory_region_get_dirty_log_mask(mr); + dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE); + cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr, + 4, dirty_log_mask); + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); +} + +void glue(stl_phys_notdirty, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +{ + glue(address_space_stl_notdirty, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +/* warning: addr must be aligned */ +static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, + MemTxResult *result, enum device_endian endian) +{ + uint8_t *ptr; + MemoryRegion *mr; + hwaddr l = 4; + hwaddr addr1; + MemTxResult r; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); + if (l < 4 || !IS_DIRECT(mr, true)) { + release_lock |= prepare_mmio_access(mr); + +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap32(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap32(val); + } +#endif + r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); + } else { + /* RAM case */ + ptr = MAP_RAM(mr, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + stl_le_p(ptr, val); + break; + case DEVICE_BIG_ENDIAN: + stl_be_p(ptr, val); + break; + default: + stl_p(ptr, val); + break; + } + INVALIDATE(mr, addr1, 4); + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); +} + +void glue(address_space_stl, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs, + result, DEVICE_NATIVE_ENDIAN); +} + +void glue(address_space_stl_le, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs, + result, DEVICE_LITTLE_ENDIAN); +} + +void glue(address_space_stl_be, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs, + result, DEVICE_BIG_ENDIAN); +} + +void glue(stl_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +{ + glue(address_space_stl, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +void glue(stl_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +{ + glue(address_space_stl_le, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +void glue(stl_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +{ + glue(address_space_stl_be, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +void glue(address_space_stb, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) +{ + uint8_t *ptr; + MemoryRegion *mr; + hwaddr l = 1; + hwaddr addr1; + MemTxResult r; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); + if (!IS_DIRECT(mr, true)) { + release_lock |= prepare_mmio_access(mr); + r = memory_region_dispatch_write(mr, addr1, val, 1, attrs); + } else { + /* RAM case */ + ptr = MAP_RAM(mr, addr1); + stb_p(ptr, val); + INVALIDATE(mr, addr1, 1); + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); +} + +void glue(stb_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +{ + glue(address_space_stb, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +/* warning: addr must be aligned */ +static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, + MemTxResult *result, enum device_endian endian) +{ + uint8_t *ptr; + MemoryRegion *mr; + hwaddr l = 2; + hwaddr addr1; + MemTxResult r; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); + if (l < 2 || !IS_DIRECT(mr, true)) { + release_lock |= prepare_mmio_access(mr); + +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap16(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap16(val); + } +#endif + r = memory_region_dispatch_write(mr, addr1, val, 2, attrs); + } else { + /* RAM case */ + ptr = MAP_RAM(mr, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + stw_le_p(ptr, val); + break; + case DEVICE_BIG_ENDIAN: + stw_be_p(ptr, val); + break; + default: + stw_p(ptr, val); + break; + } + INVALIDATE(mr, addr1, 2); + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); +} + +void glue(address_space_stw, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result, + DEVICE_NATIVE_ENDIAN); +} + +void glue(address_space_stw_le, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result, + DEVICE_LITTLE_ENDIAN); +} + +void glue(address_space_stw_be, SUFFIX)(ARG1_DECL, + hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result, + DEVICE_BIG_ENDIAN); +} + +void glue(stw_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +{ + glue(address_space_stw, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +void glue(stw_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +{ + glue(address_space_stw_le, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +void glue(stw_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val) +{ + glue(address_space_stw_be, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, + hwaddr addr, uint64_t val, MemTxAttrs attrs, + MemTxResult *result, enum device_endian endian) +{ + uint8_t *ptr; + MemoryRegion *mr; + hwaddr l = 8; + hwaddr addr1; + MemTxResult r; + bool release_lock = false; + + RCU_READ_LOCK(); + mr = TRANSLATE(addr, &addr1, &l, true); + if (l < 8 || !IS_DIRECT(mr, true)) { + release_lock |= prepare_mmio_access(mr); + +#if defined(TARGET_WORDS_BIGENDIAN) + if (endian == DEVICE_LITTLE_ENDIAN) { + val = bswap64(val); + } +#else + if (endian == DEVICE_BIG_ENDIAN) { + val = bswap64(val); + } +#endif + r = memory_region_dispatch_write(mr, addr1, val, 8, attrs); + } else { + /* RAM case */ + ptr = MAP_RAM(mr, addr1); + switch (endian) { + case DEVICE_LITTLE_ENDIAN: + stq_le_p(ptr, val); + break; + case DEVICE_BIG_ENDIAN: + stq_be_p(ptr, val); + break; + default: + stq_p(ptr, val); + break; + } + INVALIDATE(mr, addr1, 8); + r = MEMTX_OK; + } + if (result) { + *result = r; + } + if (release_lock) { + qemu_mutex_unlock_iothread(); + } + RCU_READ_UNLOCK(); +} + +void glue(address_space_stq, SUFFIX)(ARG1_DECL, + hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result, + DEVICE_NATIVE_ENDIAN); +} + +void glue(address_space_stq_le, SUFFIX)(ARG1_DECL, + hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result, + DEVICE_LITTLE_ENDIAN); +} + +void glue(address_space_stq_be, SUFFIX)(ARG1_DECL, + hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result) +{ + glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result, + DEVICE_BIG_ENDIAN); +} + +void glue(stq_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) +{ + glue(address_space_stq, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +void glue(stq_le_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) +{ + glue(address_space_stq_le, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +void glue(stq_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) +{ + glue(address_space_stq_be, SUFFIX)(ARG1, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + +#undef ARG1_DECL +#undef ARG1 +#undef SUFFIX +#undef TRANSLATE +#undef IS_DIRECT +#undef MAP_RAM +#undef INVALIDATE +#undef RCU_READ_LOCK +#undef RCU_READ_UNLOCK diff --git a/nbd/server.c b/nbd/server.c index 5b76261666..efe5cb82c9 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1366,19 +1366,18 @@ static void nbd_restart_write(void *opaque) static void nbd_set_handlers(NBDClient *client) { if (client->exp && client->exp->ctx) { - aio_set_fd_handler(client->exp->ctx, client->sioc->fd, - true, + aio_set_fd_handler(client->exp->ctx, client->sioc->fd, true, client->can_read ? nbd_read : NULL, client->send_coroutine ? nbd_restart_write : NULL, - client); + NULL, client); } } static void nbd_unset_handlers(NBDClient *client) { if (client->exp && client->exp->ctx) { - aio_set_fd_handler(client->exp->ctx, client->sioc->fd, - true, NULL, NULL, NULL); + aio_set_fd_handler(client->exp->ctx, client->sioc->fd, true, NULL, + NULL, NULL, NULL); } } diff --git a/net/Makefile.objs b/net/Makefile.objs index 2a80df5fa7..2e2fd43014 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -19,3 +19,4 @@ common-obj-y += filter-mirror.o common-obj-y += colo-compare.o common-obj-y += colo.o common-obj-y += filter-rewriter.o +common-obj-y += filter-replay.o diff --git a/net/filter-replay.c b/net/filter-replay.c new file mode 100644 index 0000000000..cff65f86e5 --- /dev/null +++ b/net/filter-replay.c @@ -0,0 +1,92 @@ +/* + * filter-replay.c + * + * Copyright (c) 2010-2016 Institute for System Programming + * of the Russian Academy of Sciences. + * + * 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 "clients.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "qemu/error-report.h" +#include "qemu/iov.h" +#include "qemu/log.h" +#include "qemu/timer.h" +#include "qapi/visitor.h" +#include "net/filter.h" +#include "sysemu/replay.h" + +#define TYPE_FILTER_REPLAY "filter-replay" + +#define FILTER_REPLAY(obj) \ + OBJECT_CHECK(NetFilterReplayState, (obj), TYPE_FILTER_REPLAY) + +struct NetFilterReplayState { + NetFilterState nfs; + ReplayNetState *rns; +}; +typedef struct NetFilterReplayState NetFilterReplayState; + +static ssize_t filter_replay_receive_iov(NetFilterState *nf, + NetClientState *sndr, + unsigned flags, + const struct iovec *iov, + int iovcnt, NetPacketSent *sent_cb) +{ + NetFilterReplayState *nfrs = FILTER_REPLAY(nf); + switch (replay_mode) { + case REPLAY_MODE_RECORD: + if (nf->netdev == sndr) { + replay_net_packet_event(nfrs->rns, flags, iov, iovcnt); + return iov_size(iov, iovcnt); + } + return 0; + case REPLAY_MODE_PLAY: + /* Drop all packets in replay mode. + Packets from the log will be injected by the replay module. */ + return iov_size(iov, iovcnt); + default: + /* Pass all the packets. */ + return 0; + } +} + +static void filter_replay_instance_init(Object *obj) +{ + NetFilterReplayState *nfrs = FILTER_REPLAY(obj); + nfrs->rns = replay_register_net(&nfrs->nfs); +} + +static void filter_replay_instance_finalize(Object *obj) +{ + NetFilterReplayState *nfrs = FILTER_REPLAY(obj); + replay_unregister_net(nfrs->rns); +} + +static void filter_replay_class_init(ObjectClass *oc, void *data) +{ + NetFilterClass *nfc = NETFILTER_CLASS(oc); + + nfc->receive_iov = filter_replay_receive_iov; +} + +static const TypeInfo filter_replay_info = { + .name = TYPE_FILTER_REPLAY, + .parent = TYPE_NETFILTER, + .class_init = filter_replay_class_init, + .instance_init = filter_replay_instance_init, + .instance_finalize = filter_replay_instance_finalize, + .instance_size = sizeof(NetFilterReplayState), +}; + +static void filter_replay_register_types(void) +{ + type_register_static(&filter_replay_info); +} + +type_init(filter_replay_register_types); diff --git a/qapi/crypto.json b/qapi/crypto.json index 15d296e3c1..f4fd93b813 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -63,6 +63,7 @@ # @aes-192: AES with 192 bit / 24 byte keys # @aes-256: AES with 256 bit / 32 byte keys # @des-rfb: RFB specific variant of single DES. Do not use except in VNC. +# @3des: 3DES(EDE) with 192 bit / 24 byte keys (since 2.9) # @cast5-128: Cast5 with 128 bit / 16 byte keys # @serpent-128: Serpent with 128 bit / 16 byte keys # @serpent-192: Serpent with 192 bit / 24 byte keys @@ -75,7 +76,7 @@ { 'enum': 'QCryptoCipherAlgorithm', 'prefix': 'QCRYPTO_CIPHER_ALG', 'data': ['aes-128', 'aes-192', 'aes-256', - 'des-rfb', + 'des-rfb', '3des', 'cast5-128', 'serpent-128', 'serpent-192', 'serpent-256', 'twofish-128', 'twofish-192', 'twofish-256']} diff --git a/qemu-img.c b/qemu-img.c index 6949b73ca5..5df66fe661 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3559,20 +3559,23 @@ static void bench_cb(void *opaque, int ret) } while (b->n > b->in_flight && b->in_flight < b->nrreq) { + int64_t offset = b->offset; + /* blk_aio_* might look for completed I/Os and kick bench_cb + * again, so make sure this operation is counted by in_flight + * and b->offset is ready for the next submission. + */ + b->in_flight++; + b->offset += b->step; + b->offset %= b->image_size; if (b->write) { - acb = blk_aio_pwritev(b->blk, b->offset, b->qiov, 0, - bench_cb, b); + acb = blk_aio_pwritev(b->blk, offset, b->qiov, 0, bench_cb, b); } else { - acb = blk_aio_preadv(b->blk, b->offset, b->qiov, 0, - bench_cb, b); + acb = blk_aio_preadv(b->blk, offset, b->qiov, 0, bench_cb, b); } if (!acb) { error_report("Failed to issue request"); exit(EXIT_FAILURE); } - b->in_flight++; - b->offset += b->step; - b->offset %= b->image_size; } } diff --git a/qemu-timer.c b/qemu-timer.c index 9299cdc5fb..ff620ecff7 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -174,7 +174,7 @@ void qemu_clock_enable(QEMUClockType type, bool enabled) bool timerlist_has_timers(QEMUTimerList *timer_list) { - return !!timer_list->active_timers; + return !!atomic_read(&timer_list->active_timers); } bool qemu_clock_has_timers(QEMUClockType type) @@ -187,6 +187,10 @@ bool timerlist_expired(QEMUTimerList *timer_list) { int64_t expire_time; + if (!atomic_read(&timer_list->active_timers)) { + return false; + } + qemu_mutex_lock(&timer_list->active_timers_lock); if (!timer_list->active_timers) { qemu_mutex_unlock(&timer_list->active_timers_lock); @@ -214,6 +218,10 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) int64_t delta; int64_t expire_time; + if (!atomic_read(&timer_list->active_timers)) { + return -1; + } + if (!timer_list->clock->enabled) { return -1; } @@ -363,7 +371,7 @@ static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts) if (!t) break; if (t == ts) { - *pt = t->next; + atomic_set(pt, t->next); break; } pt = &t->next; @@ -386,7 +394,7 @@ static bool timer_mod_ns_locked(QEMUTimerList *timer_list, } ts->expire_time = MAX(expire_time, 0); ts->next = *pt; - *pt = ts; + atomic_set(pt, ts); return pt == &timer_list->active_timers; } @@ -481,8 +489,12 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) QEMUTimerCB *cb; void *opaque; + if (!atomic_read(&timer_list->active_timers)) { + return false; + } + qemu_event_reset(&timer_list->timers_done_ev); - if (!timer_list->clock->enabled || !timer_list->active_timers) { + if (!timer_list->clock->enabled) { goto out; } diff --git a/replay/Makefile.objs b/replay/Makefile.objs index c8ad3ebb89..b2afd4030a 100644 --- a/replay/Makefile.objs +++ b/replay/Makefile.objs @@ -5,3 +5,4 @@ common-obj-y += replay-time.o common-obj-y += replay-input.o common-obj-y += replay-char.o common-obj-y += replay-snapshot.o +common-obj-y += replay-net.o diff --git a/replay/replay-events.c b/replay/replay-events.c index c513913671..94a6dcccfc 100644 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -54,6 +54,9 @@ static void replay_run_event(Event *event) case REPLAY_ASYNC_EVENT_BLOCK: aio_bh_call(event->opaque); break; + case REPLAY_ASYNC_EVENT_NET: + replay_event_net_run(event->opaque); + break; default: error_report("Replay: invalid async event ID (%d) in the queue", event->event_kind); @@ -189,6 +192,9 @@ static void replay_save_event(Event *event, int checkpoint) case REPLAY_ASYNC_EVENT_BLOCK: replay_put_qword(event->id); break; + case REPLAY_ASYNC_EVENT_NET: + replay_event_net_save(event->opaque); + break; default: error_report("Unknown ID %" PRId64 " of replay event", event->id); exit(1); @@ -252,6 +258,11 @@ static Event *replay_read_event(int checkpoint) read_id = replay_get_qword(); } break; + case REPLAY_ASYNC_EVENT_NET: + event = g_malloc0(sizeof(Event)); + event->event_kind = read_event_kind; + event->opaque = replay_event_net_load(); + return event; default: error_report("Unknown ID %d of replay event", read_event_kind); exit(1); diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 9117e442d0..c26d0795f2 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -50,6 +50,7 @@ enum ReplayAsyncEventKind { REPLAY_ASYNC_EVENT_INPUT_SYNC, REPLAY_ASYNC_EVENT_CHAR_READ, REPLAY_ASYNC_EVENT_BLOCK, + REPLAY_ASYNC_EVENT_NET, REPLAY_ASYNC_COUNT }; @@ -161,6 +162,15 @@ void replay_event_char_read_save(void *opaque); /*! Reads char event read from the file. */ void *replay_event_char_read_load(void); +/* Network devices */ + +/*! Called to run network event. */ +void replay_event_net_run(void *opaque); +/*! Writes network event to the file. */ +void replay_event_net_save(void *opaque); +/*! Reads network from the file. */ +void *replay_event_net_load(void); + /* VMState-related functions */ /* Registers replay VMState. diff --git a/replay/replay-net.c b/replay/replay-net.c new file mode 100644 index 0000000000..80b7054156 --- /dev/null +++ b/replay/replay-net.c @@ -0,0 +1,102 @@ +/* + * replay-net.c + * + * Copyright (c) 2010-2016 Institute for System Programming + * of the Russian Academy of Sciences. + * + * 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 "sysemu/replay.h" +#include "replay-internal.h" +#include "sysemu/sysemu.h" +#include "net/net.h" +#include "net/filter.h" +#include "qemu/iov.h" + +struct ReplayNetState { + NetFilterState *nfs; + int id; +}; + +typedef struct NetEvent { + uint8_t id; + uint32_t flags; + uint8_t *data; + size_t size; +} NetEvent; + +static NetFilterState **network_filters; +static int network_filters_count; + +ReplayNetState *replay_register_net(NetFilterState *nfs) +{ + ReplayNetState *rns = g_new0(ReplayNetState, 1); + rns->nfs = nfs; + rns->id = network_filters_count++; + network_filters = g_realloc(network_filters, + network_filters_count + * sizeof(*network_filters)); + network_filters[network_filters_count - 1] = nfs; + return rns; +} + +void replay_unregister_net(ReplayNetState *rns) +{ + network_filters[rns->id] = NULL; + g_free(rns); +} + +void replay_net_packet_event(ReplayNetState *rns, unsigned flags, + const struct iovec *iov, int iovcnt) +{ + NetEvent *event = g_new(NetEvent, 1); + event->flags = flags; + event->data = g_malloc(iov_size(iov, iovcnt)); + event->size = iov_size(iov, iovcnt); + event->id = rns->id; + iov_to_buf(iov, iovcnt, 0, event->data, event->size); + + replay_add_event(REPLAY_ASYNC_EVENT_NET, event, NULL, 0); +} + +void replay_event_net_run(void *opaque) +{ + NetEvent *event = opaque; + struct iovec iov = { + .iov_base = (void *)event->data, + .iov_len = event->size + }; + + assert(event->id < network_filters_count); + + qemu_netfilter_pass_to_next(network_filters[event->id]->netdev, + event->flags, &iov, 1, network_filters[event->id]); + + g_free(event->data); + g_free(event); +} + +void replay_event_net_save(void *opaque) +{ + NetEvent *event = opaque; + + replay_put_byte(event->id); + replay_put_dword(event->flags); + replay_put_array(event->data, event->size); +} + +void *replay_event_net_load(void) +{ + NetEvent *event = g_new(NetEvent, 1); + + event->id = replay_get_byte(); + event->flags = replay_get_dword(); + replay_get_array_alloc(&event->data, &event->size); + + return event; +} diff --git a/replay/replay.c b/replay/replay.c index c797aeae8a..7f27cf17b0 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -21,7 +21,7 @@ /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe02004 +#define REPLAY_VERSION 0xe02005 /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) diff --git a/rules.mak b/rules.mak index f4839d2c38..ce9e7e6ffe 100644 --- a/rules.mak +++ b/rules.mak @@ -7,6 +7,10 @@ MAKEFLAGS += -rR # Files with this suffixes are final, don't try to generate them # using implicit rules +%/trace-events: +%.hx: +%.py: +%.objs: %.d: %.h: %.c: @@ -192,15 +196,15 @@ clean: clean-timestamp # save-vars # Usage: $(call save-vars, vars) # Save each variable $v in $vars as save-vars-$v, save their object's -# variables, then clear $v. +# variables, then clear $v. saved-vars-$v contains the variables that +# where saved for the objects, in order to speedup load-vars. define save-vars $(foreach v,$1, $(eval save-vars-$v := $(value $v)) - $(foreach o,$($v), - $(foreach k,cflags libs objs, - $(if $($o-$k), - $(eval save-vars-$o-$k := $($o-$k)) - $(eval $o-$k := )))) + $(eval saved-vars-$v := $(foreach o,$($v), \ + $(if $($o-cflags), $o-cflags $(eval save-vars-$o-cflags := $($o-cflags))$(eval $o-cflags := )) \ + $(if $($o-libs), $o-libs $(eval save-vars-$o-libs := $($o-libs))$(eval $o-libs := )) \ + $(if $($o-objs), $o-objs $(eval save-vars-$o-objs := $($o-objs))$(eval $o-objs := )))) $(eval $v := )) endef @@ -213,12 +217,10 @@ define load-vars $(eval $2-new-value := $(value $2)) $(foreach v,$1, $(eval $v := $(value save-vars-$v)) - $(foreach o,$($v), - $(foreach k,cflags libs objs, - $(if $(save-vars-$o-$k), - $(eval $o-$k := $(save-vars-$o-$k)) - $(eval save-vars-$o-$k := )))) - $(eval save-vars-$v := )) + $(foreach o,$(saved-vars-$v), + $(eval $o := $(save-vars-$o)) $(eval save-vars-$o := )) + $(eval save-vars-$v := ) + $(eval saved-vars-$v := )) $(eval $2 := $(value $2) $($2-new-value)) endef diff --git a/scripts/analyze-inclusions b/scripts/analyze-inclusions index a8108d9b88..14806e18c6 100644 --- a/scripts/analyze-inclusions +++ b/scripts/analyze-inclusions @@ -48,7 +48,7 @@ grep_include() { echo Found $(find . -name "*.d" | wc -l) object files echo $(grep_include -F 'include/qemu-common.h') files include qemu-common.h echo $(grep_include -F 'hw/hw.h') files include hw/hw.h -echo $(grep_include 'target-[a-z0-9]*/cpu\.h') files include cpu.h +echo $(grep_include 'target/[a-z0-9]*/cpu\.h') files include cpu.h echo $(grep_include -F 'qapi-types.h') files include qapi-types.h echo $(grep_include -F 'trace/generated-tracers.h') files include generated-tracers.h echo $(grep_include -F 'qapi/error.h') files include qapi/error.h @@ -95,8 +95,8 @@ analyze -include ../include/qemu/osdep.h ../include/hw/hw.h echo trace/generated-tracers.h: analyze -include ../include/qemu/osdep.h trace/generated-tracers.h -echo target-i386/cpu.h: -analyze -DNEED_CPU_H -I../target-i386 -Ii386-softmmu -include ../include/qemu/osdep.h ../target-i386/cpu.h +echo target/i386/cpu.h: +analyze -DNEED_CPU_H -I../target/i386 -Ii386-softmmu -include ../include/qemu/osdep.h ../target/i386/cpu.h echo hw/hw.h + NEED_CPU_H: -analyze -DNEED_CPU_H -I../target-i386 -Ii386-softmmu -include ../include/qemu/osdep.h ../include/hw/hw.h +analyze -DNEED_CPU_H -I../target/i386 -Ii386-softmmu -include ../include/qemu/osdep.h ../include/hw/hw.h diff --git a/slirp/dhcpv6.c b/slirp/dhcpv6.c index 02c51c7756..d266611e85 100644 --- a/slirp/dhcpv6.c +++ b/slirp/dhcpv6.c @@ -168,7 +168,7 @@ static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7], sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14], sa[15], slirp->bootp_filename); - slen = min(slen, smaxlen); + slen = MIN(slen, smaxlen); *resp++ = slen >> 8; /* option-len high byte */ *resp++ = slen; /* option-len low byte */ resp += slen; diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c index 6d18e28985..298a48dd25 100644 --- a/slirp/ip6_icmp.c +++ b/slirp/ip6_icmp.c @@ -95,7 +95,7 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code) #endif rip->ip_nh = IPPROTO_ICMPV6; - const int error_data_len = min(m->m_len, + const int error_data_len = MIN(m->m_len, IF_MTU - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN)); rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len); t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl); diff --git a/slirp/slirp.c b/slirp/slirp.c index 6e2b4e5a90..60539de7a3 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -774,7 +774,7 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error) static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) { struct slirp_arphdr *ah = (struct slirp_arphdr *)(pkt + ETH_HLEN); - uint8_t arp_reply[max(ETH_HLEN + sizeof(struct slirp_arphdr), 64)]; + uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)]; struct ethhdr *reh = (struct ethhdr *)arp_reply; struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN); int ar_op; diff --git a/slirp/slirp.h b/slirp/slirp.h index a1f3139134..3877f667f0 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -292,9 +292,4 @@ int tcp_emu(struct socket *, struct mbuf *); int tcp_ctl(struct socket *); struct tcpcb *tcp_drop(struct tcpcb *tp, int err); -#ifndef _WIN32 -#define min(x,y) ((x) < (y) ? (x) : (y)) -#define max(x,y) ((x) > (y) ? (x) : (y)) -#endif - #endif diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index c5063a918d..edb98f06f3 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -596,7 +596,7 @@ findso: win = sbspace(&so->so_rcv); if (win < 0) win = 0; - tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); + tp->rcv_wnd = MAX(win, (int)(tp->rcv_adv - tp->rcv_nxt)); } switch (tp->t_state) { @@ -1065,8 +1065,8 @@ trimthenstep6: else if (++tp->t_dupacks == TCPREXMTTHRESH) { tcp_seq onxt = tp->snd_nxt; u_int win = - min(tp->snd_wnd, tp->snd_cwnd) / 2 / - tp->t_maxseg; + MIN(tp->snd_wnd, tp->snd_cwnd) / + 2 / tp->t_maxseg; if (win < 2) win = 2; @@ -1138,7 +1138,7 @@ trimthenstep6: if (cw > tp->snd_ssthresh) incr = incr * incr / cw; - tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale); + tp->snd_cwnd = MIN(cw + incr, TCP_MAXWIN << tp->snd_scale); } if (acked > so->so_snd.sb_cc) { tp->snd_wnd -= so->so_snd.sb_cc; @@ -1586,11 +1586,11 @@ tcp_mss(struct tcpcb *tp, u_int offer) switch (so->so_ffamily) { case AF_INET: - mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + mss = MIN(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip); break; case AF_INET6: - mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + mss = MIN(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip6); break; default: @@ -1598,8 +1598,8 @@ tcp_mss(struct tcpcb *tp, u_int offer) } if (offer) - mss = min(mss, offer); - mss = max(mss, 32); + mss = MIN(mss, offer); + mss = MAX(mss, 32); if (mss < tp->t_maxseg || offer != 0) tp->t_maxseg = mss; diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c index 819db27348..90b5c376f7 100644 --- a/slirp/tcp_output.c +++ b/slirp/tcp_output.c @@ -88,7 +88,7 @@ tcp_output(struct tcpcb *tp) again: sendalot = 0; off = tp->snd_nxt - tp->snd_una; - win = min(tp->snd_wnd, tp->snd_cwnd); + win = MIN(tp->snd_wnd, tp->snd_cwnd); flags = tcp_outflags[tp->t_state]; @@ -127,7 +127,7 @@ again: } } - len = min(so->so_snd.sb_cc, win) - off; + len = MIN(so->so_snd.sb_cc, win) - off; if (len < 0) { /* @@ -193,7 +193,7 @@ again: * taking into account that we are limited by * TCP_MAXWIN << tp->rcv_scale. */ - long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - + long adv = MIN(win, (long)TCP_MAXWIN << tp->rcv_scale) - (tp->rcv_adv - tp->rcv_nxt); if (adv >= (long) (2 * tp->t_maxseg)) diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c index f9060c7bf8..52ef5f9100 100644 --- a/slirp/tcp_timer.c +++ b/slirp/tcp_timer.c @@ -233,7 +233,7 @@ tcp_timers(register struct tcpcb *tp, int timer) * to go below this.) */ { - u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; + u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; if (win < 2) win = 2; tp->snd_cwnd = tp->t_maxseg; diff --git a/slirp/tcpip.h b/slirp/tcpip.h index 7bdb971c5d..07dbf2c432 100644 --- a/slirp/tcpip.h +++ b/slirp/tcpip.h @@ -85,7 +85,7 @@ struct tcpiphdr { /* This is the difference between the size of a tcpiphdr structure, and the * size of actual ip+tcp headers, rounded up since we need to align data. */ #define TCPIPHDR_DELTA\ - (max(0,\ + (MAX(0,\ (sizeof(struct tcpiphdr)\ - sizeof(struct ip) - sizeof(struct tcphdr) + 3) & ~3)) diff --git a/slirp/tftp.c b/slirp/tftp.c index c1859066cc..50e714807d 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -72,6 +72,7 @@ static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas, memset(spt, 0, sizeof(*spt)); spt->client_addr = *srcsas; spt->fd = -1; + spt->block_size = 512; spt->client_port = tp->udp.uh_sport; spt->slirp = slirp; @@ -115,7 +116,7 @@ static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr, } if (len) { - lseek(spt->fd, block_nr * 512, SEEK_SET); + lseek(spt->fd, block_nr * spt->block_size, SEEK_SET); bytes_read = read(spt->fd, buf, len); } @@ -189,7 +190,8 @@ static int tftp_send_oack(struct tftp_session *spt, values[i]) + 1; } - m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct udphdr); + m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + n + - sizeof(struct udphdr); tftp_udp_output(spt, m, recv_tp); return 0; @@ -214,7 +216,7 @@ static void tftp_send_error(struct tftp_session *spt, tp->x.tp_error.tp_error_code = htons(errorcode); pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg); - m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) + m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 + strlen(msg) - sizeof(struct udphdr); tftp_udp_output(spt, m, recv_tp); @@ -240,7 +242,8 @@ static void tftp_send_next_block(struct tftp_session *spt, tp->tp_op = htons(TFTP_DATA); tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff); - nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512); + nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, + spt->block_size); if (nobytes < 0) { m_free(m); @@ -252,10 +255,11 @@ static void tftp_send_next_block(struct tftp_session *spt, return; } - m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct udphdr); + m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes) + - sizeof(struct udphdr); tftp_udp_output(spt, m, recv_tp); - if (nobytes == 512) { + if (nobytes == spt->block_size) { tftp_session_update(spt); } else { @@ -385,13 +389,11 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas, } else if (strcasecmp(key, "blksize") == 0) { int blksize = atoi(value); - /* If blksize option is bigger than what we will - * emit, accept the option with our packet size. - * Otherwise, simply do as we didn't see the option. - */ - if (blksize >= 512) { + /* Accept blksize up to our maximum size */ + if (blksize > 0) { + spt->block_size = MIN(blksize, TFTP_BLOCKSIZE_MAX); option_name[nb_options] = "blksize"; - option_value[nb_options] = 512; + option_value[nb_options] = spt->block_size; nb_options++; } } diff --git a/slirp/tftp.h b/slirp/tftp.h index 2cd276dec6..a4c4a64e64 100644 --- a/slirp/tftp.h +++ b/slirp/tftp.h @@ -15,6 +15,7 @@ #define TFTP_OACK 6 #define TFTP_FILENAME_MAX 512 +#define TFTP_BLOCKSIZE_MAX 1428 struct tftp_t { struct udphdr udp; @@ -22,13 +23,13 @@ struct tftp_t { union { struct { uint16_t tp_block_nr; - uint8_t tp_buf[512]; + uint8_t tp_buf[TFTP_BLOCKSIZE_MAX]; } tp_data; struct { uint16_t tp_error_code; - uint8_t tp_msg[512]; + uint8_t tp_msg[TFTP_BLOCKSIZE_MAX]; } tp_error; - char tp_buf[512 + 2]; + char tp_buf[TFTP_BLOCKSIZE_MAX + 2]; } x; } __attribute__((packed)); @@ -36,6 +37,7 @@ struct tftp_session { Slirp *slirp; char *filename; int fd; + uint16_t block_size; struct sockaddr_storage client_addr; uint16_t client_port; diff --git a/stubs/set-fd-handler.c b/stubs/set-fd-handler.c index 06a5da48f1..acbe65c1da 100644 --- a/stubs/set-fd-handler.c +++ b/stubs/set-fd-handler.c @@ -15,6 +15,7 @@ void aio_set_fd_handler(AioContext *ctx, bool is_external, IOHandler *io_read, IOHandler *io_write, + AioPollFn *io_poll, void *opaque) { abort(); diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c deleted file mode 100644 index 48e02e4062..0000000000 --- a/target-m68k/op_helper.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * M68K helper routines - * - * Copyright (c) 2007 CodeSourcery - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" -#include "exec/semihost.h" - -#if defined(CONFIG_USER_ONLY) - -void m68k_cpu_do_interrupt(CPUState *cs) -{ - cs->exception_index = -1; -} - -static inline void do_interrupt_m68k_hardirq(CPUM68KState *env) -{ -} - -#else - -/* Try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) -{ - int ret; - - ret = m68k_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); - if (unlikely(ret)) { - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); - } -} - -static void do_rte(CPUM68KState *env) -{ - uint32_t sp; - uint32_t fmt; - - sp = env->aregs[7]; - fmt = cpu_ldl_kernel(env, sp); - env->pc = cpu_ldl_kernel(env, sp + 4); - sp |= (fmt >> 28) & 3; - env->aregs[7] = sp + 8; - - helper_set_sr(env, fmt); -} - -static void do_interrupt_all(CPUM68KState *env, int is_hw) -{ - CPUState *cs = CPU(m68k_env_get_cpu(env)); - uint32_t sp; - uint32_t fmt; - uint32_t retaddr; - uint32_t vector; - - fmt = 0; - retaddr = env->pc; - - if (!is_hw) { - switch (cs->exception_index) { - case EXCP_RTE: - /* Return from an exception. */ - do_rte(env); - return; - case EXCP_HALT_INSN: - if (semihosting_enabled() - && (env->sr & SR_S) != 0 - && (env->pc & 3) == 0 - && cpu_lduw_code(env, env->pc - 4) == 0x4e71 - && cpu_ldl_code(env, env->pc) == 0x4e7bf000) { - env->pc += 4; - do_m68k_semihosting(env, env->dregs[0]); - return; - } - cs->halted = 1; - cs->exception_index = EXCP_HLT; - cpu_loop_exit(cs); - return; - } - if (cs->exception_index >= EXCP_TRAP0 - && cs->exception_index <= EXCP_TRAP15) { - /* Move the PC after the trap instruction. */ - retaddr += 2; - } - } - - vector = cs->exception_index << 2; - - fmt |= 0x40000000; - fmt |= vector << 16; - fmt |= env->sr; - fmt |= cpu_m68k_get_ccr(env); - - env->sr |= SR_S; - if (is_hw) { - env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); - env->sr &= ~SR_M; - } - m68k_switch_sp(env); - sp = env->aregs[7]; - fmt |= (sp & 3) << 28; - - /* ??? This could cause MMU faults. */ - sp &= ~3; - sp -= 4; - cpu_stl_kernel(env, sp, retaddr); - sp -= 4; - cpu_stl_kernel(env, sp, fmt); - env->aregs[7] = sp; - /* Jump to vector. */ - env->pc = cpu_ldl_kernel(env, env->vbr + vector); -} - -void m68k_cpu_do_interrupt(CPUState *cs) -{ - M68kCPU *cpu = M68K_CPU(cs); - CPUM68KState *env = &cpu->env; - - do_interrupt_all(env, 0); -} - -static inline void do_interrupt_m68k_hardirq(CPUM68KState *env) -{ - do_interrupt_all(env, 1); -} -#endif - -bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - M68kCPU *cpu = M68K_CPU(cs); - CPUM68KState *env = &cpu->env; - - if (interrupt_request & CPU_INTERRUPT_HARD - && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) { - /* Real hardware gets the interrupt vector via an IACK cycle - at this point. Current emulated hardware doesn't rely on - this, so we provide/save the vector when the interrupt is - first signalled. */ - cs->exception_index = env->pending_vector; - do_interrupt_m68k_hardirq(env); - return true; - } - return false; -} - -static void raise_exception(CPUM68KState *env, int tt) -{ - CPUState *cs = CPU(m68k_env_get_cpu(env)); - - cs->exception_index = tt; - cpu_loop_exit(cs); -} - -void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) -{ - raise_exception(env, tt); -} - -void HELPER(divu)(CPUM68KState *env, uint32_t word) -{ - uint32_t num; - uint32_t den; - uint32_t quot; - uint32_t rem; - - num = env->div1; - den = env->div2; - /* ??? This needs to make sure the throwing location is accurate. */ - if (den == 0) { - raise_exception(env, EXCP_DIV0); - } - quot = num / den; - rem = num % den; - - env->cc_v = (word && quot > 0xffff ? -1 : 0); - env->cc_z = quot; - env->cc_n = quot; - env->cc_c = 0; - - env->div1 = quot; - env->div2 = rem; -} - -void HELPER(divs)(CPUM68KState *env, uint32_t word) -{ - int32_t num; - int32_t den; - int32_t quot; - int32_t rem; - - num = env->div1; - den = env->div2; - if (den == 0) { - raise_exception(env, EXCP_DIV0); - } - quot = num / den; - rem = num % den; - - env->cc_v = (word && quot != (int16_t)quot ? -1 : 0); - env->cc_z = quot; - env->cc_n = quot; - env->cc_c = 0; - - env->div1 = quot; - env->div2 = rem; -} diff --git a/target-alpha/Makefile.objs b/target/alpha/Makefile.objs index 63664629f6..63664629f6 100644 --- a/target-alpha/Makefile.objs +++ b/target/alpha/Makefile.objs diff --git a/target-alpha/STATUS b/target/alpha/STATUS index 6c9744569e..6c9744569e 100644 --- a/target-alpha/STATUS +++ b/target/alpha/STATUS diff --git a/target-alpha/cpu-qom.h b/target/alpha/cpu-qom.h index bae4945344..bae4945344 100644 --- a/target-alpha/cpu-qom.h +++ b/target/alpha/cpu-qom.h diff --git a/target-alpha/cpu.c b/target/alpha/cpu.c index 30d77ce71c..30d77ce71c 100644 --- a/target-alpha/cpu.c +++ b/target/alpha/cpu.c diff --git a/target-alpha/cpu.h b/target/alpha/cpu.h index b08d1601d1..b08d1601d1 100644 --- a/target-alpha/cpu.h +++ b/target/alpha/cpu.h diff --git a/target-alpha/fpu_helper.c b/target/alpha/fpu_helper.c index 9645978aaa..9645978aaa 100644 --- a/target-alpha/fpu_helper.c +++ b/target/alpha/fpu_helper.c diff --git a/target-alpha/gdbstub.c b/target/alpha/gdbstub.c index d64bcccfa0..d64bcccfa0 100644 --- a/target-alpha/gdbstub.c +++ b/target/alpha/gdbstub.c diff --git a/target-alpha/helper.c b/target/alpha/helper.c index a5c308859b..a5c308859b 100644 --- a/target-alpha/helper.c +++ b/target/alpha/helper.c diff --git a/target-alpha/helper.h b/target/alpha/helper.h index 004221df8c..004221df8c 100644 --- a/target-alpha/helper.h +++ b/target/alpha/helper.h diff --git a/target-alpha/int_helper.c b/target/alpha/int_helper.c index 19bebfe742..19bebfe742 100644 --- a/target-alpha/int_helper.c +++ b/target/alpha/int_helper.c diff --git a/target-alpha/machine.c b/target/alpha/machine.c index b99a123a39..b99a123a39 100644 --- a/target-alpha/machine.c +++ b/target/alpha/machine.c diff --git a/target-alpha/mem_helper.c b/target/alpha/mem_helper.c index 78a7d45590..78a7d45590 100644 --- a/target-alpha/mem_helper.c +++ b/target/alpha/mem_helper.c diff --git a/target-alpha/sys_helper.c b/target/alpha/sys_helper.c index bec1e178be..bec1e178be 100644 --- a/target-alpha/sys_helper.c +++ b/target/alpha/sys_helper.c diff --git a/target-alpha/translate.c b/target/alpha/translate.c index 114927b751..114927b751 100644 --- a/target-alpha/translate.c +++ b/target/alpha/translate.c diff --git a/target-alpha/vax_helper.c b/target/alpha/vax_helper.c index 2b0c178274..2b0c178274 100644 --- a/target-alpha/vax_helper.c +++ b/target/alpha/vax_helper.c diff --git a/target-arm/Makefile.objs b/target/arm/Makefile.objs index 847fb52ee0..847fb52ee0 100644 --- a/target-arm/Makefile.objs +++ b/target/arm/Makefile.objs diff --git a/target-arm/arch_dump.c b/target/arm/arch_dump.c index 1a9861f69b..1a9861f69b 100644 --- a/target-arm/arch_dump.c +++ b/target/arm/arch_dump.c diff --git a/target-arm/arm-powerctl.c b/target/arm/arm-powerctl.c index fbb7a15daa..fbb7a15daa 100644 --- a/target-arm/arm-powerctl.c +++ b/target/arm/arm-powerctl.c diff --git a/target-arm/arm-powerctl.h b/target/arm/arm-powerctl.h index 98ee04989b..98ee04989b 100644 --- a/target-arm/arm-powerctl.h +++ b/target/arm/arm-powerctl.h diff --git a/target-arm/arm-semi.c b/target/arm/arm-semi.c index 7cac8734c7..7cac8734c7 100644 --- a/target-arm/arm-semi.c +++ b/target/arm/arm-semi.c diff --git a/target-arm/arm_ldst.h b/target/arm/arm_ldst.h index a76d89f62c..a76d89f62c 100644 --- a/target-arm/arm_ldst.h +++ b/target/arm/arm_ldst.h diff --git a/target-arm/cpu-qom.h b/target/arm/cpu-qom.h index a42495bac9..a42495bac9 100644 --- a/target-arm/cpu-qom.h +++ b/target/arm/cpu-qom.h diff --git a/target-arm/cpu.c b/target/arm/cpu.c index 99f0dbebb9..f5cb30af6c 100644 --- a/target-arm/cpu.c +++ b/target/arm/cpu.c @@ -597,6 +597,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } else { set_feature(env, ARM_FEATURE_V6); } + + /* Always define VBAR for V7 CPUs even if it doesn't exist in + * non-EL3 configs. This is needed by some legacy boards. + */ + set_feature(env, ARM_FEATURE_VBAR); } if (arm_feature(env, ARM_FEATURE_V6K)) { set_feature(env, ARM_FEATURE_V6); @@ -721,6 +726,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) } } + if (arm_feature(env, ARM_FEATURE_EL3)) { + set_feature(env, ARM_FEATURE_VBAR); + } + register_cp_regs_for_features(cpu); arm_cpu_register_gdb_regs_for_features(cpu); @@ -1055,7 +1064,7 @@ static void cortex_a8_initfn(Object *obj) cpu->midr = 0x410fc080; cpu->reset_fpsid = 0x410330c0; cpu->mvfr0 = 0x11110222; - cpu->mvfr1 = 0x00011100; + cpu->mvfr1 = 0x00011111; cpu->ctr = 0x82048004; cpu->reset_sctlr = 0x00c50078; cpu->id_pfr0 = 0x1031; diff --git a/target-arm/cpu.h b/target/arm/cpu.h index ca5c849ed6..ab119e62ab 100644 --- a/target-arm/cpu.h +++ b/target/arm/cpu.h @@ -1125,6 +1125,7 @@ enum arm_features { ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */ ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */ ARM_FEATURE_PMU, /* has PMU support */ + ARM_FEATURE_VBAR, /* has cp15 VBAR */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/cpu64.c b/target/arm/cpu64.c index 549cb1ee93..549cb1ee93 100644 --- a/target-arm/cpu64.c +++ b/target/arm/cpu64.c diff --git a/target-arm/crypto_helper.c b/target/arm/crypto_helper.c index 3b6df3f41a..3b6df3f41a 100644 --- a/target-arm/crypto_helper.c +++ b/target/arm/crypto_helper.c diff --git a/target-arm/gdbstub.c b/target/arm/gdbstub.c index 04c1208d03..04c1208d03 100644 --- a/target-arm/gdbstub.c +++ b/target/arm/gdbstub.c diff --git a/target-arm/gdbstub64.c b/target/arm/gdbstub64.c index 49bc3fc521..49bc3fc521 100644 --- a/target-arm/gdbstub64.c +++ b/target/arm/gdbstub64.c diff --git a/target-arm/helper-a64.c b/target/arm/helper-a64.c index 98b97df461..98b97df461 100644 --- a/target-arm/helper-a64.c +++ b/target/arm/helper-a64.c diff --git a/target-arm/helper-a64.h b/target/arm/helper-a64.h index dd32000e63..dd32000e63 100644 --- a/target-arm/helper-a64.h +++ b/target/arm/helper-a64.h diff --git a/target-arm/helper.c b/target/arm/helper.c index b5b65caadf..8dcabbf576 100644 --- a/target-arm/helper.c +++ b/target/arm/helper.c @@ -1252,12 +1252,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tpm, .type = ARM_CP_ALIAS, .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .writefn = pmintenclr_write }, - { .name = "VBAR", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .writefn = vbar_write, - .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), - offsetof(CPUARMState, cp15.vbar_ns) }, - .resetvalue = 0 }, { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_RAW }, @@ -5094,6 +5088,19 @@ void register_cp_regs_for_features(ARMCPU *cpu) } } + if (arm_feature(env, ARM_FEATURE_VBAR)) { + ARMCPRegInfo vbar_cp_reginfo[] = { + { .name = "VBAR", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .writefn = vbar_write, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), + offsetof(CPUARMState, cp15.vbar_ns) }, + .resetvalue = 0 }, + REGINFO_SENTINEL + }; + define_arm_cp_regs(cpu, vbar_cp_reginfo); + } + /* Generic registers whose values depend on the implementation */ { ARMCPRegInfo sctlr = { diff --git a/target-arm/helper.h b/target/arm/helper.h index 84aa637629..84aa637629 100644 --- a/target-arm/helper.h +++ b/target/arm/helper.h diff --git a/target-arm/internals.h b/target/arm/internals.h index 3edccd2529..3cae5ff3b5 100644 --- a/target-arm/internals.h +++ b/target/arm/internals.h @@ -18,7 +18,7 @@ * <http://www.gnu.org/licenses/gpl-2.0.html> * * This header defines functions, types, etc which need to be shared - * between different source files within target-arm/ but which are + * between different source files within target/arm/ but which are * private to it and not required by the rest of QEMU. */ diff --git a/target-arm/iwmmxt_helper.c b/target/arm/iwmmxt_helper.c index 7d87e1a0a8..7d87e1a0a8 100644 --- a/target-arm/iwmmxt_helper.c +++ b/target/arm/iwmmxt_helper.c diff --git a/target-arm/kvm-consts.h b/target/arm/kvm-consts.h index a2c9518592..a2c9518592 100644 --- a/target-arm/kvm-consts.h +++ b/target/arm/kvm-consts.h diff --git a/target-arm/kvm-stub.c b/target/arm/kvm-stub.c index b2c66df532..b2c66df532 100644 --- a/target-arm/kvm-stub.c +++ b/target/arm/kvm-stub.c diff --git a/target-arm/kvm.c b/target/arm/kvm.c index c00b94e42a..c00b94e42a 100644 --- a/target-arm/kvm.c +++ b/target/arm/kvm.c diff --git a/target-arm/kvm32.c b/target/arm/kvm32.c index 069da0c5fd..069da0c5fd 100644 --- a/target-arm/kvm32.c +++ b/target/arm/kvm32.c diff --git a/target-arm/kvm64.c b/target/arm/kvm64.c index 61111091ad..61111091ad 100644 --- a/target-arm/kvm64.c +++ b/target/arm/kvm64.c diff --git a/target-arm/kvm_arm.h b/target/arm/kvm_arm.h index 633d08828a..633d08828a 100644 --- a/target-arm/kvm_arm.h +++ b/target/arm/kvm_arm.h diff --git a/target-arm/machine.c b/target/arm/machine.c index d90943b6db..d90943b6db 100644 --- a/target-arm/machine.c +++ b/target/arm/machine.c diff --git a/target-arm/monitor.c b/target/arm/monitor.c index 299cb80ae7..299cb80ae7 100644 --- a/target-arm/monitor.c +++ b/target/arm/monitor.c diff --git a/target-arm/neon_helper.c b/target/arm/neon_helper.c index ebdf7c9b10..ebdf7c9b10 100644 --- a/target-arm/neon_helper.c +++ b/target/arm/neon_helper.c diff --git a/target-arm/op_addsub.h b/target/arm/op_addsub.h index ca4a1893c3..ca4a1893c3 100644 --- a/target-arm/op_addsub.h +++ b/target/arm/op_addsub.h diff --git a/target-arm/op_helper.c b/target/arm/op_helper.c index cd94216591..ba796d898e 100644 --- a/target-arm/op_helper.c +++ b/target/arm/op_helper.c @@ -17,6 +17,7 @@ * 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 "exec/helper-proto.h" #include "internals.h" @@ -972,6 +973,9 @@ void HELPER(exception_return)(CPUARMState *env) } else { env->regs[15] = env->elr_el[cur_el] & ~0x3; } + qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to " + "AArch32 EL%d PC 0x%" PRIx32 "\n", + cur_el, new_el, env->regs[15]); } else { env->aarch64 = 1; pstate_write(env, spsr); @@ -980,6 +984,9 @@ void HELPER(exception_return)(CPUARMState *env) } aarch64_restore_sp(env, new_el); env->pc = env->elr_el[cur_el]; + qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to " + "AArch64 EL%d PC 0x%" PRIx64 "\n", + cur_el, new_el, env->pc); } arm_call_el_change_hook(arm_env_get_cpu(env)); @@ -1002,6 +1009,8 @@ illegal_return: if (!arm_singlestep_active(env)) { env->pstate &= ~PSTATE_SS; } + qemu_log_mask(LOG_GUEST_ERROR, "Illegal exception return at EL%d: " + "resuming execution at 0x%" PRIx64 "\n", cur_el, env->pc); } /* Return true if the linked breakpoint entry lbn passes its checks */ diff --git a/target-arm/psci.c b/target/arm/psci.c index 14316eb0ae..14316eb0ae 100644 --- a/target-arm/psci.c +++ b/target/arm/psci.c diff --git a/target-arm/trace-events b/target/arm/trace-events index 9f726bdae3..e21c84fc6f 100644 --- a/target-arm/trace-events +++ b/target/arm/trace-events @@ -1,6 +1,6 @@ # See docs/tracing.txt for syntax documentation. -# target-arm/helper.c +# target/arm/helper.c arm_gt_recalc(int timer, int irqstate, uint64_t nexttick) "gt recalc: timer %d irqstate %d next tick %" PRIx64 arm_gt_recalc_disabled(int timer) "gt recalc: timer %d irqstate 0 timer disabled" arm_gt_cval_write(int timer, uint64_t value) "gt_cval_write: timer %d value %" PRIx64 diff --git a/target-arm/translate-a64.c b/target/arm/translate-a64.c index 6dc27a6115..f673d939e1 100644 --- a/target-arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -527,7 +527,7 @@ static inline void assert_fp_access_checked(DisasContext *s) static inline int vec_reg_offset(DisasContext *s, int regno, int element, TCGMemOp size) { - int offs = offsetof(CPUARMState, vfp.regs[regno * 2]); + int offs = 0; #ifdef HOST_WORDS_BIGENDIAN /* This is complicated slightly because vfp.regs[2n] is * still the low half and vfp.regs[2n+1] the high half @@ -540,6 +540,7 @@ static inline int vec_reg_offset(DisasContext *s, int regno, #else offs += element * (1 << size); #endif + offs += offsetof(CPUARMState, vfp.regs[regno * 2]); assert_fp_access_checked(s); return offs; } @@ -2829,9 +2830,9 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) } else { /* Load/store one element per register */ if (is_load) { - do_vec_ld(s, rt, index, tcg_addr, s->be_data + scale); + do_vec_ld(s, rt, index, tcg_addr, scale); } else { - do_vec_st(s, rt, index, tcg_addr, s->be_data + scale); + do_vec_st(s, rt, index, tcg_addr, scale); } } tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes); diff --git a/target-arm/translate.c b/target/arm/translate.c index 0ad9070b45..0ad9070b45 100644 --- a/target-arm/translate.c +++ b/target/arm/translate.c diff --git a/target-arm/translate.h b/target/arm/translate.h index 285e96f087..285e96f087 100644 --- a/target-arm/translate.h +++ b/target/arm/translate.h diff --git a/target-cris/Makefile.objs b/target/cris/Makefile.objs index 7779227fc4..7779227fc4 100644 --- a/target-cris/Makefile.objs +++ b/target/cris/Makefile.objs diff --git a/target-cris/cpu-qom.h b/target/cris/cpu-qom.h index 7556e9f97e..7556e9f97e 100644 --- a/target-cris/cpu-qom.h +++ b/target/cris/cpu-qom.h diff --git a/target-cris/cpu.c b/target/cris/cpu.c index 2e9ab9700e..2e9ab9700e 100644 --- a/target-cris/cpu.c +++ b/target/cris/cpu.c diff --git a/target-cris/cpu.h b/target/cris/cpu.h index 43d5f9d1da..43d5f9d1da 100644 --- a/target-cris/cpu.h +++ b/target/cris/cpu.h diff --git a/target-cris/crisv10-decode.h b/target/cris/crisv10-decode.h index bdb4b6d318..bdb4b6d318 100644 --- a/target-cris/crisv10-decode.h +++ b/target/cris/crisv10-decode.h diff --git a/target-cris/crisv32-decode.h b/target/cris/crisv32-decode.h index cdc2f8cbe6..cdc2f8cbe6 100644 --- a/target-cris/crisv32-decode.h +++ b/target/cris/crisv32-decode.h diff --git a/target-cris/gdbstub.c b/target/cris/gdbstub.c index 3a72ee2a98..3a72ee2a98 100644 --- a/target-cris/gdbstub.c +++ b/target/cris/gdbstub.c diff --git a/target-cris/helper.c b/target/cris/helper.c index af78cca8b9..af78cca8b9 100644 --- a/target-cris/helper.c +++ b/target/cris/helper.c diff --git a/target-cris/helper.h b/target/cris/helper.h index ff3595641a..ff3595641a 100644 --- a/target-cris/helper.h +++ b/target/cris/helper.h diff --git a/target-cris/machine.c b/target/cris/machine.c index 6b797e8c1d..6b797e8c1d 100644 --- a/target-cris/machine.c +++ b/target/cris/machine.c diff --git a/target-cris/mmu.c b/target/cris/mmu.c index b8db908823..b8db908823 100644 --- a/target-cris/mmu.c +++ b/target/cris/mmu.c diff --git a/target-cris/mmu.h b/target/cris/mmu.h index 8e249e812b..8e249e812b 100644 --- a/target-cris/mmu.h +++ b/target/cris/mmu.h diff --git a/target-cris/op_helper.c b/target/cris/op_helper.c index 504303913c..504303913c 100644 --- a/target-cris/op_helper.c +++ b/target/cris/op_helper.c diff --git a/target-cris/opcode-cris.h b/target/cris/opcode-cris.h index e7ebb98cd0..e7ebb98cd0 100644 --- a/target-cris/opcode-cris.h +++ b/target/cris/opcode-cris.h diff --git a/target-cris/translate.c b/target/cris/translate.c index b91042743f..b91042743f 100644 --- a/target-cris/translate.c +++ b/target/cris/translate.c diff --git a/target-cris/translate_v10.c b/target/cris/translate_v10.c index 4a0b485d8e..4a0b485d8e 100644 --- a/target-cris/translate_v10.c +++ b/target/cris/translate_v10.c diff --git a/target-i386/Makefile.objs b/target/i386/Makefile.objs index b223d7932b..b223d7932b 100644 --- a/target-i386/Makefile.objs +++ b/target/i386/Makefile.objs diff --git a/target-i386/TODO b/target/i386/TODO index a8d69cf87f..a8d69cf87f 100644 --- a/target-i386/TODO +++ b/target/i386/TODO diff --git a/target-i386/arch_dump.c b/target/i386/arch_dump.c index 5a2e4be5d0..5a2e4be5d0 100644 --- a/target-i386/arch_dump.c +++ b/target/i386/arch_dump.c diff --git a/target-i386/arch_memory_mapping.c b/target/i386/arch_memory_mapping.c index 88f341e1bb..826aee597b 100644 --- a/target-i386/arch_memory_mapping.c +++ b/target/i386/arch_memory_mapping.c @@ -220,7 +220,8 @@ static void walk_pdpe(MemoryMappingList *list, AddressSpace *as, /* IA-32e Paging */ static void walk_pml4e(MemoryMappingList *list, AddressSpace *as, - hwaddr pml4e_start_addr, int32_t a20_mask) + hwaddr pml4e_start_addr, int32_t a20_mask, + target_ulong start_line_addr) { hwaddr pml4e_addr, pdpe_start_addr; uint64_t pml4e; @@ -236,11 +237,34 @@ static void walk_pml4e(MemoryMappingList *list, AddressSpace *as, continue; } - line_addr = ((i & 0x1ffULL) << 39) | (0xffffULL << 48); + line_addr = start_line_addr | ((i & 0x1ffULL) << 39); pdpe_start_addr = (pml4e & PLM4_ADDR_MASK) & a20_mask; walk_pdpe(list, as, pdpe_start_addr, a20_mask, line_addr); } } + +static void walk_pml5e(MemoryMappingList *list, AddressSpace *as, + hwaddr pml5e_start_addr, int32_t a20_mask) +{ + hwaddr pml5e_addr, pml4e_start_addr; + uint64_t pml5e; + target_ulong line_addr; + int i; + + for (i = 0; i < 512; i++) { + pml5e_addr = (pml5e_start_addr + i * 8) & a20_mask; + pml5e = address_space_ldq(as, pml5e_addr, MEMTXATTRS_UNSPECIFIED, + NULL); + if (!(pml5e & PG_PRESENT_MASK)) { + /* not present */ + continue; + } + + line_addr = (0x7fULL << 57) | ((i & 0x1ffULL) << 48); + pml4e_start_addr = (pml5e & PLM4_ADDR_MASK) & a20_mask; + walk_pml4e(list, as, pml4e_start_addr, a20_mask, line_addr); + } +} #endif void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, @@ -257,10 +281,18 @@ void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, if (env->cr[4] & CR4_PAE_MASK) { #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - hwaddr pml4e_addr; + if (env->cr[4] & CR4_LA57_MASK) { + hwaddr pml5e_addr; + + pml5e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask; + walk_pml5e(list, cs->as, pml5e_addr, env->a20_mask); + } else { + hwaddr pml4e_addr; - pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask; - walk_pml4e(list, cs->as, pml4e_addr, env->a20_mask); + pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask; + walk_pml4e(list, cs->as, pml4e_addr, env->a20_mask, + 0xffffULL << 48); + } } else #endif { diff --git a/target-i386/bpt_helper.c b/target/i386/bpt_helper.c index 6fd7fe04a0..b3efdc77ec 100644 --- a/target-i386/bpt_helper.c +++ b/target/i386/bpt_helper.c @@ -244,6 +244,13 @@ void helper_single_step(CPUX86State *env) raise_exception(env, EXCP01_DB); } +void helper_rechecking_single_step(CPUX86State *env) +{ + if ((env->eflags & TF_MASK) != 0) { + helper_single_step(env); + } +} + void helper_set_dr(CPUX86State *env, int reg, target_ulong t0) { #ifndef CONFIG_USER_ONLY diff --git a/target-i386/cc_helper.c b/target/i386/cc_helper.c index 83af223c9f..83af223c9f 100644 --- a/target-i386/cc_helper.c +++ b/target/i386/cc_helper.c diff --git a/target-i386/cc_helper_template.h b/target/i386/cc_helper_template.h index 607311f195..607311f195 100644 --- a/target-i386/cc_helper_template.h +++ b/target/i386/cc_helper_template.h diff --git a/target-i386/cpu-qom.h b/target/i386/cpu-qom.h index 7c9a07ae65..7c9a07ae65 100644 --- a/target-i386/cpu-qom.h +++ b/target/i386/cpu-qom.h diff --git a/target-i386/cpu.c b/target/i386/cpu.c index de1f30eeda..b0640f1e38 100644 --- a/target-i386/cpu.c +++ b/target/i386/cpu.c @@ -238,7 +238,8 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, CPUID_7_0_EBX_RDSEED */ -#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE) +#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE | \ + CPUID_7_0_ECX_LA57) #define TCG_7_0_EDX_FEATURES 0 #define TCG_APM_FEATURES 0 #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT @@ -422,7 +423,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "avx512f", "avx512dq", "rdseed", "adx", "smap", "avx512ifma", "pcommit", "clflushopt", "clwb", NULL, "avx512pf", "avx512er", - "avx512cd", NULL, "avx512bw", "avx512vl", + "avx512cd", "sha-ni", "avx512bw", "avx512vl", }, .cpuid_eax = 7, .cpuid_needs_ecx = true, .cpuid_ecx = 0, @@ -435,7 +436,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "ospke", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, + "la57", NULL, NULL, NULL, NULL, NULL, "rdpid", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -2742,10 +2743,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0x80000008: /* virtual & phys address size in low 2 bytes. */ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { - /* 64 bit processor, 48 bits virtual, configurable - * physical bits. - */ - *eax = 0x00003000 + cpu->phys_bits; + /* 64 bit processor */ + *eax = cpu->phys_bits; /* configurable physical bits */ + if (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_LA57) { + *eax |= 0x00003900; /* 57 bits virtual */ + } else { + *eax |= 0x00003000; /* 48 bits virtual */ + } } else { *eax = cpu->phys_bits; } diff --git a/target-i386/cpu.h b/target/i386/cpu.h index c605724022..a7f2f6099d 100644 --- a/target-i386/cpu.h +++ b/target/i386/cpu.h @@ -224,6 +224,7 @@ #define CR4_OSFXSR_SHIFT 9 #define CR4_OSFXSR_MASK (1U << CR4_OSFXSR_SHIFT) #define CR4_OSXMMEXCPT_MASK (1U << 10) +#define CR4_LA57_MASK (1U << 12) #define CR4_VMXE_MASK (1U << 13) #define CR4_SMXE_MASK (1U << 14) #define CR4_FSGSBASE_MASK (1U << 16) @@ -621,6 +622,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EBX_AVX512PF (1U << 26) /* AVX-512 Prefetch */ #define CPUID_7_0_EBX_AVX512ER (1U << 27) /* AVX-512 Exponential and Reciprocal */ #define CPUID_7_0_EBX_AVX512CD (1U << 28) /* AVX-512 Conflict Detection */ +#define CPUID_7_0_EBX_SHA_NI (1U << 29) /* SHA1/SHA256 Instruction Extensions */ #define CPUID_7_0_EBX_AVX512BW (1U << 30) /* AVX-512 Byte and Word Instructions */ #define CPUID_7_0_EBX_AVX512VL (1U << 31) /* AVX-512 Vector Length Extensions */ @@ -628,6 +630,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_ECX_UMIP (1U << 2) #define CPUID_7_0_ECX_PKU (1U << 3) #define CPUID_7_0_ECX_OSPKE (1U << 4) +#define CPUID_7_0_ECX_LA57 (1U << 16) #define CPUID_7_0_ECX_RDPID (1U << 22) #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */ diff --git a/target-i386/excp_helper.c b/target/i386/excp_helper.c index f0dc4996c1..f0dc4996c1 100644 --- a/target-i386/excp_helper.c +++ b/target/i386/excp_helper.c diff --git a/target-i386/fpu_helper.c b/target/i386/fpu_helper.c index 2049a8c01d..2049a8c01d 100644 --- a/target-i386/fpu_helper.c +++ b/target/i386/fpu_helper.c diff --git a/target-i386/gdbstub.c b/target/i386/gdbstub.c index c494535df1..9b94ab852c 100644 --- a/target-i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -44,10 +44,22 @@ int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + /* N.B. GDB can't deal with changes in registers or sizes in the middle + of a session. So if we're in 32-bit mode on a 64-bit cpu, still act + as if we're on a 64-bit cpu. */ + if (n < CPU_NB_REGS) { - if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { - return gdb_get_reg64(mem_buf, env->regs[gpr_map[n]]); - } else if (n < CPU_NB_REGS32) { + if (TARGET_LONG_BITS == 64) { + if (env->hflags & HF_CS64_MASK) { + return gdb_get_reg64(mem_buf, env->regs[gpr_map[n]]); + } else if (n < CPU_NB_REGS32) { + return gdb_get_reg64(mem_buf, + env->regs[gpr_map[n]] & 0xffffffffUL); + } else { + memset(mem_buf, 0, sizeof(target_ulong)); + return sizeof(target_ulong); + } + } else { return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]); } } else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) { @@ -60,8 +72,7 @@ int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return 10; } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { n -= IDX_XMM_REGS; - if (n < CPU_NB_REGS32 || - (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) { + if (n < CPU_NB_REGS32 || TARGET_LONG_BITS == 64) { stq_p(mem_buf, env->xmm_regs[n].ZMM_Q(0)); stq_p(mem_buf + 8, env->xmm_regs[n].ZMM_Q(1)); return 16; @@ -69,8 +80,12 @@ int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) } else { switch (n) { case IDX_IP_REG: - if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { - return gdb_get_reg64(mem_buf, env->eip); + 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); } @@ -151,9 +166,17 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) CPUX86State *env = &cpu->env; uint32_t tmp; + /* N.B. GDB can't deal with changes in registers or sizes in the middle + of a session. So if we're in 32-bit mode on a 64-bit cpu, still act + as if we're on a 64-bit cpu. */ + if (n < CPU_NB_REGS) { - if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) { - env->regs[gpr_map[n]] = ldtul_p(mem_buf); + if (TARGET_LONG_BITS == 64) { + if (env->hflags & HF_CS64_MASK) { + env->regs[gpr_map[n]] = ldtul_p(mem_buf); + } else if (n < CPU_NB_REGS32) { + env->regs[gpr_map[n]] = ldtul_p(mem_buf) & 0xffffffffUL; + } return sizeof(target_ulong); } else if (n < CPU_NB_REGS32) { n = gpr_map32[n]; @@ -169,8 +192,7 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) return 10; } else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) { n -= IDX_XMM_REGS; - if (n < CPU_NB_REGS32 || - (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) { + if (n < CPU_NB_REGS32 || TARGET_LONG_BITS == 64) { env->xmm_regs[n].ZMM_Q(0) = ldq_p(mem_buf); env->xmm_regs[n].ZMM_Q(1) = ldq_p(mem_buf + 8); return 16; @@ -178,8 +200,12 @@ 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 && env->hflags & HF_CS64_MASK) { - env->eip = ldq_p(mem_buf); + 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; diff --git a/target-i386/helper.c b/target/i386/helper.c index 4ecc0912a4..43e87ddba0 100644 --- a/target-i386/helper.c +++ b/target/i386/helper.c @@ -651,11 +651,11 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) uint32_t hflags; #if defined(DEBUG_MMU) - printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]); + printf("CR4 update: %08x -> %08x\n", (uint32_t)env->cr[4], new_cr4); #endif if ((new_cr4 ^ env->cr[4]) & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK | - CR4_SMEP_MASK | CR4_SMAP_MASK)) { + CR4_SMEP_MASK | CR4_SMAP_MASK | CR4_LA57_MASK)) { tlb_flush(CPU(cpu), 1); } @@ -757,19 +757,41 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { + bool la57 = env->cr[4] & CR4_LA57_MASK; + uint64_t pml5e_addr, pml5e; uint64_t pml4e_addr, pml4e; int32_t sext; /* test virtual address sign extension */ - sext = (int64_t)addr >> 47; + sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47; if (sext != 0 && sext != -1) { env->error_code = 0; cs->exception_index = EXCP0D_GPF; return 1; } - pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & - env->a20_mask; + if (la57) { + pml5e_addr = ((env->cr[3] & ~0xfff) + + (((addr >> 48) & 0x1ff) << 3)) & env->a20_mask; + pml5e = x86_ldq_phys(cs, pml5e_addr); + if (!(pml5e & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pml5e & (rsvd_mask | PG_PSE_MASK)) { + goto do_fault_rsvd; + } + if (!(pml5e & PG_ACCESSED_MASK)) { + pml5e |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); + } + ptep = pml5e ^ PG_NX_MASK; + } else { + pml5e = env->cr[3]; + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; + } + + pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; pml4e = x86_ldq_phys(cs, pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { goto do_fault; @@ -781,7 +803,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, pml4e |= PG_ACCESSED_MASK; x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); } - ptep = pml4e ^ PG_NX_MASK; + ptep &= pml4e ^ PG_NX_MASK; pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; pdpe = x86_ldq_phys(cs, pdpe_addr); @@ -1024,16 +1046,30 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { + bool la57 = env->cr[4] & CR4_LA57_MASK; + uint64_t pml5e_addr, pml5e; uint64_t pml4e_addr, pml4e; int32_t sext; /* test virtual address sign extension */ - sext = (int64_t)addr >> 47; + sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47; if (sext != 0 && sext != -1) { return -1; } - pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & - env->a20_mask; + + if (la57) { + pml5e_addr = ((env->cr[3] & ~0xfff) + + (((addr >> 48) & 0x1ff) << 3)) & env->a20_mask; + pml5e = x86_ldq_phys(cs, pml5e_addr); + if (!(pml5e & PG_PRESENT_MASK)) { + return -1; + } + } else { + pml5e = env->cr[3]; + } + + pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; pml4e = x86_ldq_phys(cs, pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { return -1; diff --git a/target-i386/helper.h b/target/i386/helper.h index 4e859eba9d..bd9b2cf677 100644 --- a/target-i386/helper.h +++ b/target/i386/helper.h @@ -79,6 +79,7 @@ DEF_HELPER_2(cmpxchg16b_unlocked, void, env, tl) DEF_HELPER_2(cmpxchg16b, void, env, tl) #endif DEF_HELPER_1(single_step, void, env) +DEF_HELPER_1(rechecking_single_step, void, env) DEF_HELPER_1(cpuid, void, env) DEF_HELPER_1(rdtsc, void, env) DEF_HELPER_1(rdtscp, void, env) diff --git a/target-i386/hyperv.c b/target/i386/hyperv.c index 39a230f119..39a230f119 100644 --- a/target-i386/hyperv.c +++ b/target/i386/hyperv.c diff --git a/target-i386/hyperv.h b/target/i386/hyperv.h index 0c3b562018..0c3b562018 100644 --- a/target-i386/hyperv.h +++ b/target/i386/hyperv.h diff --git a/target-i386/int_helper.c b/target/i386/int_helper.c index 9e873ac150..9e873ac150 100644 --- a/target-i386/int_helper.c +++ b/target/i386/int_helper.c diff --git a/target-i386/kvm-stub.c b/target/i386/kvm-stub.c index bda4dc2f0c..bda4dc2f0c 100644 --- a/target-i386/kvm-stub.c +++ b/target/i386/kvm-stub.c diff --git a/target-i386/kvm.c b/target/i386/kvm.c index f62264a7a8..10a9cd8f7f 100644 --- a/target-i386/kvm.c +++ b/target/i386/kvm.c @@ -117,6 +117,13 @@ bool kvm_has_smm(void) return kvm_check_extension(kvm_state, KVM_CAP_X86_SMM); } +bool kvm_has_adjust_clock_stable(void) +{ + int ret = kvm_check_extension(kvm_state, KVM_CAP_ADJUST_CLOCK); + + return (ret == KVM_CLOCK_TSC_STABLE); +} + bool kvm_allows_irq0_override(void) { return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing(); diff --git a/target-i386/kvm_i386.h b/target/i386/kvm_i386.h index 76079295b2..bfce427f86 100644 --- a/target-i386/kvm_i386.h +++ b/target/i386/kvm_i386.h @@ -17,6 +17,7 @@ bool kvm_allows_irq0_override(void); bool kvm_has_smm(void); +bool kvm_has_adjust_clock_stable(void); void kvm_synchronize_all_tsc(void); void kvm_arch_reset_vcpu(X86CPU *cs); void kvm_arch_do_init_vcpu(X86CPU *cs); diff --git a/target-i386/machine.c b/target/i386/machine.c index 760f82b6c7..760f82b6c7 100644 --- a/target-i386/machine.c +++ b/target/i386/machine.c diff --git a/target-i386/mem_helper.c b/target/i386/mem_helper.c index 70f67668ab..70f67668ab 100644 --- a/target-i386/mem_helper.c +++ b/target/i386/mem_helper.c diff --git a/target-i386/misc_helper.c b/target/i386/misc_helper.c index 3f666b4b87..3f666b4b87 100644 --- a/target-i386/misc_helper.c +++ b/target/i386/misc_helper.c diff --git a/target-i386/monitor.c b/target/i386/monitor.c index 9a3b4d746e..468aa073bc 100644 --- a/target-i386/monitor.c +++ b/target/i386/monitor.c @@ -30,13 +30,18 @@ #include "hmp.h" -static void print_pte(Monitor *mon, hwaddr addr, - hwaddr pte, - hwaddr mask) +static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr, + hwaddr pte, hwaddr mask) { #ifdef TARGET_X86_64 - if (addr & (1ULL << 47)) { - addr |= -1LL << 48; + if (env->cr[4] & CR4_LA57_MASK) { + if (addr & (1ULL << 56)) { + addr |= -1LL << 57; + } + } else { + if (addr & (1ULL << 47)) { + addr |= -1LL << 48; + } } #endif monitor_printf(mon, TARGET_FMT_plx ": " TARGET_FMT_plx @@ -66,13 +71,13 @@ static void tlb_info_32(Monitor *mon, CPUArchState *env) if (pde & PG_PRESENT_MASK) { if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { /* 4M pages */ - print_pte(mon, (l1 << 22), pde, ~((1 << 21) - 1)); + print_pte(mon, env, (l1 << 22), pde, ~((1 << 21) - 1)); } else { for(l2 = 0; l2 < 1024; l2++) { cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4); pte = le32_to_cpu(pte); if (pte & PG_PRESENT_MASK) { - print_pte(mon, (l1 << 22) + (l2 << 12), + print_pte(mon, env, (l1 << 22) + (l2 << 12), pte & ~PG_PSE_MASK, ~0xfff); } @@ -100,7 +105,7 @@ static void tlb_info_pae32(Monitor *mon, CPUArchState *env) if (pde & PG_PRESENT_MASK) { if (pde & PG_PSE_MASK) { /* 2M pages with PAE, CR4.PSE is ignored */ - print_pte(mon, (l1 << 30 ) + (l2 << 21), pde, + print_pte(mon, env, (l1 << 30) + (l2 << 21), pde, ~((hwaddr)(1 << 20) - 1)); } else { pt_addr = pde & 0x3fffffffff000ULL; @@ -108,7 +113,7 @@ static void tlb_info_pae32(Monitor *mon, CPUArchState *env) cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 8); pte = le64_to_cpu(pte); if (pte & PG_PRESENT_MASK) { - print_pte(mon, (l1 << 30 ) + (l2 << 21) + print_pte(mon, env, (l1 << 30) + (l2 << 21) + (l3 << 12), pte & ~PG_PSE_MASK, ~(hwaddr)0xfff); @@ -122,61 +127,82 @@ static void tlb_info_pae32(Monitor *mon, CPUArchState *env) } #ifdef TARGET_X86_64 -static void tlb_info_64(Monitor *mon, CPUArchState *env) +static void tlb_info_la48(Monitor *mon, CPUArchState *env, + uint64_t l0, uint64_t pml4_addr) { uint64_t l1, l2, l3, l4; uint64_t pml4e, pdpe, pde, pte; - uint64_t pml4_addr, pdp_addr, pd_addr, pt_addr; + uint64_t pdp_addr, pd_addr, pt_addr; - pml4_addr = env->cr[3] & 0x3fffffffff000ULL; for (l1 = 0; l1 < 512; l1++) { cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8); pml4e = le64_to_cpu(pml4e); - if (pml4e & PG_PRESENT_MASK) { - pdp_addr = pml4e & 0x3fffffffff000ULL; - for (l2 = 0; l2 < 512; l2++) { - cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); - pdpe = le64_to_cpu(pdpe); - if (pdpe & PG_PRESENT_MASK) { - if (pdpe & PG_PSE_MASK) { - /* 1G pages, CR4.PSE is ignored */ - print_pte(mon, (l1 << 39) + (l2 << 30), pdpe, - 0x3ffffc0000000ULL); - } else { - pd_addr = pdpe & 0x3fffffffff000ULL; - for (l3 = 0; l3 < 512; l3++) { - cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); - pde = le64_to_cpu(pde); - if (pde & PG_PRESENT_MASK) { - if (pde & PG_PSE_MASK) { - /* 2M pages, CR4.PSE is ignored */ - print_pte(mon, (l1 << 39) + (l2 << 30) + - (l3 << 21), pde, - 0x3ffffffe00000ULL); - } else { - pt_addr = pde & 0x3fffffffff000ULL; - for (l4 = 0; l4 < 512; l4++) { - cpu_physical_memory_read(pt_addr - + l4 * 8, - &pte, 8); - pte = le64_to_cpu(pte); - if (pte & PG_PRESENT_MASK) { - print_pte(mon, (l1 << 39) + - (l2 << 30) + - (l3 << 21) + (l4 << 12), - pte & ~PG_PSE_MASK, - 0x3fffffffff000ULL); - } - } - } - } - } + if (!(pml4e & PG_PRESENT_MASK)) { + continue; + } + + pdp_addr = pml4e & 0x3fffffffff000ULL; + for (l2 = 0; l2 < 512; l2++) { + cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); + pdpe = le64_to_cpu(pdpe); + if (!(pdpe & PG_PRESENT_MASK)) { + continue; + } + + if (pdpe & PG_PSE_MASK) { + /* 1G pages, CR4.PSE is ignored */ + print_pte(mon, env, (l0 << 48) + (l1 << 39) + (l2 << 30), + pdpe, 0x3ffffc0000000ULL); + continue; + } + + pd_addr = pdpe & 0x3fffffffff000ULL; + for (l3 = 0; l3 < 512; l3++) { + cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); + pde = le64_to_cpu(pde); + if (!(pde & PG_PRESENT_MASK)) { + continue; + } + + if (pde & PG_PSE_MASK) { + /* 2M pages, CR4.PSE is ignored */ + print_pte(mon, env, (l0 << 48) + (l1 << 39) + (l2 << 30) + + (l3 << 21), pde, 0x3ffffffe00000ULL); + continue; + } + + pt_addr = pde & 0x3fffffffff000ULL; + for (l4 = 0; l4 < 512; l4++) { + cpu_physical_memory_read(pt_addr + + l4 * 8, + &pte, 8); + pte = le64_to_cpu(pte); + if (pte & PG_PRESENT_MASK) { + print_pte(mon, env, (l0 << 48) + (l1 << 39) + + (l2 << 30) + (l3 << 21) + (l4 << 12), + pte & ~PG_PSE_MASK, 0x3fffffffff000ULL); } } } } } } + +static void tlb_info_la57(Monitor *mon, CPUArchState *env) +{ + uint64_t l0; + uint64_t pml5e; + uint64_t pml5_addr; + + pml5_addr = env->cr[3] & 0x3fffffffff000ULL; + for (l0 = 0; l0 < 512; l0++) { + cpu_physical_memory_read(pml5_addr + l0 * 8, &pml5e, 8); + pml5e = le64_to_cpu(pml5e); + if (pml5e & PG_PRESENT_MASK) { + tlb_info_la48(mon, env, l0, pml5e & 0x3fffffffff000ULL); + } + } +} #endif /* TARGET_X86_64 */ void hmp_info_tlb(Monitor *mon, const QDict *qdict) @@ -192,7 +218,11 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) if (env->cr[4] & CR4_PAE_MASK) { #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - tlb_info_64(mon, env); + if (env->cr[4] & CR4_LA57_MASK) { + tlb_info_la57(mon, env); + } else { + tlb_info_la48(mon, env, 0, env->cr[3] & 0x3fffffffff000ULL); + } } else #endif { @@ -324,7 +354,7 @@ static void mem_info_pae32(Monitor *mon, CPUArchState *env) #ifdef TARGET_X86_64 -static void mem_info_64(Monitor *mon, CPUArchState *env) +static void mem_info_la48(Monitor *mon, CPUArchState *env) { int prot, last_prot; uint64_t l1, l2, l3, l4; @@ -400,6 +430,98 @@ static void mem_info_64(Monitor *mon, CPUArchState *env) /* Flush last range */ mem_print(mon, &start, &last_prot, (hwaddr)1 << 48, 0); } + +static void mem_info_la57(Monitor *mon, CPUArchState *env) +{ + int prot, last_prot; + uint64_t l0, l1, l2, l3, l4; + uint64_t pml5e, pml4e, pdpe, pde, pte; + uint64_t pml5_addr, pml4_addr, pdp_addr, pd_addr, pt_addr, start, end; + + pml5_addr = env->cr[3] & 0x3fffffffff000ULL; + last_prot = 0; + start = -1; + for (l0 = 0; l0 < 512; l0++) { + cpu_physical_memory_read(pml5_addr + l0 * 8, &pml5e, 8); + pml4e = le64_to_cpu(pml5e); + end = l0 << 48; + if (!(pml5e & PG_PRESENT_MASK)) { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + continue; + } + + pml4_addr = pml5e & 0x3fffffffff000ULL; + for (l1 = 0; l1 < 512; l1++) { + cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8); + pml4e = le64_to_cpu(pml4e); + end = (l0 << 48) + (l1 << 39); + if (!(pml4e & PG_PRESENT_MASK)) { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + continue; + } + + pdp_addr = pml4e & 0x3fffffffff000ULL; + for (l2 = 0; l2 < 512; l2++) { + cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8); + pdpe = le64_to_cpu(pdpe); + end = (l0 << 48) + (l1 << 39) + (l2 << 30); + if (pdpe & PG_PRESENT_MASK) { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + continue; + } + + if (pdpe & PG_PSE_MASK) { + prot = pdpe & (PG_USER_MASK | PG_RW_MASK | + PG_PRESENT_MASK); + prot &= pml4e; + mem_print(mon, &start, &last_prot, end, prot); + continue; + } + + pd_addr = pdpe & 0x3fffffffff000ULL; + for (l3 = 0; l3 < 512; l3++) { + cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8); + pde = le64_to_cpu(pde); + end = (l0 << 48) + (l1 << 39) + (l2 << 30) + (l3 << 21); + if (pde & PG_PRESENT_MASK) { + prot = 0; + mem_print(mon, &start, &last_prot, end, prot); + continue; + } + + if (pde & PG_PSE_MASK) { + prot = pde & (PG_USER_MASK | PG_RW_MASK | + PG_PRESENT_MASK); + prot &= pml4e & pdpe; + mem_print(mon, &start, &last_prot, end, prot); + continue; + } + + pt_addr = pde & 0x3fffffffff000ULL; + for (l4 = 0; l4 < 512; l4++) { + cpu_physical_memory_read(pt_addr + l4 * 8, &pte, 8); + pte = le64_to_cpu(pte); + end = (l0 << 48) + (l1 << 39) + (l2 << 30) + + (l3 << 21) + (l4 << 12); + if (pte & PG_PRESENT_MASK) { + prot = pte & (PG_USER_MASK | PG_RW_MASK | + PG_PRESENT_MASK); + prot &= pml4e & pdpe & pde; + } else { + prot = 0; + } + mem_print(mon, &start, &last_prot, end, prot); + } + } + } + } + } + /* Flush last range */ + mem_print(mon, &start, &last_prot, (hwaddr)1 << 57, 0); +} #endif /* TARGET_X86_64 */ void hmp_info_mem(Monitor *mon, const QDict *qdict) @@ -415,7 +537,11 @@ void hmp_info_mem(Monitor *mon, const QDict *qdict) if (env->cr[4] & CR4_PAE_MASK) { #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - mem_info_64(mon, env); + if (env->cr[4] & CR4_LA57_MASK) { + mem_info_la57(mon, env); + } else { + mem_info_la48(mon, env); + } } else #endif { diff --git a/target-i386/mpx_helper.c b/target/i386/mpx_helper.c index 7e44820659..7e44820659 100644 --- a/target-i386/mpx_helper.c +++ b/target/i386/mpx_helper.c diff --git a/target-i386/ops_sse.h b/target/i386/ops_sse.h index 7a98f53864..7a98f53864 100644 --- a/target-i386/ops_sse.h +++ b/target/i386/ops_sse.h diff --git a/target-i386/ops_sse_header.h b/target/i386/ops_sse_header.h index 64c5857cf4..64c5857cf4 100644 --- a/target-i386/ops_sse_header.h +++ b/target/i386/ops_sse_header.h diff --git a/target-i386/seg_helper.c b/target/i386/seg_helper.c index fb79f3180d..fb79f3180d 100644 --- a/target-i386/seg_helper.c +++ b/target/i386/seg_helper.c diff --git a/target-i386/shift_helper_template.h b/target/i386/shift_helper_template.h index cf91a2d284..cf91a2d284 100644 --- a/target-i386/shift_helper_template.h +++ b/target/i386/shift_helper_template.h diff --git a/target-i386/smm_helper.c b/target/i386/smm_helper.c index 4dd6a2c544..4dd6a2c544 100644 --- a/target-i386/smm_helper.c +++ b/target/i386/smm_helper.c diff --git a/target-i386/svm.h b/target/i386/svm.h index 922c8fd39c..922c8fd39c 100644 --- a/target-i386/svm.h +++ b/target/i386/svm.h diff --git a/target-i386/svm_helper.c b/target/i386/svm_helper.c index 782b3f12f0..782b3f12f0 100644 --- a/target-i386/svm_helper.c +++ b/target/i386/svm_helper.c diff --git a/target-i386/trace-events b/target/i386/trace-events index 05c5453d35..de6a1cf0cb 100644 --- a/target-i386/trace-events +++ b/target/i386/trace-events @@ -1,6 +1,6 @@ # See docs/tracing.txt for syntax documentation. -# target-i386/kvm.c +# target/i386/kvm.c kvm_x86_fixup_msi_error(uint32_t gsi) "VT-d failed to remap interrupt for GSI %" PRIu32 kvm_x86_add_msi_route(int virq) "Adding route entry for virq %d" kvm_x86_remove_msi_route(int virq) "Removing route entry for virq %d" diff --git a/target-i386/translate.c b/target/i386/translate.c index 324103c885..59e11fcd1f 100644 --- a/target-i386/translate.c +++ b/target/i386/translate.c @@ -2500,8 +2500,10 @@ static void gen_bnd_jmp(DisasContext *s) } /* Generate an end of block. Trace exception is also generated if needed. - If IIM, set HF_INHIBIT_IRQ_MASK if it isn't already set. */ -static void gen_eob_inhibit_irq(DisasContext *s, bool inhibit) + If INHIBIT, set HF_INHIBIT_IRQ_MASK if it isn't already set. + If RECHECK_TF, emit a rechecking helper for #DB, ignoring the state of + S->TF. This is used by the syscall/sysret insns. */ +static void gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf) { gen_update_cc_op(s); @@ -2517,6 +2519,9 @@ static void gen_eob_inhibit_irq(DisasContext *s, bool inhibit) } if (s->singlestep_enabled) { gen_helper_debug(cpu_env); + } else if (recheck_tf) { + gen_helper_rechecking_single_step(cpu_env); + tcg_gen_exit_tb(0); } else if (s->tf) { gen_helper_single_step(cpu_env); } else { @@ -2525,10 +2530,17 @@ static void gen_eob_inhibit_irq(DisasContext *s, bool inhibit) s->is_jmp = DISAS_TB_JUMP; } +/* End of block. + If INHIBIT, set HF_INHIBIT_IRQ_MASK if it isn't already set. */ +static void gen_eob_inhibit_irq(DisasContext *s, bool inhibit) +{ + gen_eob_worker(s, inhibit, false); +} + /* End of block, resetting the inhibit irq flag. */ static void gen_eob(DisasContext *s) { - gen_eob_inhibit_irq(s, false); + gen_eob_worker(s, false, false); } /* generate a jump to eip. No segment change must happen before as a @@ -6423,7 +6435,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_const_i32(s->pc - s->cs_base)); set_cc_op(s, CC_OP_EFLAGS); } - gen_eob(s); + /* TF handling for the syscall insn is different. The TF bit is checked + after the syscall insn completes. This allows #DB to not be + generated after one has entered CPL0 if TF is set in FMASK. */ + gen_eob_worker(s, false, true); break; case 0xe8: /* call im */ { @@ -7115,7 +7130,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->lma) { set_cc_op(s, CC_OP_EFLAGS); } - gen_eob(s); + /* TF handling for the sysret insn is different. The TF bit is + checked after the sysret insn completes. This allows #DB to be + generated "as if" the syscall insn in userspace has just + completed. */ + gen_eob_worker(s, false, true); } break; #endif diff --git a/target-lm32/Makefile.objs b/target/lm32/Makefile.objs index c3e1bd6bd6..c3e1bd6bd6 100644 --- a/target-lm32/Makefile.objs +++ b/target/lm32/Makefile.objs diff --git a/target-lm32/README b/target/lm32/README index ba3508a711..ba3508a711 100644 --- a/target-lm32/README +++ b/target/lm32/README diff --git a/target-lm32/TODO b/target/lm32/TODO index e163c42ebe..e163c42ebe 100644 --- a/target-lm32/TODO +++ b/target/lm32/TODO diff --git a/target-lm32/cpu-qom.h b/target/lm32/cpu-qom.h index b423d2564b..b423d2564b 100644 --- a/target-lm32/cpu-qom.h +++ b/target/lm32/cpu-qom.h diff --git a/target-lm32/cpu.c b/target/lm32/cpu.c index 8d939a7779..8d939a7779 100644 --- a/target-lm32/cpu.c +++ b/target/lm32/cpu.c diff --git a/target-lm32/cpu.h b/target/lm32/cpu.h index d8a3515244..d8a3515244 100644 --- a/target-lm32/cpu.h +++ b/target/lm32/cpu.h diff --git a/target-lm32/gdbstub.c b/target/lm32/gdbstub.c index cf929dd392..cf929dd392 100644 --- a/target-lm32/gdbstub.c +++ b/target/lm32/gdbstub.c diff --git a/target-lm32/helper.c b/target/lm32/helper.c index 891da18c30..891da18c30 100644 --- a/target-lm32/helper.c +++ b/target/lm32/helper.c diff --git a/target-lm32/helper.h b/target/lm32/helper.h index 445578c439..445578c439 100644 --- a/target-lm32/helper.h +++ b/target/lm32/helper.h diff --git a/target-lm32/lm32-semi.c b/target/lm32/lm32-semi.c index 20f1a1cd48..6a11a6299a 100644 --- a/target-lm32/lm32-semi.c +++ b/target/lm32/lm32-semi.c @@ -3,7 +3,7 @@ * * Copyright (c) 2014 Michael Walle <michael@walle.cc> * - * Based on target-m68k/m68k-semi.c, which is + * Based on target/m68k/m68k-semi.c, which is * Copyright (c) 2005-2007 CodeSourcery. * * This work is licensed under the terms of the GNU GPL, version 2 or later. diff --git a/target-lm32/machine.c b/target/lm32/machine.c index 3c258a4bcc..3c258a4bcc 100644 --- a/target-lm32/machine.c +++ b/target/lm32/machine.c diff --git a/target-lm32/op_helper.c b/target/lm32/op_helper.c index 2177c8ad12..2177c8ad12 100644 --- a/target-lm32/op_helper.c +++ b/target/lm32/op_helper.c diff --git a/target-lm32/translate.c b/target/lm32/translate.c index 692882f447..692882f447 100644 --- a/target-lm32/translate.c +++ b/target/lm32/translate.c diff --git a/target-m68k/Makefile.objs b/target/m68k/Makefile.objs index 02cf616a78..02cf616a78 100644 --- a/target-m68k/Makefile.objs +++ b/target/m68k/Makefile.objs diff --git a/target-m68k/cpu-qom.h b/target/m68k/cpu-qom.h index 9885bba317..9885bba317 100644 --- a/target-m68k/cpu-qom.h +++ b/target/m68k/cpu-qom.h diff --git a/target-m68k/cpu.c b/target/m68k/cpu.c index ba17480098..ba17480098 100644 --- a/target-m68k/cpu.c +++ b/target/m68k/cpu.c diff --git a/target-m68k/cpu.h b/target/m68k/cpu.h index 6dfb54eb70..0b4ed7b8a6 100644 --- a/target-m68k/cpu.h +++ b/target/m68k/cpu.h @@ -95,10 +95,6 @@ typedef struct CPUM68KState { uint32_t macsr; uint32_t mac_mask; - /* Temporary storage for DIV helpers. */ - uint32_t div1; - uint32_t div2; - /* MMU status. */ struct { uint32_t ar; diff --git a/target-m68k/gdbstub.c b/target/m68k/gdbstub.c index c7f44c9bb3..c7f44c9bb3 100644 --- a/target-m68k/gdbstub.c +++ b/target/m68k/gdbstub.c diff --git a/target-m68k/helper.c b/target/m68k/helper.c index 7aed9ffd2f..f750d3dbaa 100644 --- a/target-m68k/helper.c +++ b/target/m68k/helper.c @@ -284,58 +284,6 @@ void HELPER(set_sr)(CPUM68KState *env, uint32_t val) m68k_switch_sp(env); } -uint32_t HELPER(shl_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint64_t result; - - shift &= 63; - result = (uint64_t)val << shift; - - env->cc_c = (result >> 32) & 1; - env->cc_n = result; - env->cc_z = result; - env->cc_v = 0; - env->cc_x = shift ? env->cc_c : env->cc_x; - - return result; -} - -uint32_t HELPER(shr_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint64_t temp; - uint32_t result; - - shift &= 63; - temp = (uint64_t)val << 32 >> shift; - result = temp >> 32; - - env->cc_c = (temp >> 31) & 1; - env->cc_n = result; - env->cc_z = result; - env->cc_v = 0; - env->cc_x = shift ? env->cc_c : env->cc_x; - - return result; -} - -uint32_t HELPER(sar_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint64_t temp; - uint32_t result; - - shift &= 63; - temp = (int64_t)val << 32 >> shift; - result = temp >> 32; - - env->cc_c = (temp >> 31) & 1; - env->cc_n = result; - env->cc_z = result; - env->cc_v = result ^ val; - env->cc_x = shift ? env->cc_c : env->cc_x; - - return result; -} - /* FPU helpers. */ uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val) { diff --git a/target-m68k/helper.h b/target/m68k/helper.h index 2697e32d0b..17ec342346 100644 --- a/target-m68k/helper.h +++ b/target/m68k/helper.h @@ -1,13 +1,16 @@ DEF_HELPER_1(bitrev, i32, i32) DEF_HELPER_1(ff1, i32, i32) DEF_HELPER_FLAGS_2(sats, TCG_CALL_NO_RWG_SE, i32, i32, i32) -DEF_HELPER_2(divu, void, env, i32) -DEF_HELPER_2(divs, void, env, i32) -DEF_HELPER_3(shl_cc, i32, env, i32, i32) -DEF_HELPER_3(shr_cc, i32, env, i32, i32) -DEF_HELPER_3(sar_cc, i32, env, i32, i32) +DEF_HELPER_3(divuw, void, env, int, i32) +DEF_HELPER_3(divsw, void, env, int, s32) +DEF_HELPER_4(divul, void, env, int, int, i32) +DEF_HELPER_4(divsl, void, env, int, int, s32) +DEF_HELPER_4(divull, void, env, int, int, i32) +DEF_HELPER_4(divsll, void, env, int, int, s32) DEF_HELPER_2(set_sr, void, env, i32) DEF_HELPER_3(movec, void, env, i32, i32) +DEF_HELPER_4(cas2w, void, env, i32, i32, i32) +DEF_HELPER_4(cas2l, void, env, i32, i32, i32) DEF_HELPER_2(f64_to_i32, f32, env, f64) DEF_HELPER_2(f64_to_f32, f32, env, f64) diff --git a/target-m68k/m68k-semi.c b/target/m68k/m68k-semi.c index 1402145c8f..1402145c8f 100644 --- a/target-m68k/m68k-semi.c +++ b/target/m68k/m68k-semi.c diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c new file mode 100644 index 0000000000..e56b815d73 --- /dev/null +++ b/target/m68k/op_helper.c @@ -0,0 +1,471 @@ +/* + * M68K helper routines + * + * Copyright (c) 2007 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "exec/semihost.h" + +#if defined(CONFIG_USER_ONLY) + +void m68k_cpu_do_interrupt(CPUState *cs) +{ + cs->exception_index = -1; +} + +static inline void do_interrupt_m68k_hardirq(CPUM68KState *env) +{ +} + +#else + +/* Try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) +{ + int ret; + + ret = m68k_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); + if (unlikely(ret)) { + if (retaddr) { + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); + } + cpu_loop_exit(cs); + } +} + +static void do_rte(CPUM68KState *env) +{ + uint32_t sp; + uint32_t fmt; + + sp = env->aregs[7]; + fmt = cpu_ldl_kernel(env, sp); + env->pc = cpu_ldl_kernel(env, sp + 4); + sp |= (fmt >> 28) & 3; + env->aregs[7] = sp + 8; + + helper_set_sr(env, fmt); +} + +static void do_interrupt_all(CPUM68KState *env, int is_hw) +{ + CPUState *cs = CPU(m68k_env_get_cpu(env)); + uint32_t sp; + uint32_t fmt; + uint32_t retaddr; + uint32_t vector; + + fmt = 0; + retaddr = env->pc; + + if (!is_hw) { + switch (cs->exception_index) { + case EXCP_RTE: + /* Return from an exception. */ + do_rte(env); + return; + case EXCP_HALT_INSN: + if (semihosting_enabled() + && (env->sr & SR_S) != 0 + && (env->pc & 3) == 0 + && cpu_lduw_code(env, env->pc - 4) == 0x4e71 + && cpu_ldl_code(env, env->pc) == 0x4e7bf000) { + env->pc += 4; + do_m68k_semihosting(env, env->dregs[0]); + return; + } + cs->halted = 1; + cs->exception_index = EXCP_HLT; + cpu_loop_exit(cs); + return; + } + if (cs->exception_index >= EXCP_TRAP0 + && cs->exception_index <= EXCP_TRAP15) { + /* Move the PC after the trap instruction. */ + retaddr += 2; + } + } + + vector = cs->exception_index << 2; + + fmt |= 0x40000000; + fmt |= vector << 16; + fmt |= env->sr; + fmt |= cpu_m68k_get_ccr(env); + + env->sr |= SR_S; + if (is_hw) { + env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); + env->sr &= ~SR_M; + } + m68k_switch_sp(env); + sp = env->aregs[7]; + fmt |= (sp & 3) << 28; + + /* ??? This could cause MMU faults. */ + sp &= ~3; + sp -= 4; + cpu_stl_kernel(env, sp, retaddr); + sp -= 4; + cpu_stl_kernel(env, sp, fmt); + env->aregs[7] = sp; + /* Jump to vector. */ + env->pc = cpu_ldl_kernel(env, env->vbr + vector); +} + +void m68k_cpu_do_interrupt(CPUState *cs) +{ + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; + + do_interrupt_all(env, 0); +} + +static inline void do_interrupt_m68k_hardirq(CPUM68KState *env) +{ + do_interrupt_all(env, 1); +} +#endif + +bool m68k_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; + + if (interrupt_request & CPU_INTERRUPT_HARD + && ((env->sr & SR_I) >> SR_I_SHIFT) < env->pending_level) { + /* Real hardware gets the interrupt vector via an IACK cycle + at this point. Current emulated hardware doesn't rely on + this, so we provide/save the vector when the interrupt is + first signalled. */ + cs->exception_index = env->pending_vector; + do_interrupt_m68k_hardirq(env); + return true; + } + return false; +} + +static void raise_exception_ra(CPUM68KState *env, int tt, uintptr_t raddr) +{ + CPUState *cs = CPU(m68k_env_get_cpu(env)); + + cs->exception_index = tt; + cpu_loop_exit_restore(cs, raddr); +} + +static void raise_exception(CPUM68KState *env, int tt) +{ + raise_exception_ra(env, tt, 0); +} + +void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) +{ + raise_exception(env, tt); +} + +void HELPER(divuw)(CPUM68KState *env, int destr, uint32_t den) +{ + uint32_t num = env->dregs[destr]; + uint32_t quot, rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; /* always cleared, even if overflow */ + if (quot > 0xffff) { + env->cc_v = -1; + /* real 68040 keeps N and unset Z on overflow, + * whereas documentation says "undefined" + */ + env->cc_z = 1; + return; + } + env->dregs[destr] = deposit32(quot, 16, 16, rem); + env->cc_z = (int16_t)quot; + env->cc_n = (int16_t)quot; + env->cc_v = 0; +} + +void HELPER(divsw)(CPUM68KState *env, int destr, int32_t den) +{ + int32_t num = env->dregs[destr]; + uint32_t quot, rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; /* always cleared, even if overflow */ + if (quot != (int16_t)quot) { + env->cc_v = -1; + /* nothing else is modified */ + /* real 68040 keeps N and unset Z on overflow, + * whereas documentation says "undefined" + */ + env->cc_z = 1; + return; + } + env->dregs[destr] = deposit32(quot, 16, 16, rem); + env->cc_z = (int16_t)quot; + env->cc_n = (int16_t)quot; + env->cc_v = 0; +} + +void HELPER(divul)(CPUM68KState *env, int numr, int regr, uint32_t den) +{ + uint32_t num = env->dregs[numr]; + uint32_t quot, rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; + env->cc_z = quot; + env->cc_n = quot; + env->cc_v = 0; + + if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { + if (numr == regr) { + env->dregs[numr] = quot; + } else { + env->dregs[regr] = rem; + } + } else { + env->dregs[regr] = rem; + env->dregs[numr] = quot; + } +} + +void HELPER(divsl)(CPUM68KState *env, int numr, int regr, int32_t den) +{ + int32_t num = env->dregs[numr]; + int32_t quot, rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; + env->cc_z = quot; + env->cc_n = quot; + env->cc_v = 0; + + if (m68k_feature(env, M68K_FEATURE_CF_ISA_A)) { + if (numr == regr) { + env->dregs[numr] = quot; + } else { + env->dregs[regr] = rem; + } + } else { + env->dregs[regr] = rem; + env->dregs[numr] = quot; + } +} + +void HELPER(divull)(CPUM68KState *env, int numr, int regr, uint32_t den) +{ + uint64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); + uint64_t quot; + uint32_t rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; /* always cleared, even if overflow */ + if (quot > 0xffffffffULL) { + env->cc_v = -1; + /* real 68040 keeps N and unset Z on overflow, + * whereas documentation says "undefined" + */ + env->cc_z = 1; + return; + } + env->cc_z = quot; + env->cc_n = quot; + env->cc_v = 0; + + /* + * If Dq and Dr are the same, the quotient is returned. + * therefore we set Dq last. + */ + + env->dregs[regr] = rem; + env->dregs[numr] = quot; +} + +void HELPER(divsll)(CPUM68KState *env, int numr, int regr, int32_t den) +{ + int64_t num = deposit64(env->dregs[numr], 32, 32, env->dregs[regr]); + int64_t quot; + int32_t rem; + + if (den == 0) { + raise_exception_ra(env, EXCP_DIV0, GETPC()); + } + quot = num / den; + rem = num % den; + + env->cc_c = 0; /* always cleared, even if overflow */ + if (quot != (int32_t)quot) { + env->cc_v = -1; + /* real 68040 keeps N and unset Z on overflow, + * whereas documentation says "undefined" + */ + env->cc_z = 1; + return; + } + env->cc_z = quot; + env->cc_n = quot; + env->cc_v = 0; + + /* + * If Dq and Dr are the same, the quotient is returned. + * therefore we set Dq last. + */ + + env->dregs[regr] = rem; + env->dregs[numr] = quot; +} + +void HELPER(cas2w)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2) +{ + uint32_t Dc1 = extract32(regs, 9, 3); + uint32_t Dc2 = extract32(regs, 6, 3); + uint32_t Du1 = extract32(regs, 3, 3); + uint32_t Du2 = extract32(regs, 0, 3); + int16_t c1 = env->dregs[Dc1]; + int16_t c2 = env->dregs[Dc2]; + int16_t u1 = env->dregs[Du1]; + int16_t u2 = env->dregs[Du2]; + int16_t l1, l2; + uintptr_t ra = GETPC(); + + if (parallel_cpus) { + /* Tell the main loop we need to serialize this insn. */ + cpu_loop_exit_atomic(ENV_GET_CPU(env), ra); + } else { + /* We're executing in a serial context -- no need to be atomic. */ + l1 = cpu_lduw_data_ra(env, a1, ra); + l2 = cpu_lduw_data_ra(env, a2, ra); + if (l1 == c1 && l2 == c2) { + cpu_stw_data_ra(env, a1, u1, ra); + cpu_stw_data_ra(env, a2, u2, ra); + } + } + + if (c1 != l1) { + env->cc_n = l1; + env->cc_v = c1; + } else { + env->cc_n = l2; + env->cc_v = c2; + } + env->cc_op = CC_OP_CMPW; + env->dregs[Dc1] = deposit32(env->dregs[Dc1], 0, 16, l1); + env->dregs[Dc2] = deposit32(env->dregs[Dc2], 0, 16, l2); +} + +void HELPER(cas2l)(CPUM68KState *env, uint32_t regs, uint32_t a1, uint32_t a2) +{ + uint32_t Dc1 = extract32(regs, 9, 3); + uint32_t Dc2 = extract32(regs, 6, 3); + uint32_t Du1 = extract32(regs, 3, 3); + uint32_t Du2 = extract32(regs, 0, 3); + uint32_t c1 = env->dregs[Dc1]; + uint32_t c2 = env->dregs[Dc2]; + uint32_t u1 = env->dregs[Du1]; + uint32_t u2 = env->dregs[Du2]; + uint32_t l1, l2; + uintptr_t ra = GETPC(); +#if defined(CONFIG_ATOMIC64) && !defined(CONFIG_USER_ONLY) + int mmu_idx = cpu_mmu_index(env, 0); + TCGMemOpIdx oi; +#endif + + if (parallel_cpus) { + /* We're executing in a parallel context -- must be atomic. */ +#ifdef CONFIG_ATOMIC64 + uint64_t c, u, l; + if ((a1 & 7) == 0 && a2 == a1 + 4) { + c = deposit64(c2, 32, 32, c1); + u = deposit64(u2, 32, 32, u1); +#ifdef CONFIG_USER_ONLY + l = helper_atomic_cmpxchgq_be(env, a1, c, u); +#else + oi = make_memop_idx(MO_BEQ, mmu_idx); + l = helper_atomic_cmpxchgq_be_mmu(env, a1, c, u, oi, ra); +#endif + l1 = l >> 32; + l2 = l; + } else if ((a2 & 7) == 0 && a1 == a2 + 4) { + c = deposit64(c1, 32, 32, c2); + u = deposit64(u1, 32, 32, u2); +#ifdef CONFIG_USER_ONLY + l = helper_atomic_cmpxchgq_be(env, a2, c, u); +#else + oi = make_memop_idx(MO_BEQ, mmu_idx); + l = helper_atomic_cmpxchgq_be_mmu(env, a2, c, u, oi, ra); +#endif + l2 = l >> 32; + l1 = l; + } else +#endif + { + /* Tell the main loop we need to serialize this insn. */ + cpu_loop_exit_atomic(ENV_GET_CPU(env), ra); + } + } else { + /* We're executing in a serial context -- no need to be atomic. */ + l1 = cpu_ldl_data_ra(env, a1, ra); + l2 = cpu_ldl_data_ra(env, a2, ra); + if (l1 == c1 && l2 == c2) { + cpu_stl_data_ra(env, a1, u1, ra); + cpu_stl_data_ra(env, a2, u2, ra); + } + } + + if (c1 != l1) { + env->cc_n = l1; + env->cc_v = c1; + } else { + env->cc_n = l2; + env->cc_v = c2; + } + env->cc_op = CC_OP_CMPL; + env->dregs[Dc1] = l1; + env->dregs[Dc2] = l2; +} diff --git a/target-m68k/qregs.def b/target/m68k/qregs.def index 156c0f558f..51ff43bf33 100644 --- a/target-m68k/qregs.def +++ b/target/m68k/qregs.def @@ -7,7 +7,5 @@ DEFO32(CC_C, cc_c) DEFO32(CC_N, cc_n) DEFO32(CC_V, cc_v) DEFO32(CC_Z, cc_z) -DEFO32(DIV1, div1) -DEFO32(DIV2, div2) DEFO32(MACSR, macsr) DEFO32(MAC_MASK, mac_mask) diff --git a/target-m68k/translate.c b/target/m68k/translate.c index d6ed883882..53293173c5 100644 --- a/target-m68k/translate.c +++ b/target/m68k/translate.c @@ -59,12 +59,12 @@ static TCGv cpu_aregs[8]; static TCGv_i64 cpu_fregs[8]; static TCGv_i64 cpu_macc[4]; -#define REG(insn, pos) (((insn) >> (pos)) & 7) +#define REG(insn, pos) (((insn) >> (pos)) & 7) #define DREG(insn, pos) cpu_dregs[REG(insn, pos)] -#define AREG(insn, pos) cpu_aregs[REG(insn, pos)] +#define AREG(insn, pos) get_areg(s, REG(insn, pos)) #define FREG(insn, pos) cpu_fregs[REG(insn, pos)] -#define MACREG(acc) cpu_macc[acc] -#define QREG_SP cpu_aregs[7] +#define MACREG(acc) cpu_macc[acc] +#define QREG_SP get_areg(s, 7) static TCGv NULL_QREG; #define IS_NULL_QREG(t) (TCGV_EQUAL(t, NULL_QREG)) @@ -141,8 +141,55 @@ typedef struct DisasContext { int singlestep_enabled; TCGv_i64 mactmp; int done_mac; + int writeback_mask; + TCGv writeback[8]; } DisasContext; +static TCGv get_areg(DisasContext *s, unsigned regno) +{ + if (s->writeback_mask & (1 << regno)) { + return s->writeback[regno]; + } else { + return cpu_aregs[regno]; + } +} + +static void delay_set_areg(DisasContext *s, unsigned regno, + TCGv val, bool give_temp) +{ + if (s->writeback_mask & (1 << regno)) { + if (give_temp) { + tcg_temp_free(s->writeback[regno]); + s->writeback[regno] = val; + } else { + tcg_gen_mov_i32(s->writeback[regno], val); + } + } else { + s->writeback_mask |= 1 << regno; + if (give_temp) { + s->writeback[regno] = val; + } else { + TCGv tmp = tcg_temp_new(); + s->writeback[regno] = tmp; + tcg_gen_mov_i32(tmp, val); + } + } +} + +static void do_writebacks(DisasContext *s) +{ + unsigned mask = s->writeback_mask; + if (mask) { + s->writeback_mask = 0; + do { + unsigned regno = ctz32(mask); + tcg_gen_mov_i32(cpu_aregs[regno], s->writeback[regno]); + tcg_temp_free(s->writeback[regno]); + mask &= mask - 1; + } while (mask); + } +} + #define DISAS_JUMP_NEXT 4 #if defined(CONFIG_USER_ONLY) @@ -331,7 +378,7 @@ static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s) } /* Calculate and address index. */ -static TCGv gen_addr_index(uint16_t ext, TCGv tmp) +static TCGv gen_addr_index(DisasContext *s, uint16_t ext, TCGv tmp) { TCGv add; int scale; @@ -388,7 +435,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) tmp = tcg_temp_new(); if ((ext & 0x44) == 0) { /* pre-index */ - add = gen_addr_index(ext, tmp); + add = gen_addr_index(s, ext, tmp); } else { add = NULL_QREG; } @@ -417,7 +464,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) /* memory indirect */ base = gen_load(s, OS_LONG, add, 0); if ((ext & 0x44) == 4) { - add = gen_addr_index(ext, tmp); + add = gen_addr_index(s, ext, tmp); tcg_gen_add_i32(tmp, add, base); add = tmp; } else { @@ -441,7 +488,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) } else { /* brief extension word format */ tmp = tcg_temp_new(); - add = gen_addr_index(ext, tmp); + add = gen_addr_index(s, ext, tmp); if (!IS_NULL_QREG(base)) { tcg_gen_add_i32(tmp, add, base); if ((int8_t)ext) @@ -632,12 +679,14 @@ static void gen_partset_reg(int opsize, TCGv reg, TCGv val) tmp = tcg_temp_new(); tcg_gen_ext8u_i32(tmp, val); tcg_gen_or_i32(reg, reg, tmp); + tcg_temp_free(tmp); break; case OS_WORD: tcg_gen_andi_i32(reg, reg, 0xffff0000); tmp = tcg_temp_new(); tcg_gen_ext16u_i32(tmp, val); tcg_gen_or_i32(reg, reg, tmp); + tcg_temp_free(tmp); break; case OS_LONG: case OS_SINGLE: @@ -650,37 +699,37 @@ static void gen_partset_reg(int opsize, TCGv reg, TCGv val) /* Generate code for an "effective address". Does not adjust the base register for autoincrement addressing modes. */ -static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, - int opsize) +static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s, + int mode, int reg0, int opsize) { TCGv reg; TCGv tmp; uint16_t ext; uint32_t offset; - switch ((insn >> 3) & 7) { + switch (mode) { case 0: /* Data register direct. */ case 1: /* Address register direct. */ return NULL_QREG; case 2: /* Indirect register */ case 3: /* Indirect postincrement. */ - return AREG(insn, 0); + return get_areg(s, reg0); case 4: /* Indirect predecrememnt. */ - reg = AREG(insn, 0); + reg = get_areg(s, reg0); tmp = tcg_temp_new(); tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize)); return tmp; case 5: /* Indirect displacement. */ - reg = AREG(insn, 0); + reg = get_areg(s, reg0); tmp = tcg_temp_new(); ext = read_im16(env, s); tcg_gen_addi_i32(tmp, reg, (int16_t)ext); return tmp; case 6: /* Indirect index + displacement. */ - reg = AREG(insn, 0); + reg = get_areg(s, reg0); return gen_lea_indexed(env, s, reg); case 7: /* Other */ - switch (insn & 7) { + switch (reg0) { case 0: /* Absolute short. */ offset = (int16_t)read_im16(env, s); return tcg_const_i32(offset); @@ -702,39 +751,26 @@ static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, return NULL_QREG; } -/* Helper function for gen_ea. Reuse the computed address between the - for read/write operands. */ -static inline TCGv gen_ea_once(CPUM68KState *env, DisasContext *s, - uint16_t insn, int opsize, TCGv val, - TCGv *addrp, ea_what what) +static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, + int opsize) { - TCGv tmp; - - if (addrp && what == EA_STORE) { - tmp = *addrp; - } else { - tmp = gen_lea(env, s, insn, opsize); - if (IS_NULL_QREG(tmp)) - return tmp; - if (addrp) - *addrp = tmp; - } - return gen_ldst(s, opsize, tmp, val, what); + int mode = extract32(insn, 3, 3); + int reg0 = REG(insn, 0); + return gen_lea_mode(env, s, mode, reg0, opsize); } -/* Generate code to load/store a value from/into an EA. If VAL > 0 this is +/* Generate code to load/store a value from/into an EA. If WHAT > 0 this is a write otherwise it is a read (0 == sign extend, -1 == zero extend). ADDRP is non-null for readwrite operands. */ -static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, - int opsize, TCGv val, TCGv *addrp, ea_what what) +static TCGv gen_ea_mode(CPUM68KState *env, DisasContext *s, int mode, int reg0, + int opsize, TCGv val, TCGv *addrp, ea_what what) { - TCGv reg; - TCGv result; - uint32_t offset; + TCGv reg, tmp, result; + int32_t offset; - switch ((insn >> 3) & 7) { + switch (mode) { case 0: /* Data register direct. */ - reg = DREG(insn, 0); + reg = cpu_dregs[reg0]; if (what == EA_STORE) { gen_partset_reg(opsize, reg, val); return store_dummy; @@ -742,7 +778,7 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, return gen_extend(reg, opsize, what == EA_LOADS); } case 1: /* Address register direct. */ - reg = AREG(insn, 0); + reg = get_areg(s, reg0); if (what == EA_STORE) { tcg_gen_mov_i32(reg, val); return store_dummy; @@ -750,47 +786,56 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, return gen_extend(reg, opsize, what == EA_LOADS); } case 2: /* Indirect register */ - reg = AREG(insn, 0); + reg = get_areg(s, reg0); return gen_ldst(s, opsize, reg, val, what); case 3: /* Indirect postincrement. */ - reg = AREG(insn, 0); + reg = get_areg(s, reg0); result = gen_ldst(s, opsize, reg, val, what); - /* ??? This is not exception safe. The instruction may still - fault after this point. */ - if (what == EA_STORE || !addrp) - tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize)); + if (what == EA_STORE || !addrp) { + TCGv tmp = tcg_temp_new(); + tcg_gen_addi_i32(tmp, reg, opsize_bytes(opsize)); + delay_set_areg(s, reg0, tmp, true); + } return result; case 4: /* Indirect predecrememnt. */ - { - TCGv tmp; - if (addrp && what == EA_STORE) { - tmp = *addrp; - } else { - tmp = gen_lea(env, s, insn, opsize); - if (IS_NULL_QREG(tmp)) - return tmp; - if (addrp) - *addrp = tmp; + if (addrp && what == EA_STORE) { + tmp = *addrp; + } else { + tmp = gen_lea_mode(env, s, mode, reg0, opsize); + if (IS_NULL_QREG(tmp)) { + return tmp; } - result = gen_ldst(s, opsize, tmp, val, what); - /* ??? This is not exception safe. The instruction may still - fault after this point. */ - if (what == EA_STORE || !addrp) { - reg = AREG(insn, 0); - tcg_gen_mov_i32(reg, tmp); + if (addrp) { + *addrp = tmp; } } + result = gen_ldst(s, opsize, tmp, val, what); + if (what == EA_STORE || !addrp) { + delay_set_areg(s, reg0, tmp, false); + } return result; case 5: /* Indirect displacement. */ case 6: /* Indirect index + displacement. */ - return gen_ea_once(env, s, insn, opsize, val, addrp, what); + do_indirect: + if (addrp && what == EA_STORE) { + tmp = *addrp; + } else { + tmp = gen_lea_mode(env, s, mode, reg0, opsize); + if (IS_NULL_QREG(tmp)) { + return tmp; + } + if (addrp) { + *addrp = tmp; + } + } + return gen_ldst(s, opsize, tmp, val, what); case 7: /* Other */ - switch (insn & 7) { + switch (reg0) { case 0: /* Absolute short. */ case 1: /* Absolute long. */ case 2: /* pc displacement */ case 3: /* pc index+displacement. */ - return gen_ea_once(env, s, insn, opsize, val, addrp, what); + goto do_indirect; case 4: /* Immediate. */ /* Sign extend values for consistency. */ switch (opsize) { @@ -823,6 +868,14 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, return NULL_QREG; } +static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, + int opsize, TCGv val, TCGv *addrp, ea_what what) +{ + int mode = extract32(insn, 3, 3); + int reg0 = REG(insn, 0); + return gen_ea_mode(env, s, mode, reg0, opsize, val, addrp, what); +} + typedef struct { TCGCond tcond; bool g1; @@ -1054,11 +1107,19 @@ static void gen_jmp(DisasContext *s, TCGv dest) s->is_jmp = DISAS_JUMP; } +static void gen_raise_exception(int nr) +{ + TCGv_i32 tmp = tcg_const_i32(nr); + + gen_helper_raise_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); +} + static void gen_exception(DisasContext *s, uint32_t where, int nr) { update_cc_op(s); gen_jmp_im(s, where); - gen_helper_raise_exception(cpu_env, tcg_const_i32(nr)); + gen_raise_exception(nr); } static inline void gen_addr_fault(DisasContext *s) @@ -1163,10 +1224,12 @@ DISAS_INSN(undef_fpu) DISAS_INSN(undef) { - M68kCPU *cpu = m68k_env_get_cpu(env); - + /* ??? This is both instructions that are as yet unimplemented + for the 680x0 series, as well as those that are implemented + but actually illegal for CPU32 or pre-68020. */ + qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x", + insn, s->pc - 2); gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED); - cpu_abort(CPU(cpu), "Illegal instruction: %04x @ %08x", insn, s->pc - 2); } DISAS_INSN(mulw) @@ -1187,71 +1250,297 @@ DISAS_INSN(mulw) tcg_gen_mul_i32(tmp, tmp, src); tcg_gen_mov_i32(reg, tmp); gen_logic_cc(s, tmp, OS_LONG); + tcg_temp_free(tmp); } DISAS_INSN(divw) { - TCGv reg; - TCGv tmp; - TCGv src; int sign; + TCGv src; + TCGv destr; + + /* divX.w <EA>,Dn 32/16 -> 16r:16q */ sign = (insn & 0x100) != 0; - reg = DREG(insn, 9); - if (sign) { - tcg_gen_ext16s_i32(QREG_DIV1, reg); - } else { - tcg_gen_ext16u_i32(QREG_DIV1, reg); - } + + /* dest.l / src.w */ + SRC_EA(env, src, OS_WORD, sign, NULL); - tcg_gen_mov_i32(QREG_DIV2, src); + destr = tcg_const_i32(REG(insn, 9)); if (sign) { - gen_helper_divs(cpu_env, tcg_const_i32(1)); + gen_helper_divsw(cpu_env, destr, src); } else { - gen_helper_divu(cpu_env, tcg_const_i32(1)); + gen_helper_divuw(cpu_env, destr, src); } - - tmp = tcg_temp_new(); - src = tcg_temp_new(); - tcg_gen_ext16u_i32(tmp, QREG_DIV1); - tcg_gen_shli_i32(src, QREG_DIV2, 16); - tcg_gen_or_i32(reg, tmp, src); + tcg_temp_free(destr); set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(divl) { - TCGv num; - TCGv den; - TCGv reg; + TCGv num, reg, den; + int sign; uint16_t ext; ext = read_im16(env, s); - if (ext & 0x87f8) { - gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + + sign = (ext & 0x0800) != 0; + + if (ext & 0x400) { + if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) { + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); + return; + } + + /* divX.l <EA>, Dr:Dq 64/32 -> 32r:32q */ + + SRC_EA(env, den, OS_LONG, 0, NULL); + num = tcg_const_i32(REG(ext, 12)); + reg = tcg_const_i32(REG(ext, 0)); + if (sign) { + gen_helper_divsll(cpu_env, num, reg, den); + } else { + gen_helper_divull(cpu_env, num, reg, den); + } + tcg_temp_free(reg); + tcg_temp_free(num); + set_cc_op(s, CC_OP_FLAGS); return; } - num = DREG(ext, 12); - reg = DREG(ext, 0); - tcg_gen_mov_i32(QREG_DIV1, num); + + /* divX.l <EA>, Dq 32/32 -> 32q */ + /* divXl.l <EA>, Dr:Dq 32/32 -> 32r:32q */ + SRC_EA(env, den, OS_LONG, 0, NULL); - tcg_gen_mov_i32(QREG_DIV2, den); - if (ext & 0x0800) { - gen_helper_divs(cpu_env, tcg_const_i32(0)); - } else { - gen_helper_divu(cpu_env, tcg_const_i32(0)); - } - if ((ext & 7) == ((ext >> 12) & 7)) { - /* div */ - tcg_gen_mov_i32 (reg, QREG_DIV1); + num = tcg_const_i32(REG(ext, 12)); + reg = tcg_const_i32(REG(ext, 0)); + if (sign) { + gen_helper_divsl(cpu_env, num, reg, den); } else { - /* rem */ - tcg_gen_mov_i32 (reg, QREG_DIV2); + gen_helper_divul(cpu_env, num, reg, den); } + tcg_temp_free(reg); + tcg_temp_free(num); + set_cc_op(s, CC_OP_FLAGS); } +static void bcd_add(TCGv dest, TCGv src) +{ + TCGv t0, t1; + + /* dest10 = dest10 + src10 + X + * + * t1 = src + * t2 = t1 + 0x066 + * t3 = t2 + dest + X + * t4 = t2 ^ dest + * t5 = t3 ^ t4 + * t6 = ~t5 & 0x110 + * t7 = (t6 >> 2) | (t6 >> 3) + * return t3 - t7 + */ + + /* t1 = (src + 0x066) + dest + X + * = result with some possible exceding 0x6 + */ + + t0 = tcg_const_i32(0x066); + tcg_gen_add_i32(t0, t0, src); + + t1 = tcg_temp_new(); + tcg_gen_add_i32(t1, t0, dest); + tcg_gen_add_i32(t1, t1, QREG_CC_X); + + /* we will remove exceding 0x6 where there is no carry */ + + /* t0 = (src + 0x0066) ^ dest + * = t1 without carries + */ + + tcg_gen_xor_i32(t0, t0, dest); + + /* extract the carries + * t0 = t0 ^ t1 + * = only the carries + */ + + tcg_gen_xor_i32(t0, t0, t1); + + /* generate 0x1 where there is no carry + * and for each 0x10, generate a 0x6 + */ + + tcg_gen_shri_i32(t0, t0, 3); + tcg_gen_not_i32(t0, t0); + tcg_gen_andi_i32(t0, t0, 0x22); + tcg_gen_add_i32(dest, t0, t0); + tcg_gen_add_i32(dest, dest, t0); + tcg_temp_free(t0); + + /* remove the exceding 0x6 + * for digits that have not generated a carry + */ + + tcg_gen_sub_i32(dest, t1, dest); + tcg_temp_free(t1); +} + +static void bcd_sub(TCGv dest, TCGv src) +{ + TCGv t0, t1, t2; + + /* dest10 = dest10 - src10 - X + * = bcd_add(dest + 1 - X, 0x199 - src) + */ + + /* t0 = 0x066 + (0x199 - src) */ + + t0 = tcg_temp_new(); + tcg_gen_subfi_i32(t0, 0x1ff, src); + + /* t1 = t0 + dest + 1 - X*/ + + t1 = tcg_temp_new(); + tcg_gen_add_i32(t1, t0, dest); + tcg_gen_addi_i32(t1, t1, 1); + tcg_gen_sub_i32(t1, t1, QREG_CC_X); + + /* t2 = t0 ^ dest */ + + t2 = tcg_temp_new(); + tcg_gen_xor_i32(t2, t0, dest); + + /* t0 = t1 ^ t2 */ + + tcg_gen_xor_i32(t0, t1, t2); + + /* t2 = ~t0 & 0x110 + * t0 = (t2 >> 2) | (t2 >> 3) + * + * to fit on 8bit operands, changed in: + * + * t2 = ~(t0 >> 3) & 0x22 + * t0 = t2 + t2 + * t0 = t0 + t2 + */ + + tcg_gen_shri_i32(t2, t0, 3); + tcg_gen_not_i32(t2, t2); + tcg_gen_andi_i32(t2, t2, 0x22); + tcg_gen_add_i32(t0, t2, t2); + tcg_gen_add_i32(t0, t0, t2); + tcg_temp_free(t2); + + /* return t1 - t0 */ + + tcg_gen_sub_i32(dest, t1, t0); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void bcd_flags(TCGv val) +{ + tcg_gen_andi_i32(QREG_CC_C, val, 0x0ff); + tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_C); + + tcg_gen_shri_i32(QREG_CC_C, val, 8); + tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1); + + tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C); +} + +DISAS_INSN(abcd_reg) +{ + TCGv src; + TCGv dest; + + gen_flush_flags(s); /* !Z is sticky */ + + src = gen_extend(DREG(insn, 0), OS_BYTE, 0); + dest = gen_extend(DREG(insn, 9), OS_BYTE, 0); + bcd_add(dest, src); + gen_partset_reg(OS_BYTE, DREG(insn, 9), dest); + + bcd_flags(dest); +} + +DISAS_INSN(abcd_mem) +{ + TCGv src, dest, addr; + + gen_flush_flags(s); /* !Z is sticky */ + + /* Indirect pre-decrement load (mode 4) */ + + src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE, + NULL_QREG, NULL, EA_LOADU); + dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, + NULL_QREG, &addr, EA_LOADU); + + bcd_add(dest, src); + + gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr, EA_STORE); + + bcd_flags(dest); +} + +DISAS_INSN(sbcd_reg) +{ + TCGv src, dest; + + gen_flush_flags(s); /* !Z is sticky */ + + src = gen_extend(DREG(insn, 0), OS_BYTE, 0); + dest = gen_extend(DREG(insn, 9), OS_BYTE, 0); + + bcd_sub(dest, src); + + gen_partset_reg(OS_BYTE, DREG(insn, 9), dest); + + bcd_flags(dest); +} + +DISAS_INSN(sbcd_mem) +{ + TCGv src, dest, addr; + + gen_flush_flags(s); /* !Z is sticky */ + + /* Indirect pre-decrement load (mode 4) */ + + src = gen_ea_mode(env, s, 4, REG(insn, 0), OS_BYTE, + NULL_QREG, NULL, EA_LOADU); + dest = gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, + NULL_QREG, &addr, EA_LOADU); + + bcd_sub(dest, src); + + gen_ea_mode(env, s, 4, REG(insn, 9), OS_BYTE, dest, &addr, EA_STORE); + + bcd_flags(dest); +} + +DISAS_INSN(nbcd) +{ + TCGv src, dest; + TCGv addr; + + gen_flush_flags(s); /* !Z is sticky */ + + SRC_EA(env, src, OS_BYTE, 0, &addr); + + dest = tcg_const_i32(0); + bcd_sub(dest, src); + + DEST_EA(env, insn, OS_BYTE, dest, &addr); + + bcd_flags(dest); + + tcg_temp_free(dest); +} + DISAS_INSN(addsub) { TCGv reg; @@ -1367,42 +1656,125 @@ static void gen_push(DisasContext *s, TCGv val) tcg_gen_subi_i32(tmp, QREG_SP, 4); gen_store(s, OS_LONG, tmp, val); tcg_gen_mov_i32(QREG_SP, tmp); + tcg_temp_free(tmp); +} + +static TCGv mreg(int reg) +{ + if (reg < 8) { + /* Dx */ + return cpu_dregs[reg]; + } + /* Ax */ + return cpu_aregs[reg & 7]; } DISAS_INSN(movem) { - TCGv addr; + TCGv addr, incr, tmp, r[16]; + int is_load = (insn & 0x0400) != 0; + int opsize = (insn & 0x40) != 0 ? OS_LONG : OS_WORD; + uint16_t mask = read_im16(env, s); + int mode = extract32(insn, 3, 3); + int reg0 = REG(insn, 0); int i; - uint16_t mask; - TCGv reg; - TCGv tmp; - int is_load; - mask = read_im16(env, s); - tmp = gen_lea(env, s, insn, OS_LONG); - if (IS_NULL_QREG(tmp)) { + tmp = cpu_aregs[reg0]; + + switch (mode) { + case 0: /* data register direct */ + case 1: /* addr register direct */ + do_addr_fault: gen_addr_fault(s); return; + + case 2: /* indirect */ + break; + + case 3: /* indirect post-increment */ + if (!is_load) { + /* post-increment is not allowed */ + goto do_addr_fault; + } + break; + + case 4: /* indirect pre-decrement */ + if (is_load) { + /* pre-decrement is not allowed */ + goto do_addr_fault; + } + /* We want a bare copy of the address reg, without any pre-decrement + adjustment, as gen_lea would provide. */ + break; + + default: + tmp = gen_lea_mode(env, s, mode, reg0, opsize); + if (IS_NULL_QREG(tmp)) { + goto do_addr_fault; + } + break; } + addr = tcg_temp_new(); tcg_gen_mov_i32(addr, tmp); - is_load = ((insn & 0x0400) != 0); - for (i = 0; i < 16; i++, mask >>= 1) { - if (mask & 1) { - if (i < 8) - reg = DREG(i, 0); - else - reg = AREG(i, 0); - if (is_load) { - tmp = gen_load(s, OS_LONG, addr, 0); - tcg_gen_mov_i32(reg, tmp); - } else { - gen_store(s, OS_LONG, addr, reg); + incr = tcg_const_i32(opsize_bytes(opsize)); + + if (is_load) { + /* memory to register */ + for (i = 0; i < 16; i++) { + if (mask & (1 << i)) { + r[i] = gen_load(s, opsize, addr, 1); + tcg_gen_add_i32(addr, addr, incr); + } + } + for (i = 0; i < 16; i++) { + if (mask & (1 << i)) { + tcg_gen_mov_i32(mreg(i), r[i]); + tcg_temp_free(r[i]); + } + } + if (mode == 3) { + /* post-increment: movem (An)+,X */ + tcg_gen_mov_i32(cpu_aregs[reg0], addr); + } + } else { + /* register to memory */ + if (mode == 4) { + /* pre-decrement: movem X,-(An) */ + for (i = 15; i >= 0; i--) { + if ((mask << i) & 0x8000) { + tcg_gen_sub_i32(addr, addr, incr); + if (reg0 + 8 == i && + m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) { + /* M68020+: if the addressing register is the + * register moved to memory, the value written + * is the initial value decremented by the size of + * the operation, regardless of how many actual + * stores have been performed until this point. + * M68000/M68010: the value is the initial value. + */ + tmp = tcg_temp_new(); + tcg_gen_sub_i32(tmp, cpu_aregs[reg0], incr); + gen_store(s, opsize, addr, tmp); + tcg_temp_free(tmp); + } else { + gen_store(s, opsize, addr, mreg(i)); + } + } + } + tcg_gen_mov_i32(cpu_aregs[reg0], addr); + } else { + for (i = 0; i < 16; i++) { + if (mask & (1 << i)) { + gen_store(s, opsize, addr, mreg(i)); + tcg_gen_add_i32(addr, addr, incr); + } } - if (mask != 1) - tcg_gen_addi_i32(addr, addr, 4); } } + + tcg_temp_free(incr); + tcg_temp_free(addr); } DISAS_INSN(bitop_im) @@ -1522,6 +1894,155 @@ DISAS_INSN(arith_im) tcg_temp_free(dest); } +DISAS_INSN(cas) +{ + int opsize; + TCGv addr; + uint16_t ext; + TCGv load; + TCGv cmp; + TCGMemOp opc; + + switch ((insn >> 9) & 3) { + case 1: + opsize = OS_BYTE; + opc = MO_SB; + break; + case 2: + opsize = OS_WORD; + opc = MO_TESW; + break; + case 3: + opsize = OS_LONG; + opc = MO_TESL; + break; + default: + g_assert_not_reached(); + } + opc |= MO_ALIGN; + + ext = read_im16(env, s); + + /* cas Dc,Du,<EA> */ + + addr = gen_lea(env, s, insn, opsize); + if (IS_NULL_QREG(addr)) { + gen_addr_fault(s); + return; + } + + cmp = gen_extend(DREG(ext, 0), opsize, 1); + + /* if <EA> == Dc then + * <EA> = Du + * Dc = <EA> (because <EA> == Dc) + * else + * Dc = <EA> + */ + + load = tcg_temp_new(); + tcg_gen_atomic_cmpxchg_i32(load, addr, cmp, DREG(ext, 6), + IS_USER(s), opc); + /* update flags before setting cmp to load */ + gen_update_cc_cmp(s, load, cmp, opsize); + gen_partset_reg(opsize, DREG(ext, 0), load); + + tcg_temp_free(load); +} + +DISAS_INSN(cas2w) +{ + uint16_t ext1, ext2; + TCGv addr1, addr2; + TCGv regs; + + /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */ + + ext1 = read_im16(env, s); + + if (ext1 & 0x8000) { + /* Address Register */ + addr1 = AREG(ext1, 12); + } else { + /* Data Register */ + addr1 = DREG(ext1, 12); + } + + ext2 = read_im16(env, s); + if (ext2 & 0x8000) { + /* Address Register */ + addr2 = AREG(ext2, 12); + } else { + /* Data Register */ + addr2 = DREG(ext2, 12); + } + + /* if (R1) == Dc1 && (R2) == Dc2 then + * (R1) = Du1 + * (R2) = Du2 + * else + * Dc1 = (R1) + * Dc2 = (R2) + */ + + regs = tcg_const_i32(REG(ext2, 6) | + (REG(ext1, 6) << 3) | + (REG(ext2, 0) << 6) | + (REG(ext1, 0) << 9)); + gen_helper_cas2w(cpu_env, regs, addr1, addr2); + tcg_temp_free(regs); + + /* Note that cas2w also assigned to env->cc_op. */ + s->cc_op = CC_OP_CMPW; + s->cc_op_synced = 1; +} + +DISAS_INSN(cas2l) +{ + uint16_t ext1, ext2; + TCGv addr1, addr2, regs; + + /* cas2 Dc1:Dc2,Du1:Du2,(Rn1):(Rn2) */ + + ext1 = read_im16(env, s); + + if (ext1 & 0x8000) { + /* Address Register */ + addr1 = AREG(ext1, 12); + } else { + /* Data Register */ + addr1 = DREG(ext1, 12); + } + + ext2 = read_im16(env, s); + if (ext2 & 0x8000) { + /* Address Register */ + addr2 = AREG(ext2, 12); + } else { + /* Data Register */ + addr2 = DREG(ext2, 12); + } + + /* if (R1) == Dc1 && (R2) == Dc2 then + * (R1) = Du1 + * (R2) = Du2 + * else + * Dc1 = (R1) + * Dc2 = (R2) + */ + + regs = tcg_const_i32(REG(ext2, 6) | + (REG(ext1, 6) << 3) | + (REG(ext2, 0) << 6) | + (REG(ext1, 0) << 9)); + gen_helper_cas2l(cpu_env, regs, addr1, addr2); + tcg_temp_free(regs); + + /* Note that cas2l also assigned to env->cc_op. */ + s->cc_op = CC_OP_CMPL; + s->cc_op_synced = 1; +} + DISAS_INSN(byterev) { TCGv reg; @@ -1626,10 +2147,14 @@ DISAS_INSN(lea) DISAS_INSN(clr) { int opsize; + TCGv zero; + + zero = tcg_const_i32(0); opsize = insn_opsize(insn); - DEST_EA(env, insn, opsize, tcg_const_i32(0), NULL); - gen_logic_cc(s, tcg_const_i32(0), opsize); + DEST_EA(env, insn, opsize, zero, NULL); + gen_logic_cc(s, zero, opsize); + tcg_temp_free(zero); } static TCGv gen_get_ccr(DisasContext *s) @@ -1735,6 +2260,8 @@ DISAS_INSN(swap) tcg_gen_shli_i32(src1, reg, 16); tcg_gen_shri_i32(src2, reg, 16); tcg_gen_or_i32(reg, src1, src2); + tcg_temp_free(src2); + tcg_temp_free(src1); gen_logic_cc(s, reg, OS_LONG); } @@ -1773,6 +2300,7 @@ DISAS_INSN(ext) else tcg_gen_mov_i32(reg, tmp); gen_logic_cc(s, tmp, OS_LONG); + tcg_temp_free(tmp); } DISAS_INSN(tst) @@ -1807,29 +2335,68 @@ DISAS_INSN(tas) gen_logic_cc(s, src1, OS_BYTE); tcg_gen_ori_i32(dest, src1, 0x80); DEST_EA(env, insn, OS_BYTE, dest, &addr); + tcg_temp_free(dest); } DISAS_INSN(mull) { uint16_t ext; - TCGv reg; TCGv src1; - TCGv dest; + int sign; - /* The upper 32 bits of the product are discarded, so - muls.l and mulu.l are functionally equivalent. */ ext = read_im16(env, s); - if (ext & 0x87ff) { - gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + + sign = ext & 0x800; + + if (ext & 0x400) { + if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + return; + } + + SRC_EA(env, src1, OS_LONG, 0, NULL); + + if (sign) { + tcg_gen_muls2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12)); + } else { + tcg_gen_mulu2_i32(QREG_CC_Z, QREG_CC_N, src1, DREG(ext, 12)); + } + /* if Dl == Dh, 68040 returns low word */ + tcg_gen_mov_i32(DREG(ext, 0), QREG_CC_N); + tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_Z); + tcg_gen_or_i32(QREG_CC_Z, QREG_CC_Z, QREG_CC_N); + + tcg_gen_movi_i32(QREG_CC_V, 0); + tcg_gen_movi_i32(QREG_CC_C, 0); + + set_cc_op(s, CC_OP_FLAGS); return; } - reg = DREG(ext, 12); SRC_EA(env, src1, OS_LONG, 0, NULL); - dest = tcg_temp_new(); - tcg_gen_mul_i32(dest, src1, reg); - tcg_gen_mov_i32(reg, dest); - /* Unlike m68k, coldfire always clears the overflow bit. */ - gen_logic_cc(s, dest, OS_LONG); + if (m68k_feature(s->env, M68K_FEATURE_M68000)) { + tcg_gen_movi_i32(QREG_CC_C, 0); + if (sign) { + tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12)); + /* QREG_CC_V is -(QREG_CC_V != (QREG_CC_N >> 31)) */ + tcg_gen_sari_i32(QREG_CC_Z, QREG_CC_N, 31); + tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_Z); + } else { + tcg_gen_mulu2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12)); + /* QREG_CC_V is -(QREG_CC_V != 0), use QREG_CC_C as 0 */ + tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_C); + } + tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V); + tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_N); + + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + + set_cc_op(s, CC_OP_FLAGS); + } else { + /* The upper 32 bits of the product are discarded, so + muls.l and mulu.l are functionally equivalent. */ + tcg_gen_mul_i32(DREG(ext, 12), src1, DREG(ext, 12)); + gen_logic_cc(s, DREG(ext, 12), OS_LONG); + } } static void gen_link(DisasContext *s, uint16_t insn, int32_t offset) @@ -1876,6 +2443,7 @@ DISAS_INSN(unlk) tmp = gen_load(s, OS_LONG, src, 0); tcg_gen_mov_i32(reg, tmp); tcg_gen_addi_i32(QREG_SP, src, 4); + tcg_temp_free(src); } DISAS_INSN(nop) @@ -1952,7 +2520,9 @@ DISAS_INSN(addsubq) } gen_update_cc_add(dest, val, opsize); } + tcg_temp_free(val); DEST_EA(env, insn, opsize, dest, &addr); + tcg_temp_free(dest); } DISAS_INSN(tpf) @@ -2005,11 +2575,8 @@ DISAS_INSN(branch) DISAS_INSN(moveq) { - uint32_t val; - - val = (int8_t)insn; - tcg_gen_movi_i32(DREG(insn, 9), val); - gen_logic_cc(s, tcg_const_i32(val), OS_LONG); + tcg_gen_movi_i32(DREG(insn, 9), (int8_t)insn); + gen_logic_cc(s, DREG(insn, 9), OS_LONG); } DISAS_INSN(mvzs) @@ -2049,6 +2616,7 @@ DISAS_INSN(or) gen_partset_reg(opsize, DREG(insn, 9), dest); } gen_logic_cc(s, dest, opsize); + tcg_temp_free(dest); } DISAS_INSN(suba) @@ -2143,6 +2711,7 @@ DISAS_INSN(mov3q) src = tcg_const_i32(val); gen_logic_cc(s, src, OS_LONG); DEST_EA(env, insn, OS_LONG, src, NULL); + tcg_temp_free(src); } DISAS_INSN(cmp) @@ -2173,6 +2742,21 @@ DISAS_INSN(cmpa) gen_update_cc_cmp(s, reg, src, OS_LONG); } +DISAS_INSN(cmpm) +{ + int opsize = insn_opsize(insn); + TCGv src, dst; + + /* Post-increment load (mode 3) from Ay. */ + src = gen_ea_mode(env, s, 3, REG(insn, 0), opsize, + NULL_QREG, NULL, EA_LOADS); + /* Post-increment load (mode 3) from Ax. */ + dst = gen_ea_mode(env, s, 3, REG(insn, 9), opsize, + NULL_QREG, NULL, EA_LOADS); + + gen_update_cc_cmp(s, dst, src, opsize); +} + DISAS_INSN(eor) { TCGv src; @@ -2187,6 +2771,7 @@ DISAS_INSN(eor) tcg_gen_xor_i32(dest, src, DREG(insn, 9)); gen_logic_cc(s, dest, opsize); DEST_EA(env, insn, opsize, dest, &addr); + tcg_temp_free(dest); } static void do_exg(TCGv reg1, TCGv reg2) @@ -2237,8 +2822,8 @@ DISAS_INSN(and) tcg_gen_and_i32(dest, src, reg); gen_partset_reg(opsize, reg, dest); } - tcg_temp_free(dest); gen_logic_cc(s, dest, opsize); + tcg_temp_free(dest); } DISAS_INSN(adda) @@ -2321,48 +2906,601 @@ DISAS_INSN(addx_mem) gen_store(s, opsize, addr_dest, QREG_CC_N); } -/* TODO: This could be implemented without helper functions. */ +static inline void shift_im(DisasContext *s, uint16_t insn, int opsize) +{ + int count = (insn >> 9) & 7; + int logical = insn & 8; + int left = insn & 0x100; + int bits = opsize_bytes(opsize) * 8; + TCGv reg = gen_extend(DREG(insn, 0), opsize, !logical); + + if (count == 0) { + count = 8; + } + + tcg_gen_movi_i32(QREG_CC_V, 0); + if (left) { + tcg_gen_shri_i32(QREG_CC_C, reg, bits - count); + tcg_gen_shli_i32(QREG_CC_N, reg, count); + + /* Note that ColdFire always clears V (done above), + while M68000 sets if the most significant bit is changed at + any time during the shift operation */ + if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) { + /* if shift count >= bits, V is (reg != 0) */ + if (count >= bits) { + tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, reg, QREG_CC_V); + } else { + TCGv t0 = tcg_temp_new(); + tcg_gen_sari_i32(QREG_CC_V, reg, bits - 1); + tcg_gen_sari_i32(t0, reg, bits - count - 1); + tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, t0); + tcg_temp_free(t0); + } + tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V); + } + } else { + tcg_gen_shri_i32(QREG_CC_C, reg, count - 1); + if (logical) { + tcg_gen_shri_i32(QREG_CC_N, reg, count); + } else { + tcg_gen_sari_i32(QREG_CC_N, reg, count); + } + } + + gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1); + tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1); + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C); + + gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N); + set_cc_op(s, CC_OP_FLAGS); +} + +static inline void shift_reg(DisasContext *s, uint16_t insn, int opsize) +{ + int logical = insn & 8; + int left = insn & 0x100; + int bits = opsize_bytes(opsize) * 8; + TCGv reg = gen_extend(DREG(insn, 0), opsize, !logical); + TCGv s32; + TCGv_i64 t64, s64; + + t64 = tcg_temp_new_i64(); + s64 = tcg_temp_new_i64(); + s32 = tcg_temp_new(); + + /* Note that m68k truncates the shift count modulo 64, not 32. + In addition, a 64-bit shift makes it easy to find "the last + bit shifted out", for the carry flag. */ + tcg_gen_andi_i32(s32, DREG(insn, 9), 63); + tcg_gen_extu_i32_i64(s64, s32); + tcg_gen_extu_i32_i64(t64, reg); + + /* Optimistically set V=0. Also used as a zero source below. */ + tcg_gen_movi_i32(QREG_CC_V, 0); + if (left) { + tcg_gen_shl_i64(t64, t64, s64); + + if (opsize == OS_LONG) { + tcg_gen_extr_i64_i32(QREG_CC_N, QREG_CC_C, t64); + /* Note that C=0 if shift count is 0, and we get that for free. */ + } else { + TCGv zero = tcg_const_i32(0); + tcg_gen_extrl_i64_i32(QREG_CC_N, t64); + tcg_gen_shri_i32(QREG_CC_C, QREG_CC_N, bits); + tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C, + s32, zero, zero, QREG_CC_C); + tcg_temp_free(zero); + } + tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1); + + /* X = C, but only if the shift count was non-zero. */ + tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V, + QREG_CC_C, QREG_CC_X); + + /* M68000 sets V if the most significant bit is changed at + * any time during the shift operation. Do this via creating + * an extension of the sign bit, comparing, and discarding + * the bits below the sign bit. I.e. + * int64_t s = (intN_t)reg; + * int64_t t = (int64_t)(intN_t)reg << count; + * V = ((s ^ t) & (-1 << (bits - 1))) != 0 + */ + if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) { + TCGv_i64 tt = tcg_const_i64(32); + /* if shift is greater than 32, use 32 */ + tcg_gen_movcond_i64(TCG_COND_GT, s64, s64, tt, tt, s64); + tcg_temp_free_i64(tt); + /* Sign extend the input to 64 bits; re-do the shift. */ + tcg_gen_ext_i32_i64(t64, reg); + tcg_gen_shl_i64(s64, t64, s64); + /* Clear all bits that are unchanged. */ + tcg_gen_xor_i64(t64, t64, s64); + /* Ignore the bits below the sign bit. */ + tcg_gen_andi_i64(t64, t64, -1ULL << (bits - 1)); + /* If any bits remain set, we have overflow. */ + tcg_gen_setcondi_i64(TCG_COND_NE, t64, t64, 0); + tcg_gen_extrl_i64_i32(QREG_CC_V, t64); + tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V); + } + } else { + tcg_gen_shli_i64(t64, t64, 32); + if (logical) { + tcg_gen_shr_i64(t64, t64, s64); + } else { + tcg_gen_sar_i64(t64, t64, s64); + } + tcg_gen_extr_i64_i32(QREG_CC_C, QREG_CC_N, t64); + + /* Note that C=0 if shift count is 0, and we get that for free. */ + tcg_gen_shri_i32(QREG_CC_C, QREG_CC_C, 31); + + /* X = C, but only if the shift count was non-zero. */ + tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V, + QREG_CC_C, QREG_CC_X); + } + gen_ext(QREG_CC_N, QREG_CC_N, opsize, 1); + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + + tcg_temp_free(s32); + tcg_temp_free_i64(s64); + tcg_temp_free_i64(t64); + + /* Write back the result. */ + gen_partset_reg(opsize, DREG(insn, 0), QREG_CC_N); + set_cc_op(s, CC_OP_FLAGS); +} + +DISAS_INSN(shift8_im) +{ + shift_im(s, insn, OS_BYTE); +} + +DISAS_INSN(shift16_im) +{ + shift_im(s, insn, OS_WORD); +} + DISAS_INSN(shift_im) { - TCGv reg; - int tmp; + shift_im(s, insn, OS_LONG); +} + +DISAS_INSN(shift8_reg) +{ + shift_reg(s, insn, OS_BYTE); +} + +DISAS_INSN(shift16_reg) +{ + shift_reg(s, insn, OS_WORD); +} + +DISAS_INSN(shift_reg) +{ + shift_reg(s, insn, OS_LONG); +} + +DISAS_INSN(shift_mem) +{ + int logical = insn & 8; + int left = insn & 0x100; + TCGv src; + TCGv addr; + + SRC_EA(env, src, OS_WORD, !logical, &addr); + tcg_gen_movi_i32(QREG_CC_V, 0); + if (left) { + tcg_gen_shri_i32(QREG_CC_C, src, 15); + tcg_gen_shli_i32(QREG_CC_N, src, 1); + + /* Note that ColdFire always clears V, + while M68000 sets if the most significant bit is changed at + any time during the shift operation */ + if (!logical && m68k_feature(s->env, M68K_FEATURE_M68000)) { + src = gen_extend(src, OS_WORD, 1); + tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, src); + } + } else { + tcg_gen_mov_i32(QREG_CC_C, src); + if (logical) { + tcg_gen_shri_i32(QREG_CC_N, src, 1); + } else { + tcg_gen_sari_i32(QREG_CC_N, src, 1); + } + } + + gen_ext(QREG_CC_N, QREG_CC_N, OS_WORD, 1); + tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1); + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C); + + DEST_EA(env, insn, OS_WORD, QREG_CC_N, &addr); + set_cc_op(s, CC_OP_FLAGS); +} + +static void rotate(TCGv reg, TCGv shift, int left, int size) +{ + switch (size) { + case 8: + /* Replicate the 8-bit input so that a 32-bit rotate works. */ + tcg_gen_ext8u_i32(reg, reg); + tcg_gen_muli_i32(reg, reg, 0x01010101); + goto do_long; + case 16: + /* Replicate the 16-bit input so that a 32-bit rotate works. */ + tcg_gen_deposit_i32(reg, reg, reg, 16, 16); + goto do_long; + do_long: + default: + if (left) { + tcg_gen_rotl_i32(reg, reg, shift); + } else { + tcg_gen_rotr_i32(reg, reg, shift); + } + } + + /* compute flags */ + + switch (size) { + case 8: + tcg_gen_ext8s_i32(reg, reg); + break; + case 16: + tcg_gen_ext16s_i32(reg, reg); + break; + default: + break; + } + + /* QREG_CC_X is not affected */ + + tcg_gen_mov_i32(QREG_CC_N, reg); + tcg_gen_mov_i32(QREG_CC_Z, reg); + + if (left) { + tcg_gen_andi_i32(QREG_CC_C, reg, 1); + } else { + tcg_gen_shri_i32(QREG_CC_C, reg, 31); + } + + tcg_gen_movi_i32(QREG_CC_V, 0); /* always cleared */ +} + +static void rotate_x_flags(TCGv reg, TCGv X, int size) +{ + switch (size) { + case 8: + tcg_gen_ext8s_i32(reg, reg); + break; + case 16: + tcg_gen_ext16s_i32(reg, reg); + break; + default: + break; + } + tcg_gen_mov_i32(QREG_CC_N, reg); + tcg_gen_mov_i32(QREG_CC_Z, reg); + tcg_gen_mov_i32(QREG_CC_X, X); + tcg_gen_mov_i32(QREG_CC_C, X); + tcg_gen_movi_i32(QREG_CC_V, 0); +} + +/* Result of rotate_x() is valid if 0 <= shift <= size */ +static TCGv rotate_x(TCGv reg, TCGv shift, int left, int size) +{ + TCGv X, shl, shr, shx, sz, zero; + + sz = tcg_const_i32(size); + + shr = tcg_temp_new(); + shl = tcg_temp_new(); + shx = tcg_temp_new(); + if (left) { + tcg_gen_mov_i32(shl, shift); /* shl = shift */ + tcg_gen_movi_i32(shr, size + 1); + tcg_gen_sub_i32(shr, shr, shift); /* shr = size + 1 - shift */ + tcg_gen_subi_i32(shx, shift, 1); /* shx = shift - 1 */ + /* shx = shx < 0 ? size : shx; */ + zero = tcg_const_i32(0); + tcg_gen_movcond_i32(TCG_COND_LT, shx, shx, zero, sz, shx); + tcg_temp_free(zero); + } else { + tcg_gen_mov_i32(shr, shift); /* shr = shift */ + tcg_gen_movi_i32(shl, size + 1); + tcg_gen_sub_i32(shl, shl, shift); /* shl = size + 1 - shift */ + tcg_gen_sub_i32(shx, sz, shift); /* shx = size - shift */ + } + + /* reg = (reg << shl) | (reg >> shr) | (x << shx); */ + + tcg_gen_shl_i32(shl, reg, shl); + tcg_gen_shr_i32(shr, reg, shr); + tcg_gen_or_i32(reg, shl, shr); + tcg_temp_free(shl); + tcg_temp_free(shr); + tcg_gen_shl_i32(shx, QREG_CC_X, shx); + tcg_gen_or_i32(reg, reg, shx); + tcg_temp_free(shx); + + /* X = (reg >> size) & 1 */ + + X = tcg_temp_new(); + tcg_gen_shr_i32(X, reg, sz); + tcg_gen_andi_i32(X, X, 1); + tcg_temp_free(sz); + + return X; +} + +/* Result of rotate32_x() is valid if 0 <= shift < 33 */ +static TCGv rotate32_x(TCGv reg, TCGv shift, int left) +{ + TCGv_i64 t0, shift64; + TCGv X, lo, hi, zero; + + shift64 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(shift64, shift); + + t0 = tcg_temp_new_i64(); + + X = tcg_temp_new(); + lo = tcg_temp_new(); + hi = tcg_temp_new(); + + if (left) { + /* create [reg:X:..] */ + + tcg_gen_shli_i32(lo, QREG_CC_X, 31); + tcg_gen_concat_i32_i64(t0, lo, reg); + + /* rotate */ + + tcg_gen_rotl_i64(t0, t0, shift64); + tcg_temp_free_i64(shift64); + + /* result is [reg:..:reg:X] */ + + tcg_gen_extr_i64_i32(lo, hi, t0); + tcg_gen_andi_i32(X, lo, 1); + + tcg_gen_shri_i32(lo, lo, 1); + } else { + /* create [..:X:reg] */ + + tcg_gen_concat_i32_i64(t0, reg, QREG_CC_X); + + tcg_gen_rotr_i64(t0, t0, shift64); + tcg_temp_free_i64(shift64); + + /* result is value: [X:reg:..:reg] */ + + tcg_gen_extr_i64_i32(lo, hi, t0); + + /* extract X */ + + tcg_gen_shri_i32(X, hi, 31); + + /* extract result */ + + tcg_gen_shli_i32(hi, hi, 1); + } + tcg_temp_free_i64(t0); + tcg_gen_or_i32(lo, lo, hi); + tcg_temp_free(hi); + + /* if shift == 0, register and X are not affected */ + + zero = tcg_const_i32(0); + tcg_gen_movcond_i32(TCG_COND_EQ, X, shift, zero, QREG_CC_X, X); + tcg_gen_movcond_i32(TCG_COND_EQ, reg, shift, zero, reg, lo); + tcg_temp_free(zero); + tcg_temp_free(lo); + + return X; +} + +DISAS_INSN(rotate_im) +{ TCGv shift; + int tmp; + int left = (insn & 0x100); + + tmp = (insn >> 9) & 7; + if (tmp == 0) { + tmp = 8; + } + + shift = tcg_const_i32(tmp); + if (insn & 8) { + rotate(DREG(insn, 0), shift, left, 32); + } else { + TCGv X = rotate32_x(DREG(insn, 0), shift, left); + rotate_x_flags(DREG(insn, 0), X, 32); + tcg_temp_free(X); + } + tcg_temp_free(shift); set_cc_op(s, CC_OP_FLAGS); +} + +DISAS_INSN(rotate8_im) +{ + int left = (insn & 0x100); + TCGv reg; + TCGv shift; + int tmp; + + reg = gen_extend(DREG(insn, 0), OS_BYTE, 0); - reg = DREG(insn, 0); tmp = (insn >> 9) & 7; - if (tmp == 0) + if (tmp == 0) { tmp = 8; + } + shift = tcg_const_i32(tmp); - /* No need to flush flags becuse we know we will set C flag. */ - if (insn & 0x100) { - gen_helper_shl_cc(reg, cpu_env, reg, shift); + if (insn & 8) { + rotate(reg, shift, left, 8); } else { - if (insn & 8) { - gen_helper_shr_cc(reg, cpu_env, reg, shift); - } else { - gen_helper_sar_cc(reg, cpu_env, reg, shift); - } + TCGv X = rotate_x(reg, shift, left, 8); + rotate_x_flags(reg, X, 8); + tcg_temp_free(X); } + tcg_temp_free(shift); + gen_partset_reg(OS_BYTE, DREG(insn, 0), reg); + set_cc_op(s, CC_OP_FLAGS); } -DISAS_INSN(shift_reg) +DISAS_INSN(rotate16_im) { + int left = (insn & 0x100); TCGv reg; TCGv shift; + int tmp; + + reg = gen_extend(DREG(insn, 0), OS_WORD, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) { + tmp = 8; + } + + shift = tcg_const_i32(tmp); + if (insn & 8) { + rotate(reg, shift, left, 16); + } else { + TCGv X = rotate_x(reg, shift, left, 16); + rotate_x_flags(reg, X, 16); + tcg_temp_free(X); + } + tcg_temp_free(shift); + gen_partset_reg(OS_WORD, DREG(insn, 0), reg); + set_cc_op(s, CC_OP_FLAGS); +} + +DISAS_INSN(rotate_reg) +{ + TCGv reg; + TCGv src; + TCGv t0, t1; + int left = (insn & 0x100); reg = DREG(insn, 0); - shift = DREG(insn, 9); - if (insn & 0x100) { - gen_helper_shl_cc(reg, cpu_env, reg, shift); + src = DREG(insn, 9); + /* shift in [0..63] */ + t0 = tcg_temp_new(); + tcg_gen_andi_i32(t0, src, 63); + t1 = tcg_temp_new_i32(); + if (insn & 8) { + tcg_gen_andi_i32(t1, src, 31); + rotate(reg, t1, left, 32); + /* if shift == 0, clear C */ + tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C, + t0, QREG_CC_V /* 0 */, + QREG_CC_V /* 0 */, QREG_CC_C); } else { - if (insn & 8) { - gen_helper_shr_cc(reg, cpu_env, reg, shift); - } else { - gen_helper_sar_cc(reg, cpu_env, reg, shift); - } + TCGv X; + /* modulo 33 */ + tcg_gen_movi_i32(t1, 33); + tcg_gen_remu_i32(t1, t0, t1); + X = rotate32_x(DREG(insn, 0), t1, left); + rotate_x_flags(DREG(insn, 0), X, 32); + tcg_temp_free(X); + } + tcg_temp_free(t1); + tcg_temp_free(t0); + set_cc_op(s, CC_OP_FLAGS); +} + +DISAS_INSN(rotate8_reg) +{ + TCGv reg; + TCGv src; + TCGv t0, t1; + int left = (insn & 0x100); + + reg = gen_extend(DREG(insn, 0), OS_BYTE, 0); + src = DREG(insn, 9); + /* shift in [0..63] */ + t0 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t0, src, 63); + t1 = tcg_temp_new_i32(); + if (insn & 8) { + tcg_gen_andi_i32(t1, src, 7); + rotate(reg, t1, left, 8); + /* if shift == 0, clear C */ + tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C, + t0, QREG_CC_V /* 0 */, + QREG_CC_V /* 0 */, QREG_CC_C); + } else { + TCGv X; + /* modulo 9 */ + tcg_gen_movi_i32(t1, 9); + tcg_gen_remu_i32(t1, t0, t1); + X = rotate_x(reg, t1, left, 8); + rotate_x_flags(reg, X, 8); + tcg_temp_free(X); + } + tcg_temp_free(t1); + tcg_temp_free(t0); + gen_partset_reg(OS_BYTE, DREG(insn, 0), reg); + set_cc_op(s, CC_OP_FLAGS); +} + +DISAS_INSN(rotate16_reg) +{ + TCGv reg; + TCGv src; + TCGv t0, t1; + int left = (insn & 0x100); + + reg = gen_extend(DREG(insn, 0), OS_WORD, 0); + src = DREG(insn, 9); + /* shift in [0..63] */ + t0 = tcg_temp_new_i32(); + tcg_gen_andi_i32(t0, src, 63); + t1 = tcg_temp_new_i32(); + if (insn & 8) { + tcg_gen_andi_i32(t1, src, 15); + rotate(reg, t1, left, 16); + /* if shift == 0, clear C */ + tcg_gen_movcond_i32(TCG_COND_EQ, QREG_CC_C, + t0, QREG_CC_V /* 0 */, + QREG_CC_V /* 0 */, QREG_CC_C); + } else { + TCGv X; + /* modulo 17 */ + tcg_gen_movi_i32(t1, 17); + tcg_gen_remu_i32(t1, t0, t1); + X = rotate_x(reg, t1, left, 16); + rotate_x_flags(reg, X, 16); + tcg_temp_free(X); + } + tcg_temp_free(t1); + tcg_temp_free(t0); + gen_partset_reg(OS_WORD, DREG(insn, 0), reg); + set_cc_op(s, CC_OP_FLAGS); +} + +DISAS_INSN(rotate_mem) +{ + TCGv src; + TCGv addr; + TCGv shift; + int left = (insn & 0x100); + + SRC_EA(env, src, OS_WORD, 0, &addr); + + shift = tcg_const_i32(1); + if (insn & 0x0200) { + rotate(src, shift, left, 16); + } else { + TCGv X = rotate_x(src, shift, left, 16); + rotate_x_flags(src, X, 16); + tcg_temp_free(X); } + tcg_temp_free(shift); + DEST_EA(env, insn, OS_WORD, src, &addr); set_cc_op(s, CC_OP_FLAGS); } @@ -3312,6 +4450,11 @@ void register_m68k_insns (CPUM68KState *env) BASE(bitop_im, 08c0, ffc0); INSN(arith_im, 0a80, fff8, CF_ISA_A); INSN(arith_im, 0a00, ff00, M68000); + INSN(cas, 0ac0, ffc0, CAS); + INSN(cas, 0cc0, ffc0, CAS); + INSN(cas, 0ec0, ffc0, CAS); + INSN(cas2w, 0cfc, ffff, CAS); + INSN(cas2l, 0efc, ffff, CAS); BASE(move, 1000, f000); BASE(move, 2000, f000); BASE(move, 3000, f000); @@ -3334,11 +4477,14 @@ void register_m68k_insns (CPUM68KState *env) INSN(not, 4600, ff00, M68000); INSN(undef, 46c0, ffc0, M68000); INSN(move_to_sr, 46c0, ffc0, CF_ISA_A); + INSN(nbcd, 4800, ffc0, M68000); INSN(linkl, 4808, fff8, M68000); BASE(pea, 4840, ffc0); BASE(swap, 4840, fff8); INSN(bkpt, 4848, fff8, BKPT); - BASE(movem, 48c0, fbc0); + INSN(movem, 48d0, fbf8, CF_ISA_A); + INSN(movem, 48e8, fbf8, CF_ISA_A); + INSN(movem, 4880, fb80, M68000); BASE(ext, 4880, fff8); BASE(ext, 48c0, fff8); BASE(ext, 49c0, fff8); @@ -3385,6 +4531,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(mvzs, 7100, f100, CF_ISA_B); BASE(or, 8000, f000); BASE(divw, 80c0, f0c0); + INSN(sbcd_reg, 8100, f1f8, M68000); + INSN(sbcd_mem, 8108, f1f8, M68000); BASE(addsub, 9000, f000); INSN(undef, 90c0, f0c0, CF_ISA_A); INSN(subx_reg, 9180, f1f8, CF_ISA_A); @@ -3414,6 +4562,7 @@ void register_m68k_insns (CPUM68KState *env) INSN(cmpa, b1c0, f1c0, CF_ISA_A); INSN(cmp, b000, f100, M68000); INSN(eor, b100, f100, M68000); + INSN(cmpm, b108, f138, M68000); INSN(cmpa, b0c0, f0c0, M68000); INSN(eor, b180, f1c0, CF_ISA_A); BASE(and, c000, f000); @@ -3421,6 +4570,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(exg_aa, c148, f1f8, M68000); INSN(exg_da, c188, f1f8, M68000); BASE(mulw, c0c0, f0c0); + INSN(abcd_reg, c100, f1f8, M68000); + INSN(abcd_mem, c108, f1f8, M68000); BASE(addsub, d000, f000); INSN(undef, d0c0, f0c0, CF_ISA_A); INSN(addx_reg, d180, f1f8, CF_ISA_A); @@ -3430,6 +4581,20 @@ void register_m68k_insns (CPUM68KState *env) INSN(adda, d0c0, f0c0, M68000); INSN(shift_im, e080, f0f0, CF_ISA_A); INSN(shift_reg, e0a0, f0f0, CF_ISA_A); + INSN(shift8_im, e000, f0f0, M68000); + INSN(shift16_im, e040, f0f0, M68000); + INSN(shift_im, e080, f0f0, M68000); + INSN(shift8_reg, e020, f0f0, M68000); + INSN(shift16_reg, e060, f0f0, M68000); + INSN(shift_reg, e0a0, f0f0, M68000); + INSN(shift_mem, e0c0, fcc0, M68000); + INSN(rotate_im, e090, f0f0, M68000); + INSN(rotate8_im, e010, f0f0, M68000); + INSN(rotate16_im, e050, f0f0, M68000); + INSN(rotate_reg, e0b0, f0f0, M68000); + INSN(rotate8_reg, e030, f0f0, M68000); + INSN(rotate16_reg, e070, f0f0, M68000); + INSN(rotate_mem, e4c0, fcc0, M68000); INSN(undef_fpu, f000, f000, CF_ISA_A); INSN(fpu, f200, ffc0, CF_FPU); INSN(fbcc, f280, ffc0, CF_FPU); @@ -3446,11 +4611,9 @@ void register_m68k_insns (CPUM68KState *env) write back the result to memory before setting the condition codes. */ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) { - uint16_t insn; - - insn = read_im16(env, s); - + uint16_t insn = read_im16(env, s); opcode_table[insn](env, s, insn); + do_writebacks(s); } /* generate intermediate code for basic block 'tb'. */ @@ -3478,6 +4641,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb) dc->fpcr = env->fpcr; dc->user = (env->sr & SR_S) == 0; dc->done_mac = 0; + dc->writeback_mask = 0; num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) { diff --git a/target-microblaze/Makefile.objs b/target/microblaze/Makefile.objs index f3d7b44c89..f3d7b44c89 100644 --- a/target-microblaze/Makefile.objs +++ b/target/microblaze/Makefile.objs diff --git a/target-microblaze/cpu-qom.h b/target/microblaze/cpu-qom.h index 1a61db77d0..1a61db77d0 100644 --- a/target-microblaze/cpu-qom.h +++ b/target/microblaze/cpu-qom.h diff --git a/target-microblaze/cpu.c b/target/microblaze/cpu.c index 389c7b691e..389c7b691e 100644 --- a/target-microblaze/cpu.c +++ b/target/microblaze/cpu.c diff --git a/target-microblaze/cpu.h b/target/microblaze/cpu.h index beb75ffd26..beb75ffd26 100644 --- a/target-microblaze/cpu.h +++ b/target/microblaze/cpu.h diff --git a/target-microblaze/gdbstub.c b/target/microblaze/gdbstub.c index 7fb076c2e9..7fb076c2e9 100644 --- a/target-microblaze/gdbstub.c +++ b/target/microblaze/gdbstub.c diff --git a/target-microblaze/helper.c b/target/microblaze/helper.c index da394d1dfc..da394d1dfc 100644 --- a/target-microblaze/helper.c +++ b/target/microblaze/helper.c diff --git a/target-microblaze/helper.h b/target/microblaze/helper.h index bd13826de0..bd13826de0 100644 --- a/target-microblaze/helper.h +++ b/target/microblaze/helper.h diff --git a/target-microblaze/microblaze-decode.h b/target/microblaze/microblaze-decode.h index 401319ed46..401319ed46 100644 --- a/target-microblaze/microblaze-decode.h +++ b/target/microblaze/microblaze-decode.h diff --git a/target-microblaze/mmu.c b/target/microblaze/mmu.c index a22a496ebb..a22a496ebb 100644 --- a/target-microblaze/mmu.c +++ b/target/microblaze/mmu.c diff --git a/target-microblaze/mmu.h b/target/microblaze/mmu.h index 3b7a9983d5..3b7a9983d5 100644 --- a/target-microblaze/mmu.h +++ b/target/microblaze/mmu.h diff --git a/target-microblaze/op_helper.c b/target/microblaze/op_helper.c index 4a856e6204..4a856e6204 100644 --- a/target-microblaze/op_helper.c +++ b/target/microblaze/op_helper.c diff --git a/target-microblaze/translate.c b/target/microblaze/translate.c index de2090ac71..de2090ac71 100644 --- a/target-microblaze/translate.c +++ b/target/microblaze/translate.c diff --git a/target-mips/Makefile.objs b/target/mips/Makefile.objs index bc5ed8511f..bc5ed8511f 100644 --- a/target-mips/Makefile.objs +++ b/target/mips/Makefile.objs diff --git a/target-mips/TODO b/target/mips/TODO index 1d782d8027..1d782d8027 100644 --- a/target-mips/TODO +++ b/target/mips/TODO diff --git a/target-mips/cpu-qom.h b/target/mips/cpu-qom.h index 3f5bf23823..3f5bf23823 100644 --- a/target-mips/cpu-qom.h +++ b/target/mips/cpu-qom.h diff --git a/target-mips/cpu.c b/target/mips/cpu.c index 65ca607f88..65ca607f88 100644 --- a/target-mips/cpu.c +++ b/target/mips/cpu.c diff --git a/target-mips/cpu.h b/target/mips/cpu.h index 5182dc74ff..5182dc74ff 100644 --- a/target-mips/cpu.h +++ b/target/mips/cpu.h diff --git a/target-mips/dsp_helper.c b/target/mips/dsp_helper.c index dc707934ea..dc707934ea 100644 --- a/target-mips/dsp_helper.c +++ b/target/mips/dsp_helper.c diff --git a/target-mips/gdbstub.c b/target/mips/gdbstub.c index 7c682289c2..7c682289c2 100644 --- a/target-mips/gdbstub.c +++ b/target/mips/gdbstub.c diff --git a/target-mips/helper.c b/target/mips/helper.c index c864b15b97..c864b15b97 100644 --- a/target-mips/helper.c +++ b/target/mips/helper.c diff --git a/target-mips/helper.h b/target/mips/helper.h index 666936c81b..666936c81b 100644 --- a/target-mips/helper.h +++ b/target/mips/helper.h diff --git a/target-mips/kvm.c b/target/mips/kvm.c index dcf5fbba0c..dcf5fbba0c 100644 --- a/target-mips/kvm.c +++ b/target/mips/kvm.c diff --git a/target-mips/kvm_mips.h b/target/mips/kvm_mips.h index ae957f37f0..ae957f37f0 100644 --- a/target-mips/kvm_mips.h +++ b/target/mips/kvm_mips.h diff --git a/target-mips/lmi_helper.c b/target/mips/lmi_helper.c index fb1245b39d..fb1245b39d 100644 --- a/target-mips/lmi_helper.c +++ b/target/mips/lmi_helper.c diff --git a/target-mips/machine.c b/target/mips/machine.c index d20d948457..d20d948457 100644 --- a/target-mips/machine.c +++ b/target/mips/machine.c diff --git a/target-mips/mips-defs.h b/target/mips/mips-defs.h index 047554ee45..047554ee45 100644 --- a/target-mips/mips-defs.h +++ b/target/mips/mips-defs.h diff --git a/target-mips/mips-semi.c b/target/mips/mips-semi.c index a7aefbaefc..a7aefbaefc 100644 --- a/target-mips/mips-semi.c +++ b/target/mips/mips-semi.c diff --git a/target-mips/msa_helper.c b/target/mips/msa_helper.c index 1fdb0d9792..1fdb0d9792 100644 --- a/target-mips/msa_helper.c +++ b/target/mips/msa_helper.c diff --git a/target-mips/op_helper.c b/target/mips/op_helper.c index 7af4c2f084..7af4c2f084 100644 --- a/target-mips/op_helper.c +++ b/target/mips/op_helper.c diff --git a/target-mips/translate.c b/target/mips/translate.c index 57b824ff2d..57b824ff2d 100644 --- a/target-mips/translate.c +++ b/target/mips/translate.c diff --git a/target-mips/translate_init.c b/target/mips/translate_init.c index 6ae23e476f..6ae23e476f 100644 --- a/target-mips/translate_init.c +++ b/target/mips/translate_init.c diff --git a/target-moxie/Makefile.objs b/target/moxie/Makefile.objs index 6381d4d636..6381d4d636 100644 --- a/target-moxie/Makefile.objs +++ b/target/moxie/Makefile.objs diff --git a/target-moxie/cpu.c b/target/moxie/cpu.c index b0be4a7551..b0be4a7551 100644 --- a/target-moxie/cpu.c +++ b/target/moxie/cpu.c diff --git a/target-moxie/cpu.h b/target/moxie/cpu.h index 3e880facf4..3e880facf4 100644 --- a/target-moxie/cpu.h +++ b/target/moxie/cpu.h diff --git a/target-moxie/helper.c b/target/moxie/helper.c index 330299f5a7..330299f5a7 100644 --- a/target-moxie/helper.c +++ b/target/moxie/helper.c diff --git a/target-moxie/helper.h b/target/moxie/helper.h index d94ef7a17e..d94ef7a17e 100644 --- a/target-moxie/helper.h +++ b/target/moxie/helper.h diff --git a/target-moxie/machine.c b/target/moxie/machine.c index 282dcd869f..282dcd869f 100644 --- a/target-moxie/machine.c +++ b/target/moxie/machine.c diff --git a/target-moxie/machine.h b/target/moxie/machine.h index a1b72907ae..a1b72907ae 100644 --- a/target-moxie/machine.h +++ b/target/moxie/machine.h diff --git a/target-moxie/mmu.c b/target/moxie/mmu.c index 9203330b3b..9203330b3b 100644 --- a/target-moxie/mmu.c +++ b/target/moxie/mmu.c diff --git a/target-moxie/mmu.h b/target/moxie/mmu.h index 284a44d18e..284a44d18e 100644 --- a/target-moxie/mmu.h +++ b/target/moxie/mmu.h diff --git a/target-moxie/translate.c b/target/moxie/translate.c index 0660b44c08..0660b44c08 100644 --- a/target-moxie/translate.c +++ b/target/moxie/translate.c diff --git a/target-openrisc/Makefile.objs b/target/openrisc/Makefile.objs index 397d01650e..397d01650e 100644 --- a/target-openrisc/Makefile.objs +++ b/target/openrisc/Makefile.objs diff --git a/target-openrisc/cpu.c b/target/openrisc/cpu.c index 698e87bb25..698e87bb25 100644 --- a/target-openrisc/cpu.c +++ b/target/openrisc/cpu.c diff --git a/target-openrisc/cpu.h b/target/openrisc/cpu.h index aaf153579a..aaf153579a 100644 --- a/target-openrisc/cpu.h +++ b/target/openrisc/cpu.h diff --git a/target-openrisc/exception.c b/target/openrisc/exception.c index 49470be051..49470be051 100644 --- a/target-openrisc/exception.c +++ b/target/openrisc/exception.c diff --git a/target-openrisc/exception.h b/target/openrisc/exception.h index 4ec56b4653..4ec56b4653 100644 --- a/target-openrisc/exception.h +++ b/target/openrisc/exception.h diff --git a/target-openrisc/exception_helper.c b/target/openrisc/exception_helper.c index 329a9e400b..329a9e400b 100644 --- a/target-openrisc/exception_helper.c +++ b/target/openrisc/exception_helper.c diff --git a/target-openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index c54404b80d..c54404b80d 100644 --- a/target-openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c diff --git a/target-openrisc/gdbstub.c b/target/openrisc/gdbstub.c index cb16e76358..cb16e76358 100644 --- a/target-openrisc/gdbstub.c +++ b/target/openrisc/gdbstub.c diff --git a/target-openrisc/helper.h b/target/openrisc/helper.h index f53fa21344..f53fa21344 100644 --- a/target-openrisc/helper.h +++ b/target/openrisc/helper.h diff --git a/target-openrisc/int_helper.c b/target/openrisc/int_helper.c index 4d1f958901..4d1f958901 100644 --- a/target-openrisc/int_helper.c +++ b/target/openrisc/int_helper.c diff --git a/target-openrisc/interrupt.c b/target/openrisc/interrupt.c index 5fe3f11ffc..5fe3f11ffc 100644 --- a/target-openrisc/interrupt.c +++ b/target/openrisc/interrupt.c diff --git a/target-openrisc/interrupt_helper.c b/target/openrisc/interrupt_helper.c index 116f9109a7..116f9109a7 100644 --- a/target-openrisc/interrupt_helper.c +++ b/target/openrisc/interrupt_helper.c diff --git a/target-openrisc/machine.c b/target/openrisc/machine.c index 17b0c77d6c..17b0c77d6c 100644 --- a/target-openrisc/machine.c +++ b/target/openrisc/machine.c diff --git a/target-openrisc/mmu.c b/target/openrisc/mmu.c index 505dcdcdc8..505dcdcdc8 100644 --- a/target-openrisc/mmu.c +++ b/target/openrisc/mmu.c diff --git a/target-openrisc/mmu_helper.c b/target/openrisc/mmu_helper.c index a44d0aa51a..a44d0aa51a 100644 --- a/target-openrisc/mmu_helper.c +++ b/target/openrisc/mmu_helper.c diff --git a/target-openrisc/sys_helper.c b/target/openrisc/sys_helper.c index a719e452be..a719e452be 100644 --- a/target-openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c diff --git a/target-openrisc/translate.c b/target/openrisc/translate.c index 229361aed1..229361aed1 100644 --- a/target-openrisc/translate.c +++ b/target/openrisc/translate.c diff --git a/target-ppc/Makefile.objs b/target/ppc/Makefile.objs index e667e69701..e667e69701 100644 --- a/target-ppc/Makefile.objs +++ b/target/ppc/Makefile.objs diff --git a/target-ppc/STATUS b/target/ppc/STATUS index a4d48a7ca2..a4d48a7ca2 100644 --- a/target-ppc/STATUS +++ b/target/ppc/STATUS diff --git a/target-ppc/arch_dump.c b/target/ppc/arch_dump.c index 40282a1f50..40282a1f50 100644 --- a/target-ppc/arch_dump.c +++ b/target/ppc/arch_dump.c diff --git a/target-ppc/cpu-models.c b/target/ppc/cpu-models.c index 506dee1ee8..506dee1ee8 100644 --- a/target-ppc/cpu-models.c +++ b/target/ppc/cpu-models.c diff --git a/target-ppc/cpu-models.h b/target/ppc/cpu-models.h index aafbbd7d5d..aafbbd7d5d 100644 --- a/target-ppc/cpu-models.h +++ b/target/ppc/cpu-models.h diff --git a/target-ppc/cpu-qom.h b/target/ppc/cpu-qom.h index d46c31a15d..d46c31a15d 100644 --- a/target-ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h diff --git a/target-ppc/cpu.h b/target/ppc/cpu.h index 2a50c43689..2a50c43689 100644 --- a/target-ppc/cpu.h +++ b/target/ppc/cpu.h diff --git a/target-ppc/dfp_helper.c b/target/ppc/dfp_helper.c index 9164fe701b..9164fe701b 100644 --- a/target-ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c diff --git a/target-ppc/excp_helper.c b/target/ppc/excp_helper.c index 93369d4fe5..93369d4fe5 100644 --- a/target-ppc/excp_helper.c +++ b/target/ppc/excp_helper.c diff --git a/target-ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 8a389e19af..8a389e19af 100644 --- a/target-ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c diff --git a/target-ppc/gdbstub.c b/target/ppc/gdbstub.c index 7a338136a8..7a338136a8 100644 --- a/target-ppc/gdbstub.c +++ b/target/ppc/gdbstub.c diff --git a/target-ppc/helper.h b/target/ppc/helper.h index da00f0ab49..da00f0ab49 100644 --- a/target-ppc/helper.h +++ b/target/ppc/helper.h diff --git a/target-ppc/helper_regs.h b/target/ppc/helper_regs.h index 62138163a5..62138163a5 100644 --- a/target-ppc/helper_regs.h +++ b/target/ppc/helper_regs.h diff --git a/target-ppc/int_helper.c b/target/ppc/int_helper.c index 2d57c9a1c2..2d57c9a1c2 100644 --- a/target-ppc/int_helper.c +++ b/target/ppc/int_helper.c diff --git a/target-ppc/internal.h b/target/ppc/internal.h index 1ff4896c45..1ff4896c45 100644 --- a/target-ppc/internal.h +++ b/target/ppc/internal.h diff --git a/target-ppc/kvm-stub.c b/target/ppc/kvm-stub.c index efeafca1df..efeafca1df 100644 --- a/target-ppc/kvm-stub.c +++ b/target/ppc/kvm-stub.c diff --git a/target-ppc/kvm.c b/target/ppc/kvm.c index 9c4834c4fc..9c4834c4fc 100644 --- a/target-ppc/kvm.c +++ b/target/ppc/kvm.c diff --git a/target-ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index bd1d78bfbe..bd1d78bfbe 100644 --- a/target-ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h diff --git a/target-ppc/machine.c b/target/ppc/machine.c index 18c16d2512..18c16d2512 100644 --- a/target-ppc/machine.c +++ b/target/ppc/machine.c diff --git a/target-ppc/mem_helper.c b/target/ppc/mem_helper.c index 1ab8a6eab4..1ab8a6eab4 100644 --- a/target-ppc/mem_helper.c +++ b/target/ppc/mem_helper.c diff --git a/target-ppc/mfrom_table.c b/target/ppc/mfrom_table.c index 6a1fa375c9..6a1fa375c9 100644 --- a/target-ppc/mfrom_table.c +++ b/target/ppc/mfrom_table.c diff --git a/target-ppc/mfrom_table_gen.c b/target/ppc/mfrom_table_gen.c index 631791808e..631791808e 100644 --- a/target-ppc/mfrom_table_gen.c +++ b/target/ppc/mfrom_table_gen.c diff --git a/target-ppc/misc_helper.c b/target/ppc/misc_helper.c index 1e6e705a4e..1e6e705a4e 100644 --- a/target-ppc/misc_helper.c +++ b/target/ppc/misc_helper.c diff --git a/target-ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c index 29bace622a..29bace622a 100644 --- a/target-ppc/mmu-hash32.c +++ b/target/ppc/mmu-hash32.c diff --git a/target-ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h index 5b9fb08d1a..5b9fb08d1a 100644 --- a/target-ppc/mmu-hash32.h +++ b/target/ppc/mmu-hash32.h diff --git a/target-ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index fdb7a787bf..fdb7a787bf 100644 --- a/target-ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c diff --git a/target-ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index ab5d347a53..ab5d347a53 100644 --- a/target-ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h diff --git a/target-ppc/mmu_helper.c b/target/ppc/mmu_helper.c index d09fc0a85f..d09fc0a85f 100644 --- a/target-ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c diff --git a/target-ppc/monitor.c b/target/ppc/monitor.c index c2d0806dd1..c2d0806dd1 100644 --- a/target-ppc/monitor.c +++ b/target/ppc/monitor.c diff --git a/target-ppc/timebase_helper.c b/target/ppc/timebase_helper.c index 73363e08ae..73363e08ae 100644 --- a/target-ppc/timebase_helper.c +++ b/target/ppc/timebase_helper.c diff --git a/target-ppc/trace-events b/target/ppc/trace-events index 8fcc3ce98c..b666156114 100644 --- a/target-ppc/trace-events +++ b/target/ppc/trace-events @@ -1,5 +1,5 @@ # See docs/tracing.txt for syntax documentation. -# target-ppc/kvm.c +# target/ppc/kvm.c kvm_failed_spr_set(int str, const char *msg) "Warning: Unable to set SPR %d to KVM: %s" kvm_failed_spr_get(int str, const char *msg) "Warning: Unable to retrieve SPR %d from KVM: %s" diff --git a/target-ppc/translate.c b/target/ppc/translate.c index 59e9552d2b..59e9552d2b 100644 --- a/target-ppc/translate.c +++ b/target/ppc/translate.c diff --git a/target-ppc/translate/dfp-impl.inc.c b/target/ppc/translate/dfp-impl.inc.c index 178d3044a7..178d3044a7 100644 --- a/target-ppc/translate/dfp-impl.inc.c +++ b/target/ppc/translate/dfp-impl.inc.c diff --git a/target-ppc/translate/dfp-ops.inc.c b/target/ppc/translate/dfp-ops.inc.c index 6ef38e5712..6ef38e5712 100644 --- a/target-ppc/translate/dfp-ops.inc.c +++ b/target/ppc/translate/dfp-ops.inc.c diff --git a/target-ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 872af7b56f..872af7b56f 100644 --- a/target-ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c diff --git a/target-ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c index d36ab4ecc3..d36ab4ecc3 100644 --- a/target-ppc/translate/fp-ops.inc.c +++ b/target/ppc/translate/fp-ops.inc.c diff --git a/target-ppc/translate/spe-impl.inc.c b/target/ppc/translate/spe-impl.inc.c index 8c1c16c63e..8c1c16c63e 100644 --- a/target-ppc/translate/spe-impl.inc.c +++ b/target/ppc/translate/spe-impl.inc.c diff --git a/target-ppc/translate/spe-ops.inc.c b/target/ppc/translate/spe-ops.inc.c index 7efe8b8746..7efe8b8746 100644 --- a/target-ppc/translate/spe-ops.inc.c +++ b/target/ppc/translate/spe-ops.inc.c diff --git a/target-ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c index 7143eb3a39..7143eb3a39 100644 --- a/target-ppc/translate/vmx-impl.inc.c +++ b/target/ppc/translate/vmx-impl.inc.c diff --git a/target-ppc/translate/vmx-ops.inc.c b/target/ppc/translate/vmx-ops.inc.c index f02b3bed50..f02b3bed50 100644 --- a/target-ppc/translate/vmx-ops.inc.c +++ b/target/ppc/translate/vmx-ops.inc.c diff --git a/target-ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c index 5a27be4bd4..5a27be4bd4 100644 --- a/target-ppc/translate/vsx-impl.inc.c +++ b/target/ppc/translate/vsx-impl.inc.c diff --git a/target-ppc/translate/vsx-ops.inc.c b/target/ppc/translate/vsx-ops.inc.c index 3d9104155a..3d9104155a 100644 --- a/target-ppc/translate/vsx-ops.inc.c +++ b/target/ppc/translate/vsx-ops.inc.c diff --git a/target-ppc/translate_init.c b/target/ppc/translate_init.c index 626e03186c..626e03186c 100644 --- a/target-ppc/translate_init.c +++ b/target/ppc/translate_init.c diff --git a/target-ppc/user_only_helper.c b/target/ppc/user_only_helper.c index 6aff34713f..6aff34713f 100644 --- a/target-ppc/user_only_helper.c +++ b/target/ppc/user_only_helper.c diff --git a/target-s390x/Makefile.objs b/target/s390x/Makefile.objs index 6b02b1794c..c573633bd1 100644 --- a/target-s390x/Makefile.objs +++ b/target/s390x/Makefile.objs @@ -5,7 +5,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o mmu_helper.o obj-$(CONFIG_KVM) += kvm.o # build and run feature list generator -feat-src = $(SRC_PATH)/target-$(TARGET_BASE_ARCH)/ +feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/ feat-dst = $(BUILD_DIR)/$(TARGET_DIR) ifneq ($(MAKECMDGOALS),clean) GENERATED_HEADERS += $(feat-dst)gen-features.h diff --git a/target-s390x/arch_dump.c b/target/s390x/arch_dump.c index 4731869f6b..4731869f6b 100644 --- a/target-s390x/arch_dump.c +++ b/target/s390x/arch_dump.c diff --git a/target-s390x/cc_helper.c b/target/s390x/cc_helper.c index 1cf855133e..1cf855133e 100644 --- a/target-s390x/cc_helper.c +++ b/target/s390x/cc_helper.c diff --git a/target-s390x/cpu-qom.h b/target/s390x/cpu-qom.h index 4e936e7788..4e936e7788 100644 --- a/target-s390x/cpu-qom.h +++ b/target/s390x/cpu-qom.h diff --git a/target-s390x/cpu.c b/target/s390x/cpu.c index 0a39d31237..0a39d31237 100644 --- a/target-s390x/cpu.c +++ b/target/s390x/cpu.c diff --git a/target-s390x/cpu.h b/target/s390x/cpu.h index fd36a25cf5..fd36a25cf5 100644 --- a/target-s390x/cpu.h +++ b/target/s390x/cpu.h diff --git a/target-s390x/cpu_features.c b/target/s390x/cpu_features.c index 42fd9d792b..42fd9d792b 100644 --- a/target-s390x/cpu_features.c +++ b/target/s390x/cpu_features.c diff --git a/target-s390x/cpu_features.h b/target/s390x/cpu_features.h index d669121786..d669121786 100644 --- a/target-s390x/cpu_features.h +++ b/target/s390x/cpu_features.h diff --git a/target-s390x/cpu_features_def.h b/target/s390x/cpu_features_def.h index aa5ab8d371..aa5ab8d371 100644 --- a/target-s390x/cpu_features_def.h +++ b/target/s390x/cpu_features_def.h diff --git a/target-s390x/cpu_models.c b/target/s390x/cpu_models.c index c1e729df5e..c1e729df5e 100644 --- a/target-s390x/cpu_models.c +++ b/target/s390x/cpu_models.c diff --git a/target-s390x/cpu_models.h b/target/s390x/cpu_models.h index 136a602313..136a602313 100644 --- a/target-s390x/cpu_models.h +++ b/target/s390x/cpu_models.h diff --git a/target-s390x/fpu_helper.c b/target/s390x/fpu_helper.c index e604e9f7be..e604e9f7be 100644 --- a/target-s390x/fpu_helper.c +++ b/target/s390x/fpu_helper.c diff --git a/target-s390x/gdbstub.c b/target/s390x/gdbstub.c index 3d223dec97..3d223dec97 100644 --- a/target-s390x/gdbstub.c +++ b/target/s390x/gdbstub.c diff --git a/target-s390x/gen-features.c b/target/s390x/gen-features.c index e674738ae3..e674738ae3 100644 --- a/target-s390x/gen-features.c +++ b/target/s390x/gen-features.c diff --git a/target-s390x/helper.c b/target/s390x/helper.c index 68bd2f9784..68bd2f9784 100644 --- a/target-s390x/helper.c +++ b/target/s390x/helper.c diff --git a/target-s390x/helper.h b/target/s390x/helper.h index 207a6e7d1c..207a6e7d1c 100644 --- a/target-s390x/helper.h +++ b/target/s390x/helper.h diff --git a/target-s390x/insn-data.def b/target/s390x/insn-data.def index 075ff597c3..075ff597c3 100644 --- a/target-s390x/insn-data.def +++ b/target/s390x/insn-data.def diff --git a/target-s390x/insn-format.def b/target/s390x/insn-format.def index 0e898b90bd..0e898b90bd 100644 --- a/target-s390x/insn-format.def +++ b/target/s390x/insn-format.def diff --git a/target-s390x/int_helper.c b/target/s390x/int_helper.c index 370c94da55..370c94da55 100644 --- a/target-s390x/int_helper.c +++ b/target/s390x/int_helper.c diff --git a/target-s390x/interrupt.c b/target/s390x/interrupt.c index 9edef96795..9edef96795 100644 --- a/target-s390x/interrupt.c +++ b/target/s390x/interrupt.c diff --git a/target-s390x/ioinst.c b/target/s390x/ioinst.c index 590bfa4f12..590bfa4f12 100644 --- a/target-s390x/ioinst.c +++ b/target/s390x/ioinst.c diff --git a/target-s390x/kvm.c b/target/s390x/kvm.c index 97afe02599..97afe02599 100644 --- a/target-s390x/kvm.c +++ b/target/s390x/kvm.c diff --git a/target-s390x/machine.c b/target/s390x/machine.c index edc3a4717b..edc3a4717b 100644 --- a/target-s390x/machine.c +++ b/target/s390x/machine.c diff --git a/target-s390x/mem_helper.c b/target/s390x/mem_helper.c index 99bc5e2834..99bc5e2834 100644 --- a/target-s390x/mem_helper.c +++ b/target/s390x/mem_helper.c diff --git a/target-s390x/misc_helper.c b/target/s390x/misc_helper.c index c9604ea9c7..c9604ea9c7 100644 --- a/target-s390x/misc_helper.c +++ b/target/s390x/misc_helper.c diff --git a/target-s390x/mmu_helper.c b/target/s390x/mmu_helper.c index b11a02706c..b11a02706c 100644 --- a/target-s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c diff --git a/target-s390x/trace-events b/target/s390x/trace-events index df59f5f19f..1574033e31 100644 --- a/target-s390x/trace-events +++ b/target/s390x/trace-events @@ -1,22 +1,22 @@ # See docs/tracing.txt for syntax documentation. -# target-s390x/mmu_helper.c +# target/s390x/mmu_helper.c get_skeys_nonzero(int rc) "SKEY: Call to get_skeys unexpectedly returned %d" set_skeys_nonzero(int rc) "SKEY: Call to set_skeys unexpectedly returned %d" -# target-s390x/ioinst.c +# target/s390x/ioinst.c ioinst(const char *insn) "IOINST: %s" ioinst_sch_id(const char *insn, int cssid, int ssid, int schid) "IOINST: %s (%x.%x.%04x)" ioinst_chp_id(const char *insn, int cssid, int chpid) "IOINST: %s (%x.%02x)" ioinst_chsc_cmd(uint16_t cmd, uint16_t len) "IOINST: chsc command %04x, len %04x" -# target-s390x/kvm.c +# target/s390x/kvm.c kvm_enable_cmma(int rc) "CMMA: enabling with result code %d" kvm_clear_cmma(int rc) "CMMA: clearing with result code %d" kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s" kvm_sigp_finished(uint8_t order, int cpu_index, int dst_index, int cc) "SIGP: Finished order %u on cpu %d -> cpu %d with cc=%d" -# target-s390x/cpu.c +# target/s390x/cpu.c cpu_set_state(int cpu_index, uint8_t state) "setting cpu %d state to %" PRIu8 cpu_halt(int cpu_index) "halting cpu %d" cpu_unhalt(int cpu_index) "unhalting cpu %d" diff --git a/target-s390x/translate.c b/target/s390x/translate.c index 02bc7058fd..02bc7058fd 100644 --- a/target-s390x/translate.c +++ b/target/s390x/translate.c diff --git a/target-sh4/Makefile.objs b/target/sh4/Makefile.objs index 2c25d96e65..2c25d96e65 100644 --- a/target-sh4/Makefile.objs +++ b/target/sh4/Makefile.objs diff --git a/target-sh4/README.sh4 b/target/sh4/README.sh4 index ece046442a..a192ca7540 100644 --- a/target-sh4/README.sh4 +++ b/target/sh4/README.sh4 @@ -8,7 +8,7 @@ file describes the current state of implementation. Most places requiring attention and/or modification can be detected by looking for "XXXXX" or "abort()". -The sh4 core is located in target-sh4/*, while the 7750 peripheral +The sh4 core is located in target/sh4/*, while the 7750 peripheral features (IO ports for example) are located in hw/sh7750.[ch]. The main board description is in hw/shix.c, and the NAND flash in hw/tc58128.[ch]. diff --git a/target-sh4/cpu-qom.h b/target/sh4/cpu-qom.h index 01abb206e4..01abb206e4 100644 --- a/target-sh4/cpu-qom.h +++ b/target/sh4/cpu-qom.h diff --git a/target-sh4/cpu.c b/target/sh4/cpu.c index a38f6a6ded..a38f6a6ded 100644 --- a/target-sh4/cpu.c +++ b/target/sh4/cpu.c diff --git a/target-sh4/cpu.h b/target/sh4/cpu.h index 478ab55868..478ab55868 100644 --- a/target-sh4/cpu.h +++ b/target/sh4/cpu.h diff --git a/target-sh4/gdbstub.c b/target/sh4/gdbstub.c index 13bea00d7d..13bea00d7d 100644 --- a/target-sh4/gdbstub.c +++ b/target/sh4/gdbstub.c diff --git a/target-sh4/helper.c b/target/sh4/helper.c index a33ac697c5..a33ac697c5 100644 --- a/target-sh4/helper.c +++ b/target/sh4/helper.c diff --git a/target-sh4/helper.h b/target/sh4/helper.h index dce859caea..dce859caea 100644 --- a/target-sh4/helper.h +++ b/target/sh4/helper.h diff --git a/target-sh4/monitor.c b/target/sh4/monitor.c index 426e5d4914..426e5d4914 100644 --- a/target-sh4/monitor.c +++ b/target/sh4/monitor.c diff --git a/target-sh4/op_helper.c b/target/sh4/op_helper.c index 684d3f3758..684d3f3758 100644 --- a/target-sh4/op_helper.c +++ b/target/sh4/op_helper.c diff --git a/target-sh4/translate.c b/target/sh4/translate.c index c89a14733f..c89a14733f 100644 --- a/target-sh4/translate.c +++ b/target/sh4/translate.c diff --git a/target-sparc/Makefile.objs b/target/sparc/Makefile.objs index ec905698c5..ec905698c5 100644 --- a/target-sparc/Makefile.objs +++ b/target/sparc/Makefile.objs diff --git a/target-sparc/TODO b/target/sparc/TODO index b8c727e858..b8c727e858 100644 --- a/target-sparc/TODO +++ b/target/sparc/TODO diff --git a/target-sparc/asi.h b/target/sparc/asi.h index c9a1849600..c9a1849600 100644 --- a/target-sparc/asi.h +++ b/target/sparc/asi.h diff --git a/target-sparc/cc_helper.c b/target/sparc/cc_helper.c index a410a0b98f..a410a0b98f 100644 --- a/target-sparc/cc_helper.c +++ b/target/sparc/cc_helper.c diff --git a/target-sparc/cpu-qom.h b/target/sparc/cpu-qom.h index f63af728ee..f63af728ee 100644 --- a/target-sparc/cpu-qom.h +++ b/target/sparc/cpu-qom.h diff --git a/target-sparc/cpu.c b/target/sparc/cpu.c index 4e07b92fbd..4e07b92fbd 100644 --- a/target-sparc/cpu.c +++ b/target/sparc/cpu.c diff --git a/target-sparc/cpu.h b/target/sparc/cpu.h index 5fb0ed1aad..5fb0ed1aad 100644 --- a/target-sparc/cpu.h +++ b/target/sparc/cpu.h diff --git a/target-sparc/fop_helper.c b/target/sparc/fop_helper.c index c7fb176e4c..c7fb176e4c 100644 --- a/target-sparc/fop_helper.c +++ b/target/sparc/fop_helper.c diff --git a/target-sparc/gdbstub.c b/target/sparc/gdbstub.c index ffc2baa2e7..ffc2baa2e7 100644 --- a/target-sparc/gdbstub.c +++ b/target/sparc/gdbstub.c diff --git a/target-sparc/helper.c b/target/sparc/helper.c index 359b0b15ed..359b0b15ed 100644 --- a/target-sparc/helper.c +++ b/target/sparc/helper.c diff --git a/target-sparc/helper.h b/target/sparc/helper.h index 0cf1bfb73a..0cf1bfb73a 100644 --- a/target-sparc/helper.h +++ b/target/sparc/helper.h diff --git a/target-sparc/int32_helper.c b/target/sparc/int32_helper.c index 09afe136e5..09afe136e5 100644 --- a/target-sparc/int32_helper.c +++ b/target/sparc/int32_helper.c diff --git a/target-sparc/int64_helper.c b/target/sparc/int64_helper.c index 29360fa5fe..29360fa5fe 100644 --- a/target-sparc/int64_helper.c +++ b/target/sparc/int64_helper.c diff --git a/target-sparc/ldst_helper.c b/target/sparc/ldst_helper.c index de7d53ae20..de7d53ae20 100644 --- a/target-sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c diff --git a/target-sparc/machine.c b/target/sparc/machine.c index aea6397861..aea6397861 100644 --- a/target-sparc/machine.c +++ b/target/sparc/machine.c diff --git a/target-sparc/mmu_helper.c b/target/sparc/mmu_helper.c index 044e88c4c5..044e88c4c5 100644 --- a/target-sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c diff --git a/target-sparc/monitor.c b/target/sparc/monitor.c index 7cc1b0f87f..7cc1b0f87f 100644 --- a/target-sparc/monitor.c +++ b/target/sparc/monitor.c diff --git a/target-sparc/trace-events b/target/sparc/trace-events index bf52d9769b..8df178a347 100644 --- a/target-sparc/trace-events +++ b/target/sparc/trace-events @@ -1,6 +1,6 @@ # See docs/tracing.txt for syntax documentation. -# target-sparc/mmu_helper.c +# target/sparc/mmu_helper.c mmu_helper_dfault(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DFAULT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d" mmu_helper_dprot(uint64_t address, uint64_t context, int mmu_idx, uint32_t tl) "DPROT at %"PRIx64" context %"PRIx64" mmu_idx=%d tl=%d" mmu_helper_dmiss(uint64_t address, uint64_t context) "DMISS at %"PRIx64" context %"PRIx64 @@ -10,16 +10,16 @@ mmu_helper_get_phys_addr_code(uint32_t tl, int mmu_idx, uint64_t prim_context, u mmu_helper_get_phys_addr_data(uint32_t tl, int mmu_idx, uint64_t prim_context, uint64_t sec_context, uint64_t address) "tl=%d mmu_idx=%d primary context=%"PRIx64" secondary context=%"PRIx64" address=%"PRIx64 mmu_helper_mmu_fault(uint64_t address, uint64_t paddr, int mmu_idx, uint32_t tl, uint64_t prim_context, uint64_t sec_context) "Translate at %"PRIx64" -> %"PRIx64", mmu_idx=%d tl=%d primary context=%"PRIx64" secondary context=%"PRIx64 -# target-sparc/int64_helper.c +# target/sparc/int64_helper.c int_helper_set_softint(uint32_t softint) "new %08x" int_helper_clear_softint(uint32_t softint) "new %08x" int_helper_write_softint(uint32_t softint) "new %08x" -# target-sparc/int32_helper.c +# target/sparc/int32_helper.c int_helper_icache_freeze(void) "Instruction cache: freeze" int_helper_dcache_freeze(void) "Data cache: freeze" -# target-sparc/win_helper.c +# target/sparc/win_helper.c win_helper_gregset_error(uint32_t pstate) "ERROR in get_gregset: active pstate bits=%x" win_helper_switch_pstate(uint32_t pstate_regs, uint32_t new_pstate_regs) "change_pstate: switching regs old=%x new=%x" win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=%x (unchanged)" diff --git a/target-sparc/translate.c b/target/sparc/translate.c index 2205f89837..2205f89837 100644 --- a/target-sparc/translate.c +++ b/target/sparc/translate.c diff --git a/target-sparc/vis_helper.c b/target/sparc/vis_helper.c index 8a9b763d0b..8a9b763d0b 100644 --- a/target-sparc/vis_helper.c +++ b/target/sparc/vis_helper.c diff --git a/target-sparc/win_helper.c b/target/sparc/win_helper.c index 2d5b5469a9..2d5b5469a9 100644 --- a/target-sparc/win_helper.c +++ b/target/sparc/win_helper.c diff --git a/target-tilegx/Makefile.objs b/target/tilegx/Makefile.objs index 0db778f407..0db778f407 100644 --- a/target-tilegx/Makefile.objs +++ b/target/tilegx/Makefile.objs diff --git a/target-tilegx/cpu.c b/target/tilegx/cpu.c index 454793f94a..454793f94a 100644 --- a/target-tilegx/cpu.c +++ b/target/tilegx/cpu.c diff --git a/target-tilegx/cpu.h b/target/tilegx/cpu.h index 1735427233..1735427233 100644 --- a/target-tilegx/cpu.h +++ b/target/tilegx/cpu.h diff --git a/target-tilegx/helper.c b/target/tilegx/helper.c index b4fba9cc21..b4fba9cc21 100644 --- a/target-tilegx/helper.c +++ b/target/tilegx/helper.c diff --git a/target-tilegx/helper.h b/target/tilegx/helper.h index 9281d0f428..9281d0f428 100644 --- a/target-tilegx/helper.h +++ b/target/tilegx/helper.h diff --git a/target-tilegx/opcode_tilegx.h b/target/tilegx/opcode_tilegx.h index 55376be4cf..55376be4cf 100644 --- a/target-tilegx/opcode_tilegx.h +++ b/target/tilegx/opcode_tilegx.h diff --git a/target-tilegx/simd_helper.c b/target/tilegx/simd_helper.c index 2d40ddb63e..2d40ddb63e 100644 --- a/target-tilegx/simd_helper.c +++ b/target/tilegx/simd_helper.c diff --git a/target-tilegx/spr_def_64.h b/target/tilegx/spr_def_64.h index 67a6c1751e..67a6c1751e 100644 --- a/target-tilegx/spr_def_64.h +++ b/target/tilegx/spr_def_64.h diff --git a/target-tilegx/translate.c b/target/tilegx/translate.c index 9c734eeba3..9c734eeba3 100644 --- a/target-tilegx/translate.c +++ b/target/tilegx/translate.c diff --git a/target-tricore/Makefile.objs b/target/tricore/Makefile.objs index 7a05670718..7a05670718 100644 --- a/target-tricore/Makefile.objs +++ b/target/tricore/Makefile.objs diff --git a/target-tricore/cpu-qom.h b/target/tricore/cpu-qom.h index 6a69756126..6a69756126 100644 --- a/target-tricore/cpu-qom.h +++ b/target/tricore/cpu-qom.h diff --git a/target-tricore/cpu.c b/target/tricore/cpu.c index 785b76bd3a..785b76bd3a 100644 --- a/target-tricore/cpu.c +++ b/target/tricore/cpu.c diff --git a/target-tricore/cpu.h b/target/tricore/cpu.h index a3493a123c..a3493a123c 100644 --- a/target-tricore/cpu.h +++ b/target/tricore/cpu.h diff --git a/target-tricore/csfr.def b/target/tricore/csfr.def index 05c45dd628..05c45dd628 100644 --- a/target-tricore/csfr.def +++ b/target/tricore/csfr.def diff --git a/target-tricore/fpu_helper.c b/target/tricore/fpu_helper.c index 98fe9472b1..98fe9472b1 100644 --- a/target-tricore/fpu_helper.c +++ b/target/tricore/fpu_helper.c diff --git a/target-tricore/helper.c b/target/tricore/helper.c index 3118905eca..3118905eca 100644 --- a/target-tricore/helper.c +++ b/target/tricore/helper.c diff --git a/target-tricore/helper.h b/target/tricore/helper.h index 9333e161ab..9333e161ab 100644 --- a/target-tricore/helper.h +++ b/target/tricore/helper.h diff --git a/target-tricore/op_helper.c b/target/tricore/op_helper.c index ac02e0a36b..ac02e0a36b 100644 --- a/target-tricore/op_helper.c +++ b/target/tricore/op_helper.c diff --git a/target-tricore/translate.c b/target/tricore/translate.c index 36f734a662..36f734a662 100644 --- a/target-tricore/translate.c +++ b/target/tricore/translate.c diff --git a/target-tricore/tricore-defs.h b/target/tricore/tricore-defs.h index 40abfaac14..40abfaac14 100644 --- a/target-tricore/tricore-defs.h +++ b/target/tricore/tricore-defs.h diff --git a/target-tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index df666b081f..df666b081f 100644 --- a/target-tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h diff --git a/target-unicore32/Makefile.objs b/target/unicore32/Makefile.objs index 6b41b1e9ef..6b41b1e9ef 100644 --- a/target-unicore32/Makefile.objs +++ b/target/unicore32/Makefile.objs diff --git a/target-unicore32/cpu-qom.h b/target/unicore32/cpu-qom.h index bc68e78045..bc68e78045 100644 --- a/target-unicore32/cpu-qom.h +++ b/target/unicore32/cpu-qom.h diff --git a/target-unicore32/cpu.c b/target/unicore32/cpu.c index c169972b59..c169972b59 100644 --- a/target-unicore32/cpu.c +++ b/target/unicore32/cpu.c diff --git a/target-unicore32/cpu.h b/target/unicore32/cpu.h index 7b5b405e79..7b5b405e79 100644 --- a/target-unicore32/cpu.h +++ b/target/unicore32/cpu.h diff --git a/target-unicore32/helper.c b/target/unicore32/helper.c index d603bde237..d603bde237 100644 --- a/target-unicore32/helper.c +++ b/target/unicore32/helper.c diff --git a/target-unicore32/helper.h b/target/unicore32/helper.h index 941813749d..941813749d 100644 --- a/target-unicore32/helper.h +++ b/target/unicore32/helper.h diff --git a/target-unicore32/op_helper.c b/target/unicore32/op_helper.c index 0872c29faa..0872c29faa 100644 --- a/target-unicore32/op_helper.c +++ b/target/unicore32/op_helper.c diff --git a/target-unicore32/softmmu.c b/target/unicore32/softmmu.c index e7152e72e0..e7152e72e0 100644 --- a/target-unicore32/softmmu.c +++ b/target/unicore32/softmmu.c diff --git a/target-unicore32/translate.c b/target/unicore32/translate.c index 514d460408..514d460408 100644 --- a/target-unicore32/translate.c +++ b/target/unicore32/translate.c diff --git a/target-unicore32/ucf64_helper.c b/target/unicore32/ucf64_helper.c index 6c919010c3..6c919010c3 100644 --- a/target-unicore32/ucf64_helper.c +++ b/target/unicore32/ucf64_helper.c diff --git a/target-xtensa/Makefile.objs b/target/xtensa/Makefile.objs index 481de91973..481de91973 100644 --- a/target-xtensa/Makefile.objs +++ b/target/xtensa/Makefile.objs diff --git a/target-xtensa/core-dc232b.c b/target/xtensa/core-dc232b.c index bb8ed4197f..bb8ed4197f 100644 --- a/target-xtensa/core-dc232b.c +++ b/target/xtensa/core-dc232b.c diff --git a/target-xtensa/core-dc232b/core-isa.h b/target/xtensa/core-dc232b/core-isa.h index a9935b87af..a9935b87af 100644 --- a/target-xtensa/core-dc232b/core-isa.h +++ b/target/xtensa/core-dc232b/core-isa.h diff --git a/target-xtensa/core-dc232b/gdb-config.c b/target/xtensa/core-dc232b/gdb-config.c index 13aba5edec..13aba5edec 100644 --- a/target-xtensa/core-dc232b/gdb-config.c +++ b/target/xtensa/core-dc232b/gdb-config.c diff --git a/target-xtensa/core-dc233c.c b/target/xtensa/core-dc233c.c index 40475e5205..40475e5205 100644 --- a/target-xtensa/core-dc233c.c +++ b/target/xtensa/core-dc233c.c diff --git a/target-xtensa/core-dc233c/core-isa.h b/target/xtensa/core-dc233c/core-isa.h index ff92b7f3ed..ff92b7f3ed 100644 --- a/target-xtensa/core-dc233c/core-isa.h +++ b/target/xtensa/core-dc233c/core-isa.h diff --git a/target-xtensa/core-dc233c/gdb-config.c b/target/xtensa/core-dc233c/gdb-config.c index b632341b28..b632341b28 100644 --- a/target-xtensa/core-dc233c/gdb-config.c +++ b/target/xtensa/core-dc233c/gdb-config.c diff --git a/target-xtensa/core-fsf.c b/target/xtensa/core-fsf.c index 15ef470e8b..15ef470e8b 100644 --- a/target-xtensa/core-fsf.c +++ b/target/xtensa/core-fsf.c diff --git a/target-xtensa/core-fsf/core-isa.h b/target/xtensa/core-fsf/core-isa.h index fb2bb8f2cb..fb2bb8f2cb 100644 --- a/target-xtensa/core-fsf/core-isa.h +++ b/target/xtensa/core-fsf/core-isa.h diff --git a/target-xtensa/cpu-qom.h b/target/xtensa/cpu-qom.h index 403bd95721..403bd95721 100644 --- a/target-xtensa/cpu-qom.h +++ b/target/xtensa/cpu-qom.h diff --git a/target-xtensa/cpu.c b/target/xtensa/cpu.c index e8e9f9175b..e8e9f9175b 100644 --- a/target-xtensa/cpu.c +++ b/target/xtensa/cpu.c diff --git a/target-xtensa/cpu.h b/target/xtensa/cpu.h index 7fe82a37af..7fe82a37af 100644 --- a/target-xtensa/cpu.h +++ b/target/xtensa/cpu.h diff --git a/target-xtensa/gdbstub.c b/target/xtensa/gdbstub.c index fa5469a4ef..fa5469a4ef 100644 --- a/target-xtensa/gdbstub.c +++ b/target/xtensa/gdbstub.c diff --git a/target-xtensa/helper.c b/target/xtensa/helper.c index 768b32c417..768b32c417 100644 --- a/target-xtensa/helper.c +++ b/target/xtensa/helper.c diff --git a/target-xtensa/helper.h b/target/xtensa/helper.h index 5ea9c5beec..5ea9c5beec 100644 --- a/target-xtensa/helper.h +++ b/target/xtensa/helper.h diff --git a/target-xtensa/import_core.sh b/target/xtensa/import_core.sh index 351bee41c2..351bee41c2 100755 --- a/target-xtensa/import_core.sh +++ b/target/xtensa/import_core.sh diff --git a/target-xtensa/monitor.c b/target/xtensa/monitor.c index f3fa4cd278..f3fa4cd278 100644 --- a/target-xtensa/monitor.c +++ b/target/xtensa/monitor.c diff --git a/target-xtensa/op_helper.c b/target/xtensa/op_helper.c index 0a4b2147bc..0a4b2147bc 100644 --- a/target-xtensa/op_helper.c +++ b/target/xtensa/op_helper.c diff --git a/target-xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h index e8a7fda3d8..e8a7fda3d8 100644 --- a/target-xtensa/overlay_tool.h +++ b/target/xtensa/overlay_tool.h diff --git a/target-xtensa/translate.c b/target/xtensa/translate.c index 0858c296ea..0858c296ea 100644 --- a/target-xtensa/translate.c +++ b/target/xtensa/translate.c diff --git a/target-xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c index 370e365c65..370e365c65 100644 --- a/target-xtensa/xtensa-semi.c +++ b/target/xtensa/xtensa-semi.c diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c index 253d4a0a0b..8d5d2bd300 100644 --- a/tcg/s390/tcg-target.inc.c +++ b/tcg/s390/tcg-target.inc.c @@ -378,11 +378,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) ct->ct |= TCG_CT_REG; tcg_regset_set32(ct->u.regs, 0, 0xffff); break; - case 'R': /* not R0 */ - ct->ct |= TCG_CT_REG; - tcg_regset_set32(ct->u.regs, 0, 0xffff); - tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); - break; case 'L': /* qemu_ld/st constraint */ ct->ct |= TCG_CT_REG; tcg_regset_set32(ct->u.regs, 0, 0xffff); @@ -1093,33 +1088,43 @@ static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val) } static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, - TCGArg c2, int c2const) + TCGArg c2, bool c2const, bool need_carry) { bool is_unsigned = is_unsigned_cond(c); if (c2const) { if (c2 == 0) { + if (!(is_unsigned && need_carry)) { + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RR, LTR, r1, r1); + } else { + tcg_out_insn(s, RRE, LTGR, r1, r1); + } + return tcg_cond_to_ltr_cond[c]; + } + /* If we only got here because of load-and-test, + and we couldn't use that, then we need to load + the constant into a register. */ + if (!(facilities & FACILITY_EXT_IMM)) { + c2 = TCG_TMP0; + tcg_out_movi(s, type, c2, 0); + goto do_reg; + } + } + if (is_unsigned) { if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RR, LTR, r1, r1); + tcg_out_insn(s, RIL, CLFI, r1, c2); } else { - tcg_out_insn(s, RRE, LTGR, r1, r1); + tcg_out_insn(s, RIL, CLGFI, r1, c2); } - return tcg_cond_to_ltr_cond[c]; } else { - if (is_unsigned) { - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RIL, CLFI, r1, c2); - } else { - tcg_out_insn(s, RIL, CLGFI, r1, c2); - } + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RIL, CFI, r1, c2); } else { - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RIL, CFI, r1, c2); - } else { - tcg_out_insn(s, RIL, CGFI, r1, c2); - } + tcg_out_insn(s, RIL, CGFI, r1, c2); } } } else { + do_reg: if (is_unsigned) { if (type == TCG_TYPE_I32) { tcg_out_insn(s, RR, CLR, r1, c2); @@ -1148,7 +1153,7 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, do_greater: /* The result of a compare has CC=2 for GT and CC=3 unused. ADD LOGICAL WITH CARRY considers (CC & 2) the carry bit. */ - tgen_cmp(s, type, cond, c1, c2, c2const); + tgen_cmp(s, type, cond, c1, c2, c2const, true); tcg_out_movi(s, type, dest, 0); tcg_out_insn(s, RRE, ALCGR, dest, dest); return; @@ -1219,7 +1224,7 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, break; } - cc = tgen_cmp(s, type, cond, c1, c2, c2const); + cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); if (facilities & FACILITY_LOAD_ON_COND) { /* Emit: d = 0, t = 1, d = (cc ? t : d). */ tcg_out_movi(s, TCG_TYPE_I64, dest, 0); @@ -1238,11 +1243,11 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, { int cc; if (facilities & FACILITY_LOAD_ON_COND) { - cc = tgen_cmp(s, type, c, c1, c2, c2const); + cc = tgen_cmp(s, type, c, c1, c2, c2const, false); tcg_out_insn(s, RRF, LOCGR, dest, r3, cc); } else { c = tcg_invert_cond(c); - cc = tgen_cmp(s, type, c, c1, c2, c2const); + cc = tgen_cmp(s, type, c, c1, c2, c2const, false); /* Emit: if (cc) goto over; dest = r3; over: */ tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); @@ -1374,7 +1379,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c, } } - cc = tgen_cmp(s, type, c, r1, c2, c2const); + cc = tgen_cmp(s, type, c, r1, c2, c2const, false); tgen_branch(s, cc, l); } @@ -2216,12 +2221,12 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_neg_i32, { "r", "r" } }, - { INDEX_op_shl_i32, { "r", "0", "Ri" } }, - { INDEX_op_shr_i32, { "r", "0", "Ri" } }, - { INDEX_op_sar_i32, { "r", "0", "Ri" } }, + { INDEX_op_shl_i32, { "r", "0", "ri" } }, + { INDEX_op_shr_i32, { "r", "0", "ri" } }, + { INDEX_op_sar_i32, { "r", "0", "ri" } }, - { INDEX_op_rotl_i32, { "r", "r", "Ri" } }, - { INDEX_op_rotr_i32, { "r", "r", "Ri" } }, + { INDEX_op_rotl_i32, { "r", "r", "ri" } }, + { INDEX_op_rotr_i32, { "r", "r", "ri" } }, { INDEX_op_ext8s_i32, { "r", "r" } }, { INDEX_op_ext8u_i32, { "r", "r" } }, @@ -2271,12 +2276,12 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_neg_i64, { "r", "r" } }, - { INDEX_op_shl_i64, { "r", "r", "Ri" } }, - { INDEX_op_shr_i64, { "r", "r", "Ri" } }, - { INDEX_op_sar_i64, { "r", "r", "Ri" } }, + { INDEX_op_shl_i64, { "r", "r", "ri" } }, + { INDEX_op_shr_i64, { "r", "r", "ri" } }, + { INDEX_op_sar_i64, { "r", "r", "ri" } }, - { INDEX_op_rotl_i64, { "r", "r", "Ri" } }, - { INDEX_op_rotr_i64, { "r", "r", "Ri" } }, + { INDEX_op_rotl_i64, { "r", "r", "ri" } }, + { INDEX_op_rotr_i64, { "r", "r", "ri" } }, { INDEX_op_ext8s_i64, { "r", "r" } }, { INDEX_op_ext8u_i64, { "r", "r" } }, diff --git a/tests/Makefile.include b/tests/Makefile.include index 6554ef877b..f776404d86 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -91,6 +91,7 @@ gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c check-unit-y += tests/test-write-threshold$(EXESUF) gcov-files-test-write-threshold-y = block/write-threshold.c check-unit-y += tests/test-crypto-hash$(EXESUF) +check-unit-y += tests/test-crypto-hmac$(EXESUF) check-unit-y += tests/test-crypto-cipher$(EXESUF) check-unit-y += tests/test-crypto-secret$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF) @@ -571,6 +572,7 @@ tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) tests/test-mul64$(EXESUF): tests/test-mul64.o $(test-util-obj-y) tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y) tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y) +tests/test-crypto-hmac$(EXESUF): tests/test-crypto-hmac.o $(test-crypto-obj-y) tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y) tests/test-crypto-secret$(EXESUF): tests/test-crypto-secret.o $(test-crypto-obj-y) tests/test-crypto-xts$(EXESUF): tests/test-crypto-xts.o $(test-crypto-obj-y) diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out index 8ff423f56b..dd879f1212 100644 --- a/tests/qemu-iotests/071.out +++ b/tests/qemu-iotests/071.out @@ -12,7 +12,7 @@ read 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 +blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkverify through file blockref === @@ -26,7 +26,7 @@ read 512/512 bytes at offset 229376 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 +blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkdebug through filename === @@ -56,7 +56,7 @@ QMP_VERSION {"return": {}} {"return": {}} {"return": {}} -blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 +blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkverify on existing raw block device === @@ -66,7 +66,7 @@ QMP_VERSION {"return": {}} {"return": {}} {"return": {}} -blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 +blkverify: read offset=0 bytes=512 contents mismatch at offset 0 === Testing blkdebug's set-state through QMP === diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile index 522a63e36b..7f9f2d96c3 100644 --- a/tests/tcg/xtensa/Makefile +++ b/tests/tcg/xtensa/Makefile @@ -19,7 +19,7 @@ AS = $(CROSS)gcc -x assembler-with-cpp LD = $(CROSS)ld XTENSA_SRC_PATH = $(SRC_PATH)/tests/tcg/xtensa -INCLUDE_DIRS = $(XTENSA_SRC_PATH) $(SRC_PATH)/target-xtensa/core-$(CORE) +INCLUDE_DIRS = $(XTENSA_SRC_PATH) $(SRC_PATH)/target/xtensa/core-$(CORE) XTENSA_INC = $(addprefix -I,$(INCLUDE_DIRS)) LDFLAGS = -Tlinker.ld diff --git a/tests/test-aio.c b/tests/test-aio.c index 5be99f8287..2754f154ce 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -128,7 +128,7 @@ static void *test_acquire_thread(void *opaque) static void set_event_notifier(AioContext *ctx, EventNotifier *notifier, EventNotifierHandler *handler) { - aio_set_event_notifier(ctx, notifier, false, handler); + aio_set_event_notifier(ctx, notifier, false, handler, NULL); } static void dummy_notifier_read(EventNotifier *n) @@ -388,7 +388,7 @@ static void test_aio_external_client(void) for (i = 1; i < 3; i++) { EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, true, event_ready_cb); + aio_set_event_notifier(ctx, &data.e, true, event_ready_cb, NULL); event_notifier_set(&data.e); for (j = 0; j < i; j++) { aio_disable_external(ctx); diff --git a/tests/test-crypto-cipher.c b/tests/test-crypto-cipher.c index 5d9e535e2e..07fa2fa616 100644 --- a/tests/test-crypto-cipher.c +++ b/tests/test-crypto-cipher.c @@ -165,6 +165,125 @@ static QCryptoCipherTestData test_data[] = { "ffd29f1bb5596ad94ea2d8e6196b7f09" "30d8ed0bf2773af36dd82a6280c20926", }, +#if defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT) + { + /* Borrowed from linux-kernel crypto/testmgr.h */ + .path = "/crypto/cipher/3des-cbc", + .alg = QCRYPTO_CIPHER_ALG_3DES, + .mode = QCRYPTO_CIPHER_MODE_CBC, + .key = + "e9c0ff2e760b6424444d995a12d640c0" + "eac284e81495dbe8", + .iv = + "7d3388930f93b242", + .plaintext = + "6f54206f614d796e5320636565727374" + "54206f6f4d206e612079655372637465" + "20736f54206f614d796e532063656572" + "737454206f6f4d206e61207965537263" + "746520736f54206f614d796e53206365" + "6572737454206f6f4d206e6120796553" + "7263746520736f54206f614d796e5320" + "63656572737454206f6f4d206e610a79", + .ciphertext = + "0e2db6973c5633f4671721c76e8ad549" + "74b34905c51cd0ed12565c5396b6007d" + "9048fcf58d2939cc8ad5351836234ed7" + "76d1da0c9467bb048bf2036ca8cfb6ea" + "226447aa8f7513bf9fc2c3f0c956c57a" + "71632e897b1e12cae25fafd8a4f8c97a" + "d6f92131624445a6d6bc5ad32d5443cc" + "9ddea570e942458a6bfab19113b0d919", + }, + { + /* Borrowed from linux-kernel crypto/testmgr.h */ + .path = "/crypto/cipher/3des-ecb", + .alg = QCRYPTO_CIPHER_ALG_3DES, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = + "0123456789abcdef5555555555555555" + "fedcba9876543210", + .plaintext = + "736f6d6564617461", + .ciphertext = + "18d748e563620572", + }, + { + /* Borrowed from linux-kernel crypto/testmgr.h */ + .path = "/crypto/cipher/3des-ctr", + .alg = QCRYPTO_CIPHER_ALG_3DES, + .mode = QCRYPTO_CIPHER_MODE_CTR, + .key = + "9cd6f39cb95a67005a67002dceeb2dce" + "ebb45172b451721f", + .iv = + "ffffffffffffffff", + .plaintext = + "05ec77fb42d559208b128669f05bcf56" + "39ad349f66ea7dc448d3ba0db118e34a" + "fe41285c278e11856cf75ec2553ca00b" + "9265e970db4fd6b900b41fe649fd442f" + "533a8d149863ca5dc1a833a70e9178ec" + "77de42d5bc078b12e54cf05b22563980" + "6b9f66c950c4af36ba0d947fe34add41" + "28b31a8e11f843f75e21553c876e9265" + "cc57dba235b900eb72e649d0442fb619" + "8d14ff46ca5d24a8339a6d9178c377de" + "a108bc07ee71e54cd75b22b51c806bf2" + "45c9503baf369960947fc64adda40fb3" + "1aed74f8432a5e218813876ef158cc57" + "3ea2359c67eb72c549d0bb02b619e04b" + "ff46295d248f169a6df45fc3aa3da108" + "937aee71d84cd7be01b51ce74ef2452c" + "503b82159960cb52c6a930a40f9679ed" + "74df432abd048813fa4df15823573e81" + "689c67ce51c5ac37bb02957ce04bd246" + "29b01b8f16f940f45f26aa3d846f937a" + "cd54d8a30abe01e873e74ed1452cb71e" + "8215fc47cb5225a9309b629679c074df" + "a609bd04ef76fa4dd458238a1d8168f3" + "5ace5138ac379e61957cc74bd2a50cb0" + "1be275f9402b5f268910846ff659cd54" + "3fa30a9d64e873da4ed1b803b71ee148" + "fc472e52258c179b62f55cc0ab32a609" + "907bef76d94dd4bf068a1de44ff35a2d" + "5138836a9e61c853c7ae31a50c977ee2" + "75dc402bb2058910fb42f65920543f86" + "699d64cf56daad34b803ea7de148d347", + .ciphertext = + "07c20820721f49ef19cd6f3253052215" + "a2852bdb85d2d8b9dd0d1b45cb6911d4" + "eabeb2455d0caebea0c127ac659f537e" + "afc21bb5b86d360c25c0f86d0b2901da" + "1378dc89121243faf612ef8d87627883" + "e2be41204c6d351bd10c30cfe2de2b03" + "bf4573d4e55995d1b39b276297bdde7f" + "a4d23980aa5023f074883da86a18793b" + "c4966c8d2240926ed6ad2a1fde63c0e7" + "07f72df7b5f3f0cc017c2a9bc210caaa" + "fd2b3fc5f3f6fc9b45db53e45bf3c97b" + "8e52ffc802b8ac9da10039da3d2d0e01" + "097d8d5ebe53b9b08ee7e2966ab278ea" + "de238ba5fa5ce3dabf8e316a55d16ab2" + "b5466fa5f0eeba1f9f98b0664fd03fa9" + "df5f58c4f4ff755c403a097e6e1c97d4" + "cce7e771cf0b150871fa0797cde6ca1d" + "14280ccf99137af1ebfafa9207de1da1" + "d33669fe514d9f2e83374f1f4830ed04" + "4da4ef3aca76f41c418f6337782f86a6" + "ef417ed2af88ab675271c38ef8269372" + "aad60ee70b46b13ab408a9a8a0cf200c" + "52bc8b0556b2bc319b74b92929969a50" + "dc45dc1aeb0c64d4d3057e5955c3f490" + "c2abf89b8adacea1c3f4ad77dd44c8ac" + "a3f1c9d2195cb0caa234c1f76cfdac65" + "32dc48c4f2006b77f17d76acc031632a" + "a53a62c891b10365cb43d106dfc367bc" + "dce0cd35ce4965a0527ba70d07a91bb0" + "407772c2ea0e3a7846b991b6e73d5142" + "fd51b0c62c6313785ceefccfc4700034", + }, +#endif { /* RFC 2144, Appendix B.1 */ .path = "/crypto/cipher/cast5-128", diff --git a/tests/test-crypto-hmac.c b/tests/test-crypto-hmac.c new file mode 100644 index 0000000000..ee55382a3c --- /dev/null +++ b/tests/test-crypto-hmac.c @@ -0,0 +1,266 @@ +/* + * QEMU Crypto hmac algorithms tests + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Longpeng(Mike) <longpeng2@huawei.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 "crypto/init.h" +#include "crypto/hmac.h" + +#define INPUT_TEXT1 "ABCDEFGHIJKLMNOPQRSTUVWXY" +#define INPUT_TEXT2 "Zabcdefghijklmnopqrstuvwx" +#define INPUT_TEXT3 "yz0123456789" +#define INPUT_TEXT INPUT_TEXT1 \ + INPUT_TEXT2 \ + INPUT_TEXT3 + +#define KEY "monkey monkey monkey monkey" + +typedef struct QCryptoHmacTestData QCryptoHmacTestData; +struct QCryptoHmacTestData { + QCryptoHashAlgorithm alg; + const char *hex_digest; +}; + +static QCryptoHmacTestData test_data[] = { + { + .alg = QCRYPTO_HASH_ALG_MD5, + .hex_digest = + "ede9cb83679ba82d88fbeae865b3f8fc", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA1, + .hex_digest = + "c7b5a631e3aac975c4ededfcd346e469" + "dbc5f2d1", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA224, + .hex_digest = + "5f768179dbb29ca722875d0f461a2e2f" + "597d0210340a84df1a8e9c63", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA256, + .hex_digest = + "3798f363c57afa6edaffe39016ca7bad" + "efd1e670afb0e3987194307dec3197db", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA384, + .hex_digest = + "d218680a6032d33dccd9882d6a6a7164" + "64f26623be257a9b2919b185294f4a49" + "9e54b190bfd6bc5cedd2cd05c7e65e82", + }, + { + .alg = QCRYPTO_HASH_ALG_SHA512, + .hex_digest = + "835a4f5b3750b4c1fccfa88da2f746a4" + "900160c9f18964309bb736c13b59491b" + "8e32d37b724cc5aebb0f554c6338a3b5" + "94c4ba26862b2dadb59b7ede1d08d53e", + }, + { + .alg = QCRYPTO_HASH_ALG_RIPEMD160, + .hex_digest = + "94964ed4c1155b62b668c241d67279e5" + "8a711676", + }, +}; + +static const char hex[] = "0123456789abcdef"; + +static void test_hmac_alloc(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + QCryptoHmacTestData *data = &test_data[i]; + QCryptoHmac *hmac = NULL; + uint8_t *result = NULL; + size_t resultlen = 0; + Error *err = NULL; + const char *exp_output = NULL; + int ret; + size_t j; + + if (!qcrypto_hmac_supports(data->alg)) { + return; + } + + exp_output = data->hex_digest; + + hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, + strlen(KEY), &err); + g_assert(err == NULL); + g_assert(hmac != NULL); + + ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT, + strlen(INPUT_TEXT), &result, + &resultlen, &err); + g_assert(err == NULL); + g_assert(ret == 0); + + for (j = 0; j < resultlen; j++) { + g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]); + } + + qcrypto_hmac_free(hmac); + + g_free(result); + } +} + +static void test_hmac_prealloc(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + QCryptoHmacTestData *data = &test_data[i]; + QCryptoHmac *hmac = NULL; + uint8_t *result = NULL; + size_t resultlen = 0; + Error *err = NULL; + const char *exp_output = NULL; + int ret; + size_t j; + + if (!qcrypto_hmac_supports(data->alg)) { + return; + } + + exp_output = data->hex_digest; + + resultlen = strlen(exp_output) / 2; + result = g_new0(uint8_t, resultlen); + + hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, + strlen(KEY), &err); + g_assert(err == NULL); + g_assert(hmac != NULL); + + ret = qcrypto_hmac_bytes(hmac, (const char *)INPUT_TEXT, + strlen(INPUT_TEXT), &result, + &resultlen, &err); + g_assert(err == NULL); + g_assert(ret == 0); + + exp_output = data->hex_digest; + for (j = 0; j < resultlen; j++) { + g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]); + } + + qcrypto_hmac_free(hmac); + + g_free(result); + } +} + +static void test_hmac_iov(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + QCryptoHmacTestData *data = &test_data[i]; + QCryptoHmac *hmac = NULL; + uint8_t *result = NULL; + size_t resultlen = 0; + Error *err = NULL; + const char *exp_output = NULL; + int ret; + size_t j; + struct iovec iov[3] = { + { .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) }, + }; + + if (!qcrypto_hmac_supports(data->alg)) { + return; + } + + exp_output = data->hex_digest; + + hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, + strlen(KEY), &err); + g_assert(err == NULL); + g_assert(hmac != NULL); + + ret = qcrypto_hmac_bytesv(hmac, iov, 3, &result, + &resultlen, &err); + g_assert(err == NULL); + g_assert(ret == 0); + + for (j = 0; j < resultlen; j++) { + g_assert(exp_output[j * 2] == hex[(result[j] >> 4) & 0xf]); + g_assert(exp_output[j * 2 + 1] == hex[result[j] & 0xf]); + } + + qcrypto_hmac_free(hmac); + + g_free(result); + } +} + +static void test_hmac_digest(void) +{ + size_t i; + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + QCryptoHmacTestData *data = &test_data[i]; + QCryptoHmac *hmac = NULL; + uint8_t *result = NULL; + Error *err = NULL; + const char *exp_output = NULL; + int ret; + + if (!qcrypto_hmac_supports(data->alg)) { + return; + } + + exp_output = data->hex_digest; + + hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY, + strlen(KEY), &err); + g_assert(err == NULL); + g_assert(hmac != NULL); + + ret = qcrypto_hmac_digest(hmac, (const char *)INPUT_TEXT, + strlen(INPUT_TEXT), (char **)&result, + &err); + g_assert(err == NULL); + g_assert(ret == 0); + + g_assert_cmpstr((const char *)result, ==, exp_output); + + qcrypto_hmac_free(hmac); + + g_free(result); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_assert(qcrypto_init(NULL) == 0); + + g_test_add_func("/crypto/hmac/iov", test_hmac_iov); + g_test_add_func("/crypto/hmac/alloc", test_hmac_alloc); + g_test_add_func("/crypto/hmac/prealloc", test_hmac_prealloc); + g_test_add_func("/crypto/hmac/digest", test_hmac_digest); + + return g_test_run(); +} diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 9c4f6cb406..060407b20e 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -16,61 +16,53 @@ #include "libqos/virtio-pci.h" #include "standard-headers/linux/virtio_ids.h" #include "standard-headers/linux/virtio_pci.h" +#include "hw/9pfs/9p.h" static const char mount_tag[] = "qtest"; -static char *test_share; +typedef struct { + QVirtioDevice *dev; + QOSState *qs; + QVirtQueue *vq; + char *test_share; + uint16_t p9_req_tag; +} QVirtIO9P; -static QOSState *qvirtio_9p_start(void) +static QVirtIO9P *qvirtio_9p_start(const char *driver) { const char *arch = qtest_get_arch(); const char *cmd = "-fsdev local,id=fsdev0,security_model=none,path=%s " - "-device virtio-9p-pci,fsdev=fsdev0,mount_tag=%s"; + "-device %s,fsdev=fsdev0,mount_tag=%s"; + QVirtIO9P *v9p = g_new0(QVirtIO9P, 1); - test_share = g_strdup("/tmp/qtest.XXXXXX"); - g_assert_nonnull(mkdtemp(test_share)); + v9p->test_share = g_strdup("/tmp/qtest.XXXXXX"); + g_assert_nonnull(mkdtemp(v9p->test_share)); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - return qtest_pc_boot(cmd, test_share, mount_tag); - } - if (strcmp(arch, "ppc64") == 0) { - return qtest_spapr_boot(cmd, test_share, mount_tag); + v9p->qs = qtest_pc_boot(cmd, v9p->test_share, driver, mount_tag); + } else if (strcmp(arch, "ppc64") == 0) { + v9p->qs = qtest_spapr_boot(cmd, v9p->test_share, driver, mount_tag); + } else { + g_printerr("virtio-9p tests are only available on x86 or ppc64\n"); + exit(EXIT_FAILURE); } - g_printerr("virtio-9p tests are only available on x86 or ppc64\n"); - exit(EXIT_FAILURE); -} - -static void qvirtio_9p_stop(QOSState *qs) -{ - qtest_shutdown(qs); - rmdir(test_share); - g_free(test_share); + return v9p; } -static void pci_nop(void) +static void qvirtio_9p_stop(QVirtIO9P *v9p) { - QOSState *qs; - - qs = qvirtio_9p_start(); - qvirtio_9p_stop(qs); + qtest_shutdown(v9p->qs); + rmdir(v9p->test_share); + g_free(v9p->test_share); + g_free(v9p); } -typedef struct { - QVirtioDevice *dev; - QOSState *qs; - QVirtQueue *vq; -} QVirtIO9P; - -static QVirtIO9P *qvirtio_9p_pci_init(QOSState *qs) +static QVirtIO9P *qvirtio_9p_pci_start(void) { - QVirtIO9P *v9p; - QVirtioPCIDevice *dev; - - v9p = g_new0(QVirtIO9P, 1); - - v9p->qs = qs; - dev = qvirtio_pci_device_find(v9p->qs->pcibus, VIRTIO_ID_9P); + QVirtIO9P *v9p = qvirtio_9p_start("virtio-9p-pci"); + QVirtioPCIDevice *dev = qvirtio_pci_device_find(v9p->qs->pcibus, + VIRTIO_ID_9P); g_assert_nonnull(dev); g_assert_cmphex(dev->vdev.device_type, ==, VIRTIO_ID_9P); v9p->dev = (QVirtioDevice *) dev; @@ -84,26 +76,20 @@ static QVirtIO9P *qvirtio_9p_pci_init(QOSState *qs) return v9p; } -static void qvirtio_9p_pci_free(QVirtIO9P *v9p) +static void qvirtio_9p_pci_stop(QVirtIO9P *v9p) { qvirtqueue_cleanup(v9p->dev->bus, v9p->vq, v9p->qs->alloc); qvirtio_pci_device_disable(container_of(v9p->dev, QVirtioPCIDevice, vdev)); g_free(v9p->dev); - g_free(v9p); + qvirtio_9p_stop(v9p); } -static void pci_basic_config(void) +static void pci_config(QVirtIO9P *v9p) { - QVirtIO9P *v9p; - size_t tag_len; + size_t tag_len = qvirtio_config_readw(v9p->dev, 0); char *tag; int i; - QOSState *qs; - qs = qvirtio_9p_start(); - v9p = qvirtio_9p_pci_init(qs); - - tag_len = qvirtio_config_readw(v9p->dev, 0); g_assert_cmpint(tag_len, ==, strlen(mount_tag)); tag = g_malloc(tag_len); @@ -112,16 +98,406 @@ static void pci_basic_config(void) } g_assert_cmpmem(tag, tag_len, mount_tag, tag_len); g_free(tag); +} + +#define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */ + +typedef struct { + QVirtIO9P *v9p; + uint16_t tag; + uint64_t t_msg; + uint32_t t_size; + uint64_t r_msg; + /* No r_size, it is hardcoded to P9_MAX_SIZE */ + size_t t_off; + size_t r_off; +} P9Req; + +static void v9fs_memwrite(P9Req *req, const void *addr, size_t len) +{ + memwrite(req->t_msg + req->t_off, addr, len); + req->t_off += len; +} + +static void v9fs_memskip(P9Req *req, size_t len) +{ + req->r_off += len; +} + +static void v9fs_memrewind(P9Req *req, size_t len) +{ + req->r_off -= len; +} + +static void v9fs_memread(P9Req *req, void *addr, size_t len) +{ + memread(req->r_msg + req->r_off, addr, len); + req->r_off += len; +} + +static void v9fs_uint16_write(P9Req *req, uint16_t val) +{ + uint16_t le_val = cpu_to_le16(val); + + v9fs_memwrite(req, &le_val, 2); +} + +static void v9fs_uint16_read(P9Req *req, uint16_t *val) +{ + v9fs_memread(req, val, 2); + le16_to_cpus(val); +} + +static void v9fs_uint32_write(P9Req *req, uint32_t val) +{ + uint32_t le_val = cpu_to_le32(val); + + v9fs_memwrite(req, &le_val, 4); +} + +static void v9fs_uint32_read(P9Req *req, uint32_t *val) +{ + v9fs_memread(req, val, 4); + le32_to_cpus(val); +} + +/* len[2] string[len] */ +static uint16_t v9fs_string_size(const char *string) +{ + size_t len = strlen(string); + + g_assert_cmpint(len, <=, UINT16_MAX); + + return 2 + len; +} + +static void v9fs_string_write(P9Req *req, const char *string) +{ + int len = strlen(string); + + g_assert_cmpint(len, <=, UINT16_MAX); + + v9fs_uint16_write(req, (uint16_t) len); + v9fs_memwrite(req, string, len); +} + +static void v9fs_string_read(P9Req *req, uint16_t *len, char **string) +{ + uint16_t local_len; + + v9fs_uint16_read(req, &local_len); + if (len) { + *len = local_len; + } + if (string) { + *string = g_malloc(local_len); + v9fs_memread(req, *string, local_len); + } else { + v9fs_memskip(req, local_len); + } +} + + typedef struct { + uint32_t size; + uint8_t id; + uint16_t tag; +} QEMU_PACKED P9Hdr; + +static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id, + uint16_t tag) +{ + P9Req *req = g_new0(P9Req, 1); + uint32_t t_size = 7 + size; /* 9P header has well-known size of 7 bytes */ + P9Hdr hdr = { + .size = cpu_to_le32(t_size), + .id = id, + .tag = cpu_to_le16(tag) + }; + + g_assert_cmpint(t_size, <=, P9_MAX_SIZE); - qvirtio_9p_pci_free(v9p); - qvirtio_9p_stop(qs); + req->v9p = v9p; + req->t_size = t_size; + req->t_msg = guest_alloc(v9p->qs->alloc, req->t_size); + v9fs_memwrite(req, &hdr, 7); + req->tag = tag; + return req; +} + +static void v9fs_req_send(P9Req *req) +{ + QVirtIO9P *v9p = req->v9p; + uint32_t free_head; + + req->r_msg = guest_alloc(v9p->qs->alloc, P9_MAX_SIZE); + free_head = qvirtqueue_add(v9p->vq, req->t_msg, req->t_size, false, true); + qvirtqueue_add(v9p->vq, req->r_msg, P9_MAX_SIZE, true, false); + qvirtqueue_kick(v9p->dev, v9p->vq, free_head); + req->t_off = 0; +} + +static void v9fs_req_recv(P9Req *req, uint8_t id) +{ + QVirtIO9P *v9p = req->v9p; + P9Hdr hdr; + int i; + + for (i = 0; i < 10; i++) { + qvirtio_wait_queue_isr(v9p->dev, v9p->vq, 1000 * 1000); + + v9fs_memread(req, &hdr, 7); + le32_to_cpus(&hdr.size); + le16_to_cpus(&hdr.tag); + if (hdr.size >= 7) { + break; + } + v9fs_memrewind(req, 7); + } + + g_assert_cmpint(hdr.size, >=, 7); + g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE); + g_assert_cmpint(hdr.tag, ==, req->tag); + + if (hdr.id != id && hdr.id == P9_RLERROR) { + uint32_t err; + v9fs_uint32_read(req, &err); + g_printerr("Received Rlerror (%d) instead of Response %d\n", err, id); + g_assert_not_reached(); + } + g_assert_cmpint(hdr.id, ==, id); +} + +static void v9fs_req_free(P9Req *req) +{ + QVirtIO9P *v9p = req->v9p; + + guest_free(v9p->qs->alloc, req->t_msg); + guest_free(v9p->qs->alloc, req->r_msg); + g_free(req); +} + +/* size[4] Rlerror tag[2] ecode[4] */ +static void v9fs_rlerror(P9Req *req, uint32_t *err) +{ + v9fs_req_recv(req, P9_RLERROR); + v9fs_uint32_read(req, err); + v9fs_req_free(req); +} + +/* size[4] Tversion tag[2] msize[4] version[s] */ +static P9Req *v9fs_tversion(QVirtIO9P *v9p, uint32_t msize, const char *version) +{ + P9Req *req = v9fs_req_init(v9p, 4 + v9fs_string_size(version), P9_TVERSION, + P9_NOTAG); + + v9fs_uint32_write(req, msize); + v9fs_string_write(req, version); + v9fs_req_send(req); + return req; +} + +/* size[4] Rversion tag[2] msize[4] version[s] */ +static void v9fs_rversion(P9Req *req, uint16_t *len, char **version) +{ + uint32_t msize; + + v9fs_req_recv(req, P9_RVERSION); + v9fs_uint32_read(req, &msize); + + g_assert_cmpint(msize, ==, P9_MAX_SIZE); + + if (len || version) { + v9fs_string_read(req, len, version); + } + + v9fs_req_free(req); +} + +/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */ +static P9Req *v9fs_tattach(QVirtIO9P *v9p, uint32_t fid, uint32_t n_uname) +{ + const char *uname = ""; /* ignored by QEMU */ + const char *aname = ""; /* ignored by QEMU */ + P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, + ++(v9p->p9_req_tag)); + + v9fs_uint32_write(req, fid); + v9fs_uint32_write(req, P9_NOFID); + v9fs_string_write(req, uname); + v9fs_string_write(req, aname); + v9fs_uint32_write(req, n_uname); + v9fs_req_send(req); + return req; +} + +typedef char v9fs_qid[13]; + +/* size[4] Rattach tag[2] qid[13] */ +static void v9fs_rattach(P9Req *req, v9fs_qid *qid) +{ + v9fs_req_recv(req, P9_RATTACH); + if (qid) { + v9fs_memread(req, qid, 13); + } + v9fs_req_free(req); +} + +/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ +static P9Req *v9fs_twalk(QVirtIO9P *v9p, uint32_t fid, uint32_t newfid, + uint16_t nwname, char *const wnames[]) +{ + P9Req *req; + int i; + uint32_t size = 4 + 4 + 2; + + for (i = 0; i < nwname; i++) { + size += v9fs_string_size(wnames[i]); + } + req = v9fs_req_init(v9p, size, P9_TWALK, ++(v9p->p9_req_tag)); + v9fs_uint32_write(req, fid); + v9fs_uint32_write(req, newfid); + v9fs_uint16_write(req, nwname); + for (i = 0; i < nwname; i++) { + v9fs_string_write(req, wnames[i]); + } + v9fs_req_send(req); + return req; +} + +/* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13]) */ +static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid) +{ + uint16_t local_nwqid; + + v9fs_req_recv(req, P9_RWALK); + v9fs_uint16_read(req, &local_nwqid); + if (nwqid) { + *nwqid = local_nwqid; + } + if (wqid) { + *wqid = g_malloc(local_nwqid * 13); + v9fs_memread(req, *wqid, local_nwqid * 13); + } + v9fs_req_free(req); +} + +static void fs_version(QVirtIO9P *v9p) +{ + const char *version = "9P2000.L"; + uint16_t server_len; + char *server_version; + P9Req *req; + + req = v9fs_tversion(v9p, P9_MAX_SIZE, version); + v9fs_rversion(req, &server_len, &server_version); + + g_assert_cmpmem(server_version, server_len, version, strlen(version)); + + g_free(server_version); +} + +static void fs_attach(QVirtIO9P *v9p) +{ + P9Req *req; + + fs_version(v9p); + req = v9fs_tattach(v9p, 0, getuid()); + v9fs_rattach(req, NULL); +} + +static void fs_walk(QVirtIO9P *v9p) +{ + char *wnames[P9_MAXWELEM], *paths[P9_MAXWELEM]; + char *last_path = v9p->test_share; + uint16_t nwqid; + v9fs_qid *wqid; + int i; + P9Req *req; + + for (i = 0; i < P9_MAXWELEM; i++) { + wnames[i] = g_strdup_printf("%s%d", __func__, i); + last_path = paths[i] = g_strdup_printf("%s/%s", last_path, wnames[i]); + g_assert(!mkdir(paths[i], 0700)); + } + + fs_attach(v9p); + req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames); + v9fs_rwalk(req, &nwqid, &wqid); + + g_assert_cmpint(nwqid, ==, P9_MAXWELEM); + + for (i = 0; i < P9_MAXWELEM; i++) { + rmdir(paths[P9_MAXWELEM - i - 1]); + g_free(paths[P9_MAXWELEM - i - 1]); + g_free(wnames[i]); + } + + g_free(wqid); +} + +static void fs_walk_no_slash(QVirtIO9P *v9p) +{ + char *const wnames[] = { g_strdup(" /") }; + P9Req *req; + uint32_t err; + + fs_attach(v9p); + req = v9fs_twalk(v9p, 0, 1, 1, wnames); + v9fs_rlerror(req, &err); + + g_assert_cmpint(err, ==, ENOENT); + + g_free(wnames[0]); +} + +static void fs_walk_dotdot(QVirtIO9P *v9p) +{ + char *const wnames[] = { g_strdup("..") }; + v9fs_qid root_qid, *wqid; + P9Req *req; + + fs_version(v9p); + req = v9fs_tattach(v9p, 0, getuid()); + v9fs_rattach(req, &root_qid); + + req = v9fs_twalk(v9p, 0, 1, 1, wnames); + v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */ + + g_assert_cmpmem(&root_qid, 13, wqid[0], 13); + + g_free(wqid); + g_free(wnames[0]); +} + +typedef void (*v9fs_test_fn)(QVirtIO9P *v9p); + +static void v9fs_run_pci_test(gconstpointer data) +{ + v9fs_test_fn fn = data; + QVirtIO9P *v9p = qvirtio_9p_pci_start(); + + if (fn) { + fn(v9p); + } + qvirtio_9p_pci_stop(v9p); +} + +static void v9fs_qtest_pci_add(const char *path, v9fs_test_fn fn) +{ + qtest_add_data_func(path, fn, v9fs_run_pci_test); } int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); - qtest_add_func("/virtio/9p/pci/nop", pci_nop); - qtest_add_func("/virtio/9p/pci/basic/configuration", pci_basic_config); + v9fs_qtest_pci_add("/virtio/9p/pci/nop", NULL); + v9fs_qtest_pci_add("/virtio/9p/pci/config", pci_config); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/version/basic", fs_version); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/attach/basic", fs_attach); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/basic", fs_walk); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/no_slash", fs_walk_no_slash); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/dotdot_from_root", + fs_walk_dotdot); return g_test_run(); } diff --git a/trace-events b/trace-events index f74e1d3d22..1181486454 100644 --- a/trace-events +++ b/trace-events @@ -25,6 +25,12 @@ # # The <format-string> should be a sprintf()-compatible format string. +# aio-posix.c +run_poll_handlers_begin(void *ctx, int64_t max_ns) "ctx %p max_ns %"PRId64 +run_poll_handlers_end(void *ctx, bool progress) "ctx %p progress %d" +poll_shrink(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64 +poll_grow(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64 + # thread-pool.c thread_pool_submit(void *pool, void *req, void *opaque) "pool %p req %p opaque %p" thread_pool_complete(void *pool, void *req, void *opaque, int ret) "pool %p req %p opaque %p ret %d" diff --git a/util/event_notifier-posix.c b/util/event_notifier-posix.c index c1f0d79b34..f2aacfc8b3 100644 --- a/util/event_notifier-posix.c +++ b/util/event_notifier-posix.c @@ -95,7 +95,7 @@ int event_notifier_set_handler(EventNotifier *e, EventNotifierHandler *handler) { aio_set_fd_handler(iohandler_get_aio_context(), e->rfd, is_external, - (IOHandler *)handler, NULL, e); + (IOHandler *)handler, NULL, NULL, e); return 0; } diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 737bffa984..a5d2f6c0c3 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -131,6 +131,13 @@ void qemu_coroutine_enter(Coroutine *co) } } +void qemu_coroutine_enter_if_inactive(Coroutine *co) +{ + if (!qemu_coroutine_entered(co)) { + qemu_coroutine_enter(co); + } +} + void coroutine_fn qemu_coroutine_yield(void) { Coroutine *self = qemu_coroutine_self(); diff --git a/vl.c b/vl.c index d77dd862f9..a23de18fa9 100644 --- a/vl.c +++ b/vl.c @@ -2859,7 +2859,8 @@ static bool object_create_initial(const char *type) g_str_equal(type, "filter-mirror") || g_str_equal(type, "filter-redirector") || g_str_equal(type, "colo-compare") || - g_str_equal(type, "filter-rewriter")) { + g_str_equal(type, "filter-rewriter") || + g_str_equal(type, "filter-replay")) { return false; } |