aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFathi Boudra <fathi.boudra@linaro.org>2012-09-15 09:43:51 +0300
committerFathi Boudra <fathi.boudra@linaro.org>2012-12-25 16:58:47 +0200
commitf77d2c3c841d1990d10ab147b770bf5673dbfacc (patch)
tree24ad479e52a07b73625a5fe6d9d350b2c97be0db
parent111465fea3aa2452c34a609bdc4318d9a7667bb7 (diff)
parentdd55a01d2af35f5e9dabb2b745770afd008c9e24 (diff)
Imported Debian patch 1.2.0-2012.09-0ubuntu1~linaro1debian/1.2.0-2012.09-0ubuntu1_linaro1
-rw-r--r--Changelog.LINARO3
-rw-r--r--MAINTAINERS12
-rw-r--r--Makefile27
-rw-r--r--Makefile.objs8
-rw-r--r--QMP/qmp-events.txt291
-rw-r--r--QMP/qmp-spec.txt10
-rw-r--r--VERSION2
-rw-r--r--VERSION.LINARO2
-rw-r--r--arch_init.c259
-rw-r--r--arch_init.h5
-rw-r--r--audio/winwaveaudio.c12
-rw-r--r--block.c4
-rw-r--r--block.h1
-rw-r--r--block/iscsi.c185
-rw-r--r--block/qcow2.c32
-rw-r--r--block/qed-check.c26
-rw-r--r--block/qed.c22
-rw-r--r--block/qed.h5
-rw-r--r--block/raw-posix.c46
-rw-r--r--block/raw-win32.c6
-rw-r--r--block/sheepdog.c1
-rw-r--r--block/stream.c6
-rw-r--r--block/vdi.c5
-rw-r--r--block/vmdk.c83
-rw-r--r--block/vpc.c4
-rw-r--r--block/vvfat.c16
-rw-r--r--block_int.h1
-rw-r--r--blockdev.c1
-rw-r--r--compiler.h7
-rwxr-xr-xconfigure164
-rw-r--r--console.c59
-rw-r--r--cpu-all.h22
-rw-r--r--cpu-exec.c1
-rw-r--r--cputlb.c4
-rw-r--r--cutils.c47
-rw-r--r--debian/changelog12
-rw-r--r--default-configs/arm-softmmu.mak18
-rw-r--r--default-configs/unicore32-softmmu.mak4
-rw-r--r--dma-helpers.c5
-rw-r--r--docs/bootindex.txt2
-rw-r--r--docs/writing-qmp-commands.txt47
-rw-r--r--docs/xbzrle.txt128
-rw-r--r--error.c93
-rw-r--r--error.h34
-rw-r--r--error_int.h29
-rw-r--r--exec.c23
-rw-r--r--hmp-commands.hx38
-rw-r--r--hmp.c176
-rw-r--r--hmp.h5
-rw-r--r--hw/Makefile.objs30
-rw-r--r--hw/acpi.c2
-rw-r--r--hw/acpi_piix4.c6
-rw-r--r--hw/alpha_pci.c1
-rw-r--r--hw/alpha_typhoon.c26
-rw-r--r--hw/apic_common.c4
-rw-r--r--hw/arm/Makefile.objs15
-rw-r--r--hw/arm_gic.c1
-rw-r--r--hw/armv7m.c5
-rw-r--r--hw/armv7m_nvic.c21
-rw-r--r--hw/boards.h3
-rw-r--r--hw/bonito.c152
-rw-r--r--hw/cirrus_vga.c2
-rw-r--r--hw/dec_pci.c31
-rw-r--r--hw/dec_pci.h2
-rw-r--r--hw/esp.c16
-rw-r--r--hw/framebuffer.c2
-rw-r--r--hw/grackle_pci.c65
-rw-r--r--hw/gt64xxx.c67
-rw-r--r--hw/i82378.c1
-rw-r--r--hw/ide/ahci.c44
-rw-r--r--hw/ide/internal.h1
-rw-r--r--hw/ivshmem.c22
-rw-r--r--hw/kvm/i8254.c52
-rw-r--r--hw/megasas.c9
-rw-r--r--hw/mips_malta.c1
-rw-r--r--hw/msix.c21
-rw-r--r--hw/null-machine.c40
-rw-r--r--hw/openpic.c17
-rw-r--r--hw/pc.c32
-rw-r--r--hw/pc.h4
-rw-r--r--hw/pc_piix.c12
-rw-r--r--hw/pci_host.c12
-rw-r--r--hw/pci_host.h5
-rw-r--r--hw/petalogix_ml605_mmu.c24
-rw-r--r--hw/piix_pci.c22
-rw-r--r--hw/ppc/Makefile.objs4
-rw-r--r--hw/ppc/e500.c (renamed from hw/ppce500_mpc8544ds.c)141
-rw-r--r--hw/ppc/e500.h21
-rw-r--r--hw/ppc/e500plat.c60
-rw-r--r--hw/ppc/mpc8544ds.c61
-rw-r--r--hw/ppc440_bamboo.c3
-rw-r--r--hw/ppc4xx.h2
-rw-r--r--hw/ppc4xx_pci.c27
-rw-r--r--hw/ppc_mac.h1
-rw-r--r--hw/ppc_newworld.c2
-rw-r--r--hw/ppc_oldworld.c2
-rw-r--r--hw/ppc_prep.c5
-rw-r--r--hw/ppce500_pci.c24
-rw-r--r--hw/prep_pci.c33
-rw-r--r--hw/puv3.c131
-rw-r--r--hw/puv3.h49
-rw-r--r--hw/puv3_dma.c109
-rw-r--r--hw/puv3_gpio.c141
-rw-r--r--hw/puv3_intc.c135
-rw-r--r--hw/puv3_ost.c151
-rw-r--r--hw/puv3_pm.c149
-rw-r--r--hw/qdev-monitor.c4
-rw-r--r--hw/qdev.c2
-rw-r--r--hw/scsi-bus.c2
-rw-r--r--hw/scsi-disk.c113
-rw-r--r--hw/scsi-generic.c3
-rw-r--r--hw/sd.c74
-rw-r--r--hw/sd.h8
-rw-r--r--hw/shpc.c1
-rw-r--r--hw/spapr.c112
-rw-r--r--hw/spapr.h17
-rw-r--r--hw/spapr_iommu.c58
-rw-r--r--hw/spapr_llan.c2
-rw-r--r--hw/spapr_pci.c392
-rw-r--r--hw/spapr_pci.h41
-rw-r--r--hw/spapr_vio.c14
-rw-r--r--hw/spapr_vio.h8
-rw-r--r--hw/spapr_vty.c2
-rw-r--r--hw/ssd0323.c4
-rw-r--r--hw/stream.c23
-rw-r--r--hw/stream.h31
-rw-r--r--hw/sun4u.c1
-rw-r--r--hw/unicore32/Makefile.objs6
-rw-r--r--hw/unin_pci.c185
-rw-r--r--hw/usb.h4
-rw-r--r--hw/usb/core.c39
-rw-r--r--hw/usb/dev-uas.c5
-rw-r--r--hw/usb/hcd-ehci.c151
-rw-r--r--hw/usb/hcd-musb.c3
-rw-r--r--hw/usb/hcd-ohci.c4
-rw-r--r--hw/usb/hcd-uhci.c20
-rw-r--r--hw/usb/hcd-xhci.c2
-rw-r--r--hw/usb/host-linux.c1
-rw-r--r--hw/versatilepb.c2
-rw-r--r--hw/vga-pci.c2
-rw-r--r--hw/vga-pci.h12
-rw-r--r--hw/virtio-blk.c30
-rw-r--r--hw/virtio-blk.h8
-rw-r--r--hw/virtio-pci.c3
-rw-r--r--hw/virtio-scsi.c17
-rw-r--r--hw/virtio-scsi.h9
-rw-r--r--hw/xen_platform.c3
-rw-r--r--hw/xics.c12
-rw-r--r--hw/xics.h5
-rw-r--r--hw/xilinx.h22
-rw-r--r--hw/xilinx_axidma.c74
-rw-r--r--hw/xilinx_axidma.h39
-rw-r--r--hw/xilinx_axienet.c32
-rw-r--r--include/qemu/object.h46
-rw-r--r--include/qemu/page_cache.h79
-rw-r--r--iohandler.c1
-rw-r--r--iov.c7
-rw-r--r--json-parser.c230
-rw-r--r--kvm-all.c29
-rw-r--r--linux-headers/asm-s390/kvm.h2
-rw-r--r--linux-headers/asm-s390/kvm_para.h2
-rw-r--r--linux-headers/asm-x86/kvm.h1
-rw-r--r--linux-headers/asm-x86/kvm_para.h7
-rw-r--r--linux-headers/linux/kvm.h3
-rw-r--r--linux-user/elfload.c161
-rw-r--r--linux-user/flatload.c2
-rw-r--r--linux-user/ioctls.h4
-rw-r--r--linux-user/main.c52
-rw-r--r--linux-user/qemu.h15
-rw-r--r--linux-user/syscall.c82
-rw-r--r--linux-user/syscall_defs.h16
-rw-r--r--linux-user/syscall_types.h3
-rw-r--r--memory.c2
-rw-r--r--migration-tcp.c22
-rw-r--r--migration.c119
-rw-r--r--migration.h21
-rw-r--r--monitor.c396
-rw-r--r--monitor.h6
-rw-r--r--nbd.c2
-rw-r--r--osdep.c122
-rw-r--r--osdep.h7
-rw-r--r--page_cache.c218
-rw-r--r--pc-bios/README4
-rw-r--r--qapi-schema.json452
-rw-r--r--qapi/opts-visitor.c2
-rw-r--r--qapi/qmp-core.h1
-rw-r--r--qapi/qmp-dispatch.c11
-rw-r--r--qemu-char.c21
-rw-r--r--qemu-common.h24
-rw-r--r--qemu-config.c18
-rw-r--r--qemu-config.h1
-rw-r--r--qemu-doc.texi5
-rw-r--r--qemu-ga.c12
-rw-r--r--qemu-img.c2
-rw-r--r--qemu-img.texi10
-rw-r--r--qemu-options.hx23
-rw-r--r--qemu-seccomp.c141
-rw-r--r--qemu-seccomp.h22
-rw-r--r--qemu-sockets.c14
-rw-r--r--qemu-timer.c3
-rw-r--r--qemu-tool.c25
-rw-r--r--qemu-user.c20
-rw-r--r--qemu_socket.h4
-rw-r--r--qerror.c516
-rw-r--r--qerror.h168
-rw-r--r--qlist.c13
-rw-r--r--qlist.h1
-rw-r--r--qmp-commands.hx309
-rw-r--r--qmp.c62
-rw-r--r--qom/object.c225
-rw-r--r--rules.mak2
-rw-r--r--savevm.c163
-rw-r--r--scripts/qapi-commands.py1
-rw-r--r--scripts/qapi-types.py17
-rwxr-xr-xscripts/simpletrace.py2
-rw-r--r--scripts/tracetool/backend/simple.py2
-rw-r--r--softmmu-semi.h5
-rw-r--r--sysemu.h1
-rw-r--r--target-arm/arm-semi.c15
-rw-r--r--target-arm/cpu.h2
-rw-r--r--target-arm/helper.c6
-rw-r--r--target-arm/neon_helper.c26
-rw-r--r--target-arm/op_helper.c2
-rw-r--r--target-arm/translate.c12
-rw-r--r--target-i386/Makefile.objs9
-rw-r--r--target-i386/cc_helper.c199
-rw-r--r--target-i386/cc_helper_template.h36
-rw-r--r--target-i386/cpu.c37
-rw-r--r--target-i386/cpu.h1
-rw-r--r--target-i386/fpu_helper.c429
-rw-r--r--target-i386/helper.h352
-rw-r--r--target-i386/int_helper.c44
-rw-r--r--target-i386/kvm.c13
-rw-r--r--target-i386/machine.c21
-rw-r--r--target-i386/mem_helper.c46
-rw-r--r--target-i386/misc_helper.c75
-rw-r--r--target-i386/ops_sse.h378
-rw-r--r--target-i386/ops_sse_header.h334
-rw-r--r--target-i386/seg_helper.c434
-rw-r--r--target-i386/shift_helper_template.h10
-rw-r--r--target-i386/smm_helper.c14
-rw-r--r--target-i386/svm_helper.c185
-rw-r--r--target-i386/translate.c917
-rw-r--r--target-mips/op_helper.c75
-rw-r--r--target-mips/translate.c37
-rw-r--r--target-ppc/kvm.c2
-rw-r--r--target-ppc/translate.c2
-rw-r--r--target-ppc/translate_init.c26
-rw-r--r--target-s390x/Makefile.objs2
-rw-r--r--target-s390x/cpu.h3
-rw-r--r--target-s390x/interrupt.c29
-rw-r--r--target-s390x/kvm.c5
-rw-r--r--target-s390x/op_helper.c43
-rw-r--r--target-unicore32/Makefile.objs4
-rw-r--r--target-unicore32/cpu.c19
-rw-r--r--target-unicore32/cpu.h18
-rw-r--r--target-unicore32/helper.c511
-rw-r--r--target-unicore32/helper.h17
-rw-r--r--target-unicore32/machine.c23
-rw-r--r--target-unicore32/op_helper.c44
-rw-r--r--target-unicore32/softmmu.c267
-rw-r--r--target-unicore32/translate.c159
-rw-r--r--target-unicore32/ucf64_helper.c345
-rw-r--r--target-xtensa/xtensa-semi.c2
-rw-r--r--tcg/arm/tcg-target.c237
-rw-r--r--tcg/ia64/tcg-target.c58
-rw-r--r--tcg/mips/tcg-target.c158
-rw-r--r--tests/Makefile2
-rw-r--r--tests/check-qjson.c53
-rwxr-xr-xtests/qemu-iotests/03039
-rw-r--r--tests/qemu-iotests/030.out4
-rwxr-xr-xtests/qemu-iotests/0391
-rw-r--r--tests/qemu-iotests/039.out6
-rw-r--r--tests/qemu-iotests/common.rc34
-rw-r--r--trace-events8
-rw-r--r--trace/simple.c35
-rw-r--r--trace/simple.h1
-rw-r--r--ui/vnc.c2
-rw-r--r--vl.c117
-rw-r--r--xen-all.c24
-rw-r--r--xen-mapcache.c9
281 files changed, 10498 insertions, 5095 deletions
diff --git a/Changelog.LINARO b/Changelog.LINARO
index e0ac2da..b959f31 100644
--- a/Changelog.LINARO
+++ b/Changelog.LINARO
@@ -12,6 +12,9 @@ here. For full change detail consult the git history:
Bug numbers refer to Launchpad qemu-linaro bugs, eg:
https://bugs.launchpad.net/qemu-linaro/+bug/703094
+version 2012.09:
+ - No significant changes, rebased onto upstream v1.2.0.
+
version 2012.08:
- Fixes #1004205: the -dtb option now accepts a filename
with no directory as being in the current directory
diff --git a/MAINTAINERS b/MAINTAINERS
index 2d219d2..6d864c1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -405,6 +405,14 @@ M: Alexander Graf <agraf@suse.de>
S: Maintained
F: hw/s390-*.c
+UniCore32 Machines
+-------------
+PKUnity-3 SoC initramfs-with-busybox
+M: Guan Xuetao <gxt@mprc.pku.edu.cn>
+S: Maintained
+F: hw/puv3*
+F: hw/unicore32/
+
X86 Machines
------------
PC
@@ -560,7 +568,7 @@ F: monitor.c
Network device layer
M: Anthony Liguori <aliguori@us.ibm.com>
-M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+M: Stefan Hajnoczi <stefanha@gmail.com>
S: Maintained
F: net/
T: git git://github.com/stefanha/qemu.git net
@@ -580,7 +588,7 @@ F: slirp/
T: git git://git.kiszka.org/qemu.git queues/slirp
Tracing
-M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+M: Stefan Hajnoczi <stefanha@gmail.com>
S: Maintained
F: trace/
F: scripts/tracetool.py
diff --git a/Makefile b/Makefile
index 0444b2f..44a4258 100644
--- a/Makefile
+++ b/Makefile
@@ -148,9 +148,6 @@ install-libcacard: libcacard.la
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
endif
-vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o libcacard/vscclient.o
- $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@")
-
######################################################################
qemu-img.o: qemu-img-cmds.h
@@ -166,6 +163,9 @@ qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
+vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) $(tools-obj-y) qemu-timer-common.o libcacard/vscclient.o
+ $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@")
+
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
@@ -181,24 +181,26 @@ ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/tests/Makefile
endif
+qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
+
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, " GEN $@")
qapi-types.c qapi-types.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, " GEN $@")
qapi-visit.c qapi-visit.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." < $<, " GEN $@")
qmp-commands.h qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@")
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
@@ -212,13 +214,10 @@ clean:
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f qemu-options.def
- rm -f *.o *.d *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
+ find . -name '*.[od]' -exec rm -f {} +
+ rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
rm -Rf .libs
- rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
- rm -f qom/*.o qom/*.d libuser/qom/*.o libuser/qom/*.d
- rm -f hw/usb/*.o hw/usb/*.d hw/*.o hw/*.d
rm -f qemu-img-cmds.h
- rm -f trace/*.o trace/*.d
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
@# May not be present in GENERATED_HEADERS
rm -f trace-dtrace.h trace-dtrace.h-timestamp
diff --git a/Makefile.objs b/Makefile.objs
index 5ebbcfa..4412757 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -77,6 +77,7 @@ common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += pflib.o
common-obj-y += bitmap.o bitops.o
+common-obj-y += page_cache.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
common-obj-$(CONFIG_WIN32) += version.o
@@ -96,6 +97,12 @@ common-obj-y += qemu-timer.o qemu-timer-common.o
common-obj-$(CONFIG_SLIRP) += slirp/
######################################################################
+# libseccomp
+ifeq ($(CONFIG_SECCOMP),y)
+common-obj-y += qemu-seccomp.o
+endif
+
+######################################################################
# libuser
user-obj-y =
@@ -211,6 +218,7 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
# qapi
qapi-obj-y = qapi/
+qapi-obj-y += qapi-types.o qapi-visit.o
common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o
common-obj-y += qmp.o hmp.o
diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index 9ba7079..2878058 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -1,6 +1,23 @@
QEMU Monitor Protocol Events
============================
+BALLOON_CHANGE
+--------------
+
+Emitted when the guest changes the actual BALLOON level. This
+value is equivalent to the 'actual' field return by the
+'query-balloon' command
+
+Data:
+
+- "actual": actual level of the guest memory balloon in bytes (json-number)
+
+Example:
+
+{ "event": "BALLOON_CHANGE",
+ "data": { "actual": 944766976 },
+ "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+
BLOCK_IO_ERROR
--------------
@@ -26,6 +43,57 @@ Example:
Note: If action is "stop", a STOP event will eventually follow the
BLOCK_IO_ERROR event.
+BLOCK_JOB_CANCELLED
+-------------------
+
+Emitted when a block job has been cancelled.
+
+Data:
+
+- "type": Job type ("stream" for image streaming, json-string)
+- "device": Device name (json-string)
+- "len": Maximum progress value (json-int)
+- "offset": Current progress value (json-int)
+ On success this is equal to len.
+ On failure this is less than len.
+- "speed": Rate limit, bytes per second (json-int)
+
+Example:
+
+{ "event": "BLOCK_JOB_CANCELLED",
+ "data": { "type": "stream", "device": "virtio-disk0",
+ "len": 10737418240, "offset": 134217728,
+ "speed": 0 },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+BLOCK_JOB_COMPLETED
+-------------------
+
+Emitted when a block job has completed.
+
+Data:
+
+- "type": Job type ("stream" for image streaming, json-string)
+- "device": Device name (json-string)
+- "len": Maximum progress value (json-int)
+- "offset": Current progress value (json-int)
+ On success this is equal to len.
+ On failure this is less than len.
+- "speed": Rate limit, bytes per second (json-int)
+- "error": Error message (json-string, optional)
+ Only present on failure. This field contains a human-readable
+ error message. There are no semantics other than that streaming
+ has failed and clients should not try to interpret the error
+ string.
+
+Example:
+
+{ "event": "BLOCK_JOB_COMPLETED",
+ "data": { "type": "stream", "device": "virtio-disk0",
+ "len": 10737418240, "offset": 10737418240,
+ "speed": 0 },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
DEVICE_TRAY_MOVED
-----------------
@@ -98,6 +166,68 @@ Example:
Note: If the command-line option "-no-shutdown" has been specified, a STOP
event will eventually follow the SHUTDOWN event.
+SPICE_CONNECTED, SPICE_DISCONNECTED
+-----------------------------------
+
+Emitted when a SPICE client connects or disconnects.
+
+Data:
+
+- "server": Server information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+- "client": Client information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+ "event": "SPICE_CONNECTED",
+ "data": {
+ "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+ "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+}}
+
+SPICE_INITIALIZED
+-----------------
+
+Emitted after initial handshake and authentication takes place (if any)
+and the SPICE channel is up'n'running
+
+Data:
+
+- "server": Server information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "connection-id": spice connection id. All channels with the same id
+ belong to the same spice session (json-int)
+ - "channel-type": channel type. "1" is the main control channel, filter for
+ this one if you want track spice sessions only (json-int)
+ - "channel-id": channel id. Usually "0", might be different needed when
+ multiple channels of the same type exist, such as multiple
+ display channels in a multihead setup (json-int)
+ - "tls": whevener the channel is encrypted (json-bool)
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+ "event": "SPICE_INITIALIZED",
+ "data": {"server": {"auth": "spice", "port": "5921",
+ "family": "ipv4", "host": "127.0.0.1"},
+ "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
+ "connection-id": 1804289383, "host": "127.0.0.1",
+ "channel-id": 0, "tls": true}
+}}
+
STOP
----
@@ -110,6 +240,32 @@ Example:
{ "event": "STOP",
"timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
+SUSPEND
+-------
+
+Emitted when guest enters S3 state.
+
+Data: None.
+
+Example:
+
+{ "event": "SUSPEND",
+ "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+
+SUSPEND_DISK
+------------
+
+Emitted when the guest makes a request to enter S4 state.
+
+Data: None.
+
+Example:
+
+{ "event": "SUSPEND_DISK",
+ "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+
+Note: QEMU shuts down when entering S4 state.
+
VNC_CONNECTED
-------------
@@ -200,69 +356,17 @@ Example:
"host": "127.0.0.1", "sasl_username": "luiz" } },
"timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
-SPICE_CONNECTED, SPICE_DISCONNECTED
------------------------------------
-
-Emitted when a SPICE client connects or disconnects.
-
-Data:
-
-- "server": Server information (json-object)
- - "host": IP address (json-string)
- - "port": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
-- "client": Client information (json-object)
- - "host": IP address (json-string)
- - "port": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
- "event": "SPICE_CONNECTED",
- "data": {
- "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
- "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
-}}
-
-
-SPICE_INITIALIZED
------------------
-
-Emitted after initial handshake and authentication takes place (if any)
-and the SPICE channel is up'n'running
+WAKEUP
+------
-Data:
+Emitted when the guest has woken up from S3 and is running.
-- "server": Server information (json-object)
- - "host": IP address (json-string)
- - "port": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
- - "host": IP address (json-string)
- - "port": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "connection-id": spice connection id. All channels with the same id
- belong to the same spice session (json-int)
- - "channel-type": channel type. "1" is the main control channel, filter for
- this one if you want track spice sessions only (json-int)
- - "channel-id": channel id. Usually "0", might be different needed when
- multiple channels of the same type exist, such as multiple
- display channels in a multihead setup (json-int)
- - "tls": whevener the channel is encrypted (json-bool)
+Data: None.
Example:
-{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
- "event": "SPICE_INITIALIZED",
- "data": {"server": {"auth": "spice", "port": "5921",
- "family": "ipv4", "host": "127.0.0.1"},
- "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
- "connection-id": 1804289383, "host": "127.0.0.1",
- "channel-id": 0, "tls": true}
-}}
-
+{ "event": "WATCHDOG",
+ "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
WATCHDOG
--------
@@ -282,74 +386,3 @@ Example:
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events.
-
-
-BLOCK_JOB_COMPLETED
--------------------
-
-Emitted when a block job has completed.
-
-Data:
-
-- "type": Job type ("stream" for image streaming, json-string)
-- "device": Device name (json-string)
-- "len": Maximum progress value (json-int)
-- "offset": Current progress value (json-int)
- On success this is equal to len.
- On failure this is less than len.
-- "speed": Rate limit, bytes per second (json-int)
-- "error": Error message (json-string, optional)
- Only present on failure. This field contains a human-readable
- error message. There are no semantics other than that streaming
- has failed and clients should not try to interpret the error
- string.
-
-Example:
-
-{ "event": "BLOCK_JOB_COMPLETED",
- "data": { "type": "stream", "device": "virtio-disk0",
- "len": 10737418240, "offset": 10737418240,
- "speed": 0 },
- "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-
-BLOCK_JOB_CANCELLED
--------------------
-
-Emitted when a block job has been cancelled.
-
-Data:
-
-- "type": Job type ("stream" for image streaming, json-string)
-- "device": Device name (json-string)
-- "len": Maximum progress value (json-int)
-- "offset": Current progress value (json-int)
- On success this is equal to len.
- On failure this is less than len.
-- "speed": Rate limit, bytes per second (json-int)
-
-Example:
-
-{ "event": "BLOCK_JOB_CANCELLED",
- "data": { "type": "stream", "device": "virtio-disk0",
- "len": 10737418240, "offset": 134217728,
- "speed": 0 },
- "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-
-BALLOON_CHANGE
-----------
-
-Emitted when the guest changes the actual BALLOON level. This
-value is equivalent to the 'actual' field return by the
-'query-balloon' command
-
-Data:
-
-- "actual": actual level of the guest memory balloon in bytes (json-number)
-
-Example:
-
-{ "event": "BALLOON_CHANGE",
- "data": { "actual": 944766976 },
- "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
index 1ba916c..a277896 100644
--- a/QMP/qmp-spec.txt
+++ b/QMP/qmp-spec.txt
@@ -106,14 +106,11 @@ completed because of an error condition.
The format is:
-{ "error": { "class": json-string, "data": json-object, "desc": json-string },
- "id": json-value }
+{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
Where,
-- The "class" member contains the error class name (eg. "ServiceUnavailable")
-- The "data" member contains specific error data and is defined in a
- per-command basis, it will be an empty json-object if the error has no data
+- The "class" member contains the error class name (eg. "GenericError")
- The "desc" member is a human-readable error message. Clients should
not attempt to parse this message.
- The "id" member contains the transaction identification associated with
@@ -173,8 +170,7 @@ S: {"return": {"enabled": true, "present": true}, "id": "example"}
------------------
C: { "execute": }
-S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
-{}}}
+S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
3.5 Powerdown event
-------------------
diff --git a/VERSION b/VERSION
index da44c7f..26aaba0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.50
+1.2.0
diff --git a/VERSION.LINARO b/VERSION.LINARO
index 43e6f54..7ac4e2e 100644
--- a/VERSION.LINARO
+++ b/VERSION.LINARO
@@ -1 +1 @@
-qemu-linaro 2012.08
+qemu-linaro 2012.09
diff --git a/arch_init.c b/arch_init.c
index 60823ba..5a1173e 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -43,6 +43,8 @@
#include "hw/smbios.h"
#include "exec-memory.h"
#include "hw/pcspk.h"
+#include "qemu/page_cache.h"
+#include "qmp-commands.h"
#ifdef DEBUG_ARCH_INIT
#define DPRINTF(fmt, ...) \
@@ -91,6 +93,8 @@ int graphic_depth = 15;
#define QEMU_ARCH QEMU_ARCH_SPARC
#elif defined(TARGET_XTENSA)
#define QEMU_ARCH QEMU_ARCH_XTENSA
+#elif defined(TARGET_UNICORE32)
+#define QEMU_ARCH QEMU_ARCH_UNICORE32
#endif
const uint32_t arch_type = QEMU_ARCH;
@@ -104,6 +108,7 @@ const uint32_t arch_type = QEMU_ARCH;
#define RAM_SAVE_FLAG_PAGE 0x08
#define RAM_SAVE_FLAG_EOS 0x10
#define RAM_SAVE_FLAG_CONTINUE 0x20
+#define RAM_SAVE_FLAG_XBZRLE 0x40
#ifdef __ALTIVEC__
#include <altivec.h>
@@ -171,6 +176,92 @@ static int is_dup_page(uint8_t *page)
return 1;
}
+/* struct contains XBZRLE cache and a static page
+ used by the compression */
+static struct {
+ /* buffer used for XBZRLE encoding */
+ uint8_t *encoded_buf;
+ /* buffer for storing page content */
+ uint8_t *current_buf;
+ /* buffer used for XBZRLE decoding */
+ uint8_t *decoded_buf;
+ /* Cache for XBZRLE */
+ PageCache *cache;
+} XBZRLE = {
+ .encoded_buf = NULL,
+ .current_buf = NULL,
+ .decoded_buf = NULL,
+ .cache = NULL,
+};
+
+
+int64_t xbzrle_cache_resize(int64_t new_size)
+{
+ if (XBZRLE.cache != NULL) {
+ return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) *
+ TARGET_PAGE_SIZE;
+ }
+ return pow2floor(new_size);
+}
+
+/* accounting for migration statistics */
+typedef struct AccountingInfo {
+ uint64_t dup_pages;
+ uint64_t norm_pages;
+ uint64_t iterations;
+ uint64_t xbzrle_bytes;
+ uint64_t xbzrle_pages;
+ uint64_t xbzrle_cache_miss;
+ uint64_t xbzrle_overflows;
+} AccountingInfo;
+
+static AccountingInfo acct_info;
+
+static void acct_clear(void)
+{
+ memset(&acct_info, 0, sizeof(acct_info));
+}
+
+uint64_t dup_mig_bytes_transferred(void)
+{
+ return acct_info.dup_pages * TARGET_PAGE_SIZE;
+}
+
+uint64_t dup_mig_pages_transferred(void)
+{
+ return acct_info.dup_pages;
+}
+
+uint64_t norm_mig_bytes_transferred(void)
+{
+ return acct_info.norm_pages * TARGET_PAGE_SIZE;
+}
+
+uint64_t norm_mig_pages_transferred(void)
+{
+ return acct_info.norm_pages;
+}
+
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+ return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+ return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+ return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+ return acct_info.xbzrle_overflows;
+}
+
static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
int cont, int flag)
{
@@ -183,6 +274,61 @@ static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
}
+#define ENCODING_FLAG_XBZRLE 0x1
+
+static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
+ ram_addr_t current_addr, RAMBlock *block,
+ ram_addr_t offset, int cont, bool last_stage)
+{
+ int encoded_len = 0, bytes_sent = -1;
+ uint8_t *prev_cached_page;
+
+ if (!cache_is_cached(XBZRLE.cache, current_addr)) {
+ if (!last_stage) {
+ cache_insert(XBZRLE.cache, current_addr,
+ g_memdup(current_data, TARGET_PAGE_SIZE));
+ }
+ acct_info.xbzrle_cache_miss++;
+ return -1;
+ }
+
+ prev_cached_page = get_cached_data(XBZRLE.cache, current_addr);
+
+ /* save current buffer into memory */
+ memcpy(XBZRLE.current_buf, current_data, TARGET_PAGE_SIZE);
+
+ /* XBZRLE encoding (if there is no overflow) */
+ encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf,
+ TARGET_PAGE_SIZE, XBZRLE.encoded_buf,
+ TARGET_PAGE_SIZE);
+ if (encoded_len == 0) {
+ DPRINTF("Skipping unmodified page\n");
+ return 0;
+ } else if (encoded_len == -1) {
+ DPRINTF("Overflow\n");
+ acct_info.xbzrle_overflows++;
+ /* update data in the cache */
+ memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
+ return -1;
+ }
+
+ /* we need to update the data in the cache, in order to get the same data */
+ if (!last_stage) {
+ memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE);
+ }
+
+ /* Send XBZRLE based compressed page */
+ save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE);
+ qemu_put_byte(f, ENCODING_FLAG_XBZRLE);
+ qemu_put_be16(f, encoded_len);
+ qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
+ bytes_sent = encoded_len + 1 + 2;
+ acct_info.xbzrle_pages++;
+ acct_info.xbzrle_bytes += bytes_sent;
+
+ return bytes_sent;
+}
+
static RAMBlock *last_block;
static ram_addr_t last_offset;
@@ -194,12 +340,13 @@ static ram_addr_t last_offset;
* n: the amount of bytes written in other case
*/
-static int ram_save_block(QEMUFile *f)
+static int ram_save_block(QEMUFile *f, bool last_stage)
{
RAMBlock *block = last_block;
ram_addr_t offset = last_offset;
int bytes_sent = -1;
MemoryRegion *mr;
+ ram_addr_t current_addr;
if (!block)
block = QLIST_FIRST(&ram_list.blocks);
@@ -217,16 +364,31 @@ static int ram_save_block(QEMUFile *f)
p = memory_region_get_ram_ptr(mr) + offset;
if (is_dup_page(p)) {
+ acct_info.dup_pages++;
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
qemu_put_byte(f, *p);
bytes_sent = 1;
- } else {
+ } else if (migrate_use_xbzrle()) {
+ current_addr = block->offset + offset;
+ bytes_sent = save_xbzrle_page(f, p, current_addr, block,
+ offset, cont, last_stage);
+ if (!last_stage) {
+ p = get_cached_data(XBZRLE.cache, current_addr);
+ }
+ }
+
+ /* either we didn't send yet (we may have had XBZRLE overflow) */
+ if (bytes_sent == -1) {
save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
bytes_sent = TARGET_PAGE_SIZE;
+ acct_info.norm_pages++;
}
- break;
+ /* if page is unmodified, continue to the next */
+ if (bytes_sent != 0) {
+ break;
+ }
}
offset += TARGET_PAGE_SIZE;
@@ -304,6 +466,15 @@ static void sort_ram_list(void)
static void migration_end(void)
{
memory_global_dirty_log_stop();
+
+ if (migrate_use_xbzrle()) {
+ cache_fini(XBZRLE.cache);
+ g_free(XBZRLE.cache);
+ g_free(XBZRLE.encoded_buf);
+ g_free(XBZRLE.current_buf);
+ g_free(XBZRLE.decoded_buf);
+ XBZRLE.cache = NULL;
+ }
}
static void ram_migration_cancel(void *opaque)
@@ -323,6 +494,19 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
last_offset = 0;
sort_ram_list();
+ if (migrate_use_xbzrle()) {
+ XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
+ TARGET_PAGE_SIZE,
+ TARGET_PAGE_SIZE);
+ if (!XBZRLE.cache) {
+ DPRINTF("Error creating cache\n");
+ return -1;
+ }
+ XBZRLE.encoded_buf = g_malloc0(TARGET_PAGE_SIZE);
+ XBZRLE.current_buf = g_malloc(TARGET_PAGE_SIZE);
+ acct_clear();
+ }
+
/* Make sure all dirty bits are set */
QLIST_FOREACH(block, &ram_list.blocks, next) {
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
@@ -363,12 +547,13 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
while ((ret = qemu_file_rate_limit(f)) == 0) {
int bytes_sent;
- bytes_sent = ram_save_block(f);
+ bytes_sent = ram_save_block(f, false);
/* no more blocks to sent */
if (bytes_sent < 0) {
break;
}
bytes_transferred += bytes_sent;
+ acct_info.iterations++;
/* we want to check in the 1st loop, just in case it was the 1st time
and we had to sync the dirty bitmap.
qemu_get_clock_ns() is a bit expensive, so we only check each some
@@ -424,7 +609,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
while (true) {
int bytes_sent;
- bytes_sent = ram_save_block(f);
+ bytes_sent = ram_save_block(f, true);
/* no more blocks to sent */
if (bytes_sent < 0) {
break;
@@ -438,6 +623,47 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
return 0;
}
+static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
+{
+ int ret, rc = 0;
+ unsigned int xh_len;
+ int xh_flags;
+
+ if (!XBZRLE.decoded_buf) {
+ XBZRLE.decoded_buf = g_malloc(TARGET_PAGE_SIZE);
+ }
+
+ /* extract RLE header */
+ xh_flags = qemu_get_byte(f);
+ xh_len = qemu_get_be16(f);
+
+ if (xh_flags != ENCODING_FLAG_XBZRLE) {
+ fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n");
+ return -1;
+ }
+
+ if (xh_len > TARGET_PAGE_SIZE) {
+ fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n");
+ return -1;
+ }
+ /* load data and decode */
+ qemu_get_buffer(f, XBZRLE.decoded_buf, xh_len);
+
+ /* decode RLE */
+ ret = xbzrle_decode_buffer(XBZRLE.decoded_buf, xh_len, host,
+ TARGET_PAGE_SIZE);
+ if (ret == -1) {
+ fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
+ rc = -1;
+ } else if (ret > TARGET_PAGE_SIZE) {
+ fprintf(stderr, "Failed to load XBZRLE page - size %d exceeds %d!\n",
+ ret, TARGET_PAGE_SIZE);
+ abort();
+ }
+
+ return rc;
+}
+
static inline void *host_from_stream_offset(QEMUFile *f,
ram_addr_t offset,
int flags)
@@ -551,6 +777,19 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
}
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
+ } else if (flags & RAM_SAVE_FLAG_XBZRLE) {
+ if (!migrate_use_xbzrle()) {
+ return -EINVAL;
+ }
+ void *host = host_from_stream_offset(f, addr, flags);
+ if (!host) {
+ return -EINVAL;
+ }
+
+ if (load_xbzrle(f, addr, host) < 0) {
+ ret = -EINVAL;
+ goto done;
+ }
}
error = qemu_file_get_error(f);
if (error) {
@@ -842,3 +1081,13 @@ int xen_available(void)
return 0;
#endif
}
+
+
+TargetInfo *qmp_query_target(Error **errp)
+{
+ TargetInfo *info = g_malloc0(sizeof(*info));
+
+ info->arch = TARGET_TYPE;
+
+ return info;
+}
diff --git a/arch_init.h b/arch_init.h
index 3dfea3b..d9c572a 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -1,6 +1,8 @@
#ifndef QEMU_ARCH_INIT_H
#define QEMU_ARCH_INIT_H
+#include "qmp-commands.h"
+
enum {
QEMU_ARCH_ALL = -1,
QEMU_ARCH_ALPHA = 1,
@@ -17,6 +19,7 @@ enum {
QEMU_ARCH_SPARC = 2048,
QEMU_ARCH_XTENSA = 4096,
QEMU_ARCH_OPENRISC = 8192,
+ QEMU_ARCH_UNICORE32 = 0x4000,
};
extern const uint32_t arch_type;
@@ -31,4 +34,6 @@ int tcg_available(void);
int kvm_available(void);
int xen_available(void);
+CpuDefinitionInfoList GCC_WEAK_DECL *arch_query_cpu_definitions(Error **errp);
+
#endif
diff --git a/audio/winwaveaudio.c b/audio/winwaveaudio.c
index 663abb9..72babbf 100644
--- a/audio/winwaveaudio.c
+++ b/audio/winwaveaudio.c
@@ -349,21 +349,15 @@ static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
else {
hw->poll_mode = 0;
}
- if (wave->paused) {
- mr = waveOutRestart (wave->hwo);
- if (mr != MMSYSERR_NOERROR) {
- winwave_logerr (mr, "waveOutRestart");
- }
- wave->paused = 0;
- }
+ wave->paused = 0;
}
return 0;
case VOICE_DISABLE:
if (!wave->paused) {
- mr = waveOutPause (wave->hwo);
+ mr = waveOutReset (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
- winwave_logerr (mr, "waveOutPause");
+ winwave_logerr (mr, "waveOutReset");
}
else {
wave->paused = 1;
diff --git a/block.c b/block.c
index 24323c1..470bdcc 100644
--- a/block.c
+++ b/block.c
@@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
info->value->inserted->ro = bs->read_only;
info->value->inserted->drv = g_strdup(bs->drv->format_name);
info->value->inserted->encrypted = bs->encrypted;
+ info->value->inserted->encryption_key_missing = bdrv_key_required(bs);
if (bs->backing_file[0]) {
info->value->inserted->has_backing_file = true;
info->value->inserted->backing_file = g_strdup(bs->backing_file);
@@ -3533,7 +3534,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
/* But don't actually force it to the disk with cache=unsafe */
if (bs->open_flags & BDRV_O_NO_FLUSH) {
- return 0;
+ goto flush_parent;
}
if (bs->drv->bdrv_co_flush_to_disk) {
@@ -3572,6 +3573,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
/* Now flush the underlying protocol. It will also have BDRV_O_NO_FLUSH
* in the case of cache=unsafe, so there are no useless flushes.
*/
+flush_parent:
return bdrv_co_flush(bs->file);
}
diff --git a/block.h b/block.h
index 650d872..2e2be11 100644
--- a/block.h
+++ b/block.h
@@ -79,6 +79,7 @@ typedef struct BlockDevOps {
#define BDRV_O_NO_FLUSH 0x0200 /* disable flushing on this disk */
#define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */
#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
+#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
diff --git a/block/iscsi.c b/block/iscsi.c
index 993a86d..0b96165 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -73,9 +73,43 @@ struct IscsiTask {
};
static void
+iscsi_bh_cb(void *p)
+{
+ IscsiAIOCB *acb = p;
+
+ qemu_bh_delete(acb->bh);
+
+ if (acb->canceled == 0) {
+ acb->common.cb(acb->common.opaque, acb->status);
+ }
+
+ if (acb->task != NULL) {
+ scsi_free_scsi_task(acb->task);
+ acb->task = NULL;
+ }
+
+ qemu_aio_release(acb);
+}
+
+static void
+iscsi_schedule_bh(IscsiAIOCB *acb)
+{
+ if (acb->bh) {
+ return;
+ }
+ acb->bh = qemu_bh_new(iscsi_bh_cb, acb);
+ qemu_bh_schedule(acb->bh);
+}
+
+
+static void
iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
void *private_data)
{
+ IscsiAIOCB *acb = private_data;
+
+ acb->status = -ECANCELED;
+ iscsi_schedule_bh(acb);
}
static void
@@ -84,15 +118,19 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
IscsiLun *iscsilun = acb->iscsilun;
- acb->common.cb(acb->common.opaque, -ECANCELED);
+ if (acb->status != -EINPROGRESS) {
+ return;
+ }
+
acb->canceled = 1;
/* send a task mgmt call to the target to cancel the task on the target */
iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
- iscsi_abort_task_cb, NULL);
+ iscsi_abort_task_cb, acb);
- /* then also cancel the task locally in libiscsi */
- iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
+ while (acb->status == -EINPROGRESS) {
+ qemu_aio_wait();
+ }
}
static AIOPool iscsi_aio_pool = {
@@ -159,34 +197,6 @@ iscsi_process_write(void *arg)
}
-static int
-iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
-{
- acb->bh = qemu_bh_new(cb, acb);
- if (!acb->bh) {
- error_report("oom: could not create iscsi bh");
- return -EIO;
- }
-
- qemu_bh_schedule(acb->bh);
- return 0;
-}
-
-static void
-iscsi_readv_writev_bh_cb(void *p)
-{
- IscsiAIOCB *acb = p;
-
- qemu_bh_delete(acb->bh);
-
- if (acb->canceled == 0) {
- acb->common.cb(acb->common.opaque, acb->status);
- }
-
- qemu_aio_release(acb);
-}
-
-
static void
iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
@@ -198,9 +208,6 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
g_free(acb->buf);
if (acb->canceled != 0) {
- qemu_aio_release(acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
return;
}
@@ -211,9 +218,7 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
acb->status = -EIO;
}
- iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
+ iscsi_schedule_bh(acb);
}
static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
@@ -242,6 +247,8 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
acb->qiov = qiov;
acb->canceled = 0;
+ acb->bh = NULL;
+ acb->status = -EINPROGRESS;
/* XXX we should pass the iovec to write16 to avoid the extra copy */
/* this will allow us to get rid of 'buf' completely */
@@ -299,9 +306,6 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
trace_iscsi_aio_read16_cb(iscsi, status, acb, acb->canceled);
if (acb->canceled != 0) {
- qemu_aio_release(acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
return;
}
@@ -312,9 +316,7 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
acb->status = -EIO;
}
- iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
+ iscsi_schedule_bh(acb);
}
static BlockDriverAIOCB *
@@ -340,6 +342,8 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
acb->qiov = qiov;
acb->canceled = 0;
+ acb->bh = NULL;
+ acb->status = -EINPROGRESS;
acb->read_size = qemu_read_size;
acb->buf = NULL;
@@ -415,9 +419,6 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
IscsiAIOCB *acb = opaque;
if (acb->canceled != 0) {
- qemu_aio_release(acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
return;
}
@@ -428,9 +429,7 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
acb->status = -EIO;
}
- iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
+ iscsi_schedule_bh(acb);
}
static BlockDriverAIOCB *
@@ -445,6 +444,8 @@ iscsi_aio_flush(BlockDriverState *bs,
acb->iscsilun = iscsilun;
acb->canceled = 0;
+ acb->bh = NULL;
+ acb->status = -EINPROGRESS;
acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
0, 0, 0, 0,
@@ -469,9 +470,6 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
IscsiAIOCB *acb = opaque;
if (acb->canceled != 0) {
- qemu_aio_release(acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
return;
}
@@ -482,9 +480,7 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
acb->status = -EIO;
}
- iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
+ iscsi_schedule_bh(acb);
}
static BlockDriverAIOCB *
@@ -501,6 +497,8 @@ iscsi_aio_discard(BlockDriverState *bs,
acb->iscsilun = iscsilun;
acb->canceled = 0;
+ acb->bh = NULL;
+ acb->status = -EINPROGRESS;
list[0].lba = sector_qemu2lun(sector_num, iscsilun);
list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size;
@@ -529,9 +527,6 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
IscsiAIOCB *acb = opaque;
if (acb->canceled != 0) {
- qemu_aio_release(acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
return;
}
@@ -559,9 +554,7 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
memcpy(acb->ioh->sbp, &acb->task->datain.data[2], ss);
}
- iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
- scsi_free_scsi_task(acb->task);
- acb->task = NULL;
+ iscsi_schedule_bh(acb);
}
static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
@@ -579,6 +572,8 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
acb->iscsilun = iscsilun;
acb->canceled = 0;
+ acb->bh = NULL;
+ acb->status = -EINPROGRESS;
acb->buf = NULL;
acb->ioh = buf;
@@ -726,7 +721,12 @@ iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
}
itask->iscsilun->block_size = rc10->block_size;
- itask->iscsilun->num_blocks = rc10->lba + 1;
+ if (rc10->lba == 0) {
+ /* blank disk loaded */
+ itask->iscsilun->num_blocks = 0;
+ } else {
+ itask->iscsilun->num_blocks = rc10->lba + 1;
+ }
itask->bs->total_sectors = itask->iscsilun->num_blocks *
itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
@@ -896,26 +896,26 @@ static char *parse_initiator_name(const char *target)
QemuOptsList *list;
QemuOpts *opts;
const char *name = NULL;
+ const char *iscsi_name = qemu_get_vm_name();
list = qemu_find_opts("iscsi");
- if (!list) {
- return g_strdup("iqn.2008-11.org.linux-kvm");
- }
-
- opts = qemu_opts_find(list, target);
- if (opts == NULL) {
- opts = QTAILQ_FIRST(&list->head);
+ if (list) {
+ opts = qemu_opts_find(list, target);
if (!opts) {
- return g_strdup("iqn.2008-11.org.linux-kvm");
+ opts = QTAILQ_FIRST(&list->head);
+ }
+ if (opts) {
+ name = qemu_opt_get(opts, "initiator-name");
}
}
- name = qemu_opt_get(opts, "initiator-name");
- if (!name) {
- return g_strdup("iqn.2008-11.org.linux-kvm");
+ if (name) {
+ return g_strdup(name);
+ } else {
+ return g_strdup_printf("iqn.2008-11.org.linux-kvm%s%s",
+ iscsi_name ? ":" : "",
+ iscsi_name ? iscsi_name : "");
}
-
- return g_strdup(name);
}
/*
@@ -943,7 +943,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
error_report("Failed to parse URL : %s %s", filename,
iscsi_get_error(iscsi));
ret = -EINVAL;
- goto failed;
+ goto out;
}
memset(iscsilun, 0, sizeof(IscsiLun));
@@ -954,13 +954,13 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
if (iscsi == NULL) {
error_report("iSCSI: Failed to create iSCSI context.");
ret = -ENOMEM;
- goto failed;
+ goto out;
}
if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
error_report("iSCSI: Failed to set target name.");
ret = -EINVAL;
- goto failed;
+ goto out;
}
if (iscsi_url->user != NULL) {
@@ -969,7 +969,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
if (ret != 0) {
error_report("Failed to set initiator username and password");
ret = -EINVAL;
- goto failed;
+ goto out;
}
}
@@ -977,13 +977,13 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
if (parse_chap(iscsi, iscsi_url->target) != 0) {
error_report("iSCSI: Failed to set CHAP user/password");
ret = -EINVAL;
- goto failed;
+ goto out;
}
if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
error_report("iSCSI: Failed to set session type to normal.");
ret = -EINVAL;
- goto failed;
+ goto out;
}
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
@@ -1004,7 +1004,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
!= 0) {
error_report("iSCSI: Failed to start async connect.");
ret = -EINVAL;
- goto failed;
+ goto out;
}
while (!task.complete) {
@@ -1015,11 +1015,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
error_report("iSCSI: Failed to connect to LUN : %s",
iscsi_get_error(iscsi));
ret = -EINVAL;
- goto failed;
- }
-
- if (iscsi_url != NULL) {
- iscsi_destroy_url(iscsi_url);
+ goto out;
}
/* Medium changer or tape. We dont have any emulation for this so this must
@@ -1031,19 +1027,22 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
bs->sg = 1;
}
- return 0;
+ ret = 0;
-failed:
+out:
if (initiator_name != NULL) {
g_free(initiator_name);
}
if (iscsi_url != NULL) {
iscsi_destroy_url(iscsi_url);
}
- if (iscsi != NULL) {
- iscsi_destroy_context(iscsi);
+
+ if (ret) {
+ if (iscsi != NULL) {
+ iscsi_destroy_context(iscsi);
+ }
+ memset(iscsilun, 0, sizeof(IscsiLun));
}
- memset(iscsilun, 0, sizeof(IscsiLun));
return ret;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index fd5e214..8f183f1 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -270,6 +270,20 @@ static int qcow2_mark_clean(BlockDriverState *bs)
return 0;
}
+static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
+ BdrvCheckMode fix)
+{
+ int ret = qcow2_check_refcounts(bs, result, fix);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (fix && result->check_errors == 0 && result->corruptions == 0) {
+ return qcow2_mark_clean(bs);
+ }
+ return ret;
+}
+
static int qcow2_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
@@ -470,16 +484,11 @@ static int qcow2_open(BlockDriverState *bs, int flags)
qemu_co_mutex_init(&s->lock);
/* Repair image if dirty */
- if ((s->incompatible_features & QCOW2_INCOMPAT_DIRTY) &&
- !bs->read_only) {
+ if (!(flags & BDRV_O_CHECK) && !bs->read_only &&
+ (s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
BdrvCheckResult result = {0};
- ret = qcow2_check_refcounts(bs, &result, BDRV_FIX_ERRORS);
- if (ret < 0) {
- goto fail;
- }
-
- ret = qcow2_mark_clean(bs);
+ ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS);
if (ret < 0) {
goto fail;
}
@@ -1568,13 +1577,6 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0;
}
-
-static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
- BdrvCheckMode fix)
-{
- return qcow2_check_refcounts(bs, result, fix);
-}
-
#if 0
static void dump_refcounts(BlockDriverState *bs)
{
diff --git a/block/qed-check.c b/block/qed-check.c
index 5edf607..b473dcd 100644
--- a/block/qed-check.c
+++ b/block/qed-check.c
@@ -194,6 +194,28 @@ static void qed_check_for_leaks(QEDCheck *check)
}
}
+/**
+ * Mark an image clean once it passes check or has been repaired
+ */
+static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
+{
+ /* Skip if there were unfixable corruptions or I/O errors */
+ if (result->corruptions > 0 || result->check_errors > 0) {
+ return;
+ }
+
+ /* Skip if image is already marked clean */
+ if (!(s->header.features & QED_F_NEED_CHECK)) {
+ return;
+ }
+
+ /* Ensure fixes reach storage before clearing check bit */
+ bdrv_flush(s->bs);
+
+ s->header.features &= ~QED_F_NEED_CHECK;
+ qed_write_header_sync(s);
+}
+
int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
{
QEDCheck check = {
@@ -215,6 +237,10 @@ int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
if (ret == 0) {
/* Only check for leaks if entire image was scanned successfully */
qed_check_for_leaks(&check);
+
+ if (fix) {
+ qed_check_mark_clean(s, result);
+ }
}
g_free(check.used_clusters);
diff --git a/block/qed.c b/block/qed.c
index 5f3eefa..21cb239 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -89,7 +89,7 @@ static void qed_header_cpu_to_le(const QEDHeader *cpu, QEDHeader *le)
le->backing_filename_size = cpu_to_le32(cpu->backing_filename_size);
}
-static int qed_write_header_sync(BDRVQEDState *s)
+int qed_write_header_sync(BDRVQEDState *s)
{
QEDHeader le;
int ret;
@@ -477,7 +477,7 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
}
/* If image was not closed cleanly, check consistency */
- if (s->header.features & QED_F_NEED_CHECK) {
+ if (!(flags & BDRV_O_CHECK) && (s->header.features & QED_F_NEED_CHECK)) {
/* Read-only images cannot be fixed. There is no risk of corruption
* since write operations are not possible. Therefore, allow
* potentially inconsistent images to be opened read-only. This can
@@ -491,13 +491,6 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
if (ret) {
goto out;
}
- if (!result.corruptions && !result.check_errors) {
- /* Ensure fixes reach storage before clearing check bit */
- bdrv_flush(s->bs);
-
- s->header.features &= ~QED_F_NEED_CHECK;
- qed_write_header_sync(s);
- }
}
}
@@ -1370,10 +1363,21 @@ static int coroutine_fn bdrv_qed_co_write_zeroes(BlockDriverState *bs,
int nb_sectors)
{
BlockDriverAIOCB *blockacb;
+ BDRVQEDState *s = bs->opaque;
QEDWriteZeroesCB cb = { .done = false };
QEMUIOVector qiov;
struct iovec iov;
+ /* Refuse if there are untouched backing file sectors */
+ if (bs->backing_hd) {
+ if (qed_offset_into_cluster(s, sector_num * BDRV_SECTOR_SIZE) != 0) {
+ return -ENOTSUP;
+ }
+ if (qed_offset_into_cluster(s, nb_sectors * BDRV_SECTOR_SIZE) != 0) {
+ return -ENOTSUP;
+ }
+ }
+
/* Zero writes start without an I/O buffer. If a buffer becomes necessary
* then it will be allocated during request processing.
*/
diff --git a/block/qed.h b/block/qed.h
index c716772..a063bf7 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -211,6 +211,11 @@ void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque);
void gencb_complete(void *opaque, int ret);
/**
+ * Header functions
+ */
+int qed_write_header_sync(BDRVQEDState *s);
+
+/**
* L2 cache functions
*/
void qed_init_l2_cache(L2TableCache *l2_cache);
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 0dce089..6be20b1 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -271,7 +271,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
out_free_buf:
qemu_vfree(s->aligned_buf);
out_close:
- close(fd);
+ qemu_close(fd);
return -errno;
}
@@ -376,7 +376,7 @@ static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
if (s->fd >= 0) {
- close(s->fd);
+ qemu_close(s->fd);
s->fd = -1;
if (s->aligned_buf != NULL)
qemu_vfree(s->aligned_buf);
@@ -572,15 +572,15 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
options++;
}
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
- 0644);
+ fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ 0644);
if (fd < 0) {
result = -errno;
} else {
if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
result = -errno;
}
- if (close(fd) != 0) {
+ if (qemu_close(fd) != 0) {
result = -errno;
}
}
@@ -846,11 +846,11 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
if ( bsdPath[ 0 ] != '\0' ) {
strcat(bsdPath,"s0");
/* some CDs don't have a partition 0 */
- fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
+ fd = qemu_open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0) {
bsdPath[strlen(bsdPath)-1] = '1';
} else {
- close(fd);
+ qemu_close(fd);
}
filename = bsdPath;
}
@@ -889,7 +889,7 @@ static int fd_open(BlockDriverState *bs)
last_media_present = (s->fd >= 0);
if (s->fd >= 0 &&
(get_clock() - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
- close(s->fd);
+ qemu_close(s->fd);
s->fd = -1;
#ifdef DEBUG_FLOPPY
printf("Floppy closed\n");
@@ -903,7 +903,7 @@ static int fd_open(BlockDriverState *bs)
#endif
return -EIO;
}
- s->fd = open(bs->filename, s->open_flags & ~O_NONBLOCK);
+ s->fd = qemu_open(bs->filename, s->open_flags & ~O_NONBLOCK);
if (s->fd < 0) {
s->fd_error_time = get_clock();
s->fd_got_error = 1;
@@ -977,7 +977,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
options++;
}
- fd = open(filename, O_WRONLY | O_BINARY);
+ fd = qemu_open(filename, O_WRONLY | O_BINARY);
if (fd < 0)
return -errno;
@@ -988,7 +988,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE)
ret = -ENOSPC;
- close(fd);
+ qemu_close(fd);
return ret;
}
@@ -1038,7 +1038,7 @@ static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
return ret;
/* close fd so that we can reopen it as needed */
- close(s->fd);
+ qemu_close(s->fd);
s->fd = -1;
s->fd_media_changed = 1;
@@ -1052,10 +1052,12 @@ static int floppy_probe_device(const char *filename)
struct floppy_struct fdparam;
struct stat st;
- if (strstart(filename, "/dev/fd", NULL))
+ if (strstart(filename, "/dev/fd", NULL) &&
+ !strstart(filename, "/dev/fdset/", NULL)) {
prio = 50;
+ }
- fd = open(filename, O_RDONLY | O_NONBLOCK);
+ fd = qemu_open(filename, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
goto out;
}
@@ -1070,7 +1072,7 @@ static int floppy_probe_device(const char *filename)
prio = 100;
outc:
- close(fd);
+ qemu_close(fd);
out:
return prio;
}
@@ -1105,14 +1107,14 @@ static void floppy_eject(BlockDriverState *bs, bool eject_flag)
int fd;
if (s->fd >= 0) {
- close(s->fd);
+ qemu_close(s->fd);
s->fd = -1;
}
- fd = open(bs->filename, s->open_flags | O_NONBLOCK);
+ fd = qemu_open(bs->filename, s->open_flags | O_NONBLOCK);
if (fd >= 0) {
if (ioctl(fd, FDEJECT, 0) < 0)
perror("FDEJECT");
- close(fd);
+ qemu_close(fd);
}
}
@@ -1158,7 +1160,7 @@ static int cdrom_probe_device(const char *filename)
int prio = 0;
struct stat st;
- fd = open(filename, O_RDONLY | O_NONBLOCK);
+ fd = qemu_open(filename, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
goto out;
}
@@ -1173,7 +1175,7 @@ static int cdrom_probe_device(const char *filename)
prio = 100;
outc:
- close(fd);
+ qemu_close(fd);
out:
return prio;
}
@@ -1281,8 +1283,8 @@ static int cdrom_reopen(BlockDriverState *bs)
* FreeBSD seems to not notice sometimes...
*/
if (s->fd >= 0)
- close(s->fd);
- fd = open(bs->filename, s->open_flags, 0644);
+ qemu_close(s->fd);
+ fd = qemu_open(bs->filename, s->open_flags, 0644);
if (fd < 0) {
s->fd = -1;
return -EIO;
diff --git a/block/raw-win32.c b/block/raw-win32.c
index e4b0b75..c56bf83 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -255,13 +255,13 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
options++;
}
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
- 0644);
+ fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ 0644);
if (fd < 0)
return -EIO;
set_sparse(fd);
ftruncate(fd, total_size * 512);
- close(fd);
+ qemu_close(fd);
return 0;
}
diff --git a/block/sheepdog.c b/block/sheepdog.c
index a04ad99..df4f441 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -485,6 +485,7 @@ static int connect_to_sdog(const char *addr, const char *port)
if (errno == EINTR) {
goto reconnect;
}
+ close(fd);
break;
}
diff --git a/block/stream.c b/block/stream.c
index 37c4652..c4f87dd 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -122,6 +122,12 @@ wait:
* known-unallocated area [sector_num, sector_num+n). */
ret = bdrv_co_is_allocated_above(bs->backing_hd, base,
sector_num, n, &n);
+
+ /* Finish early if end of backing file has been reached */
+ if (ret == 0 && n == 0) {
+ n = end - sector_num;
+ }
+
copy = (ret == 1);
}
trace_stream_one_iteration(s, sector_num, n, ret);
diff --git a/block/vdi.c b/block/vdi.c
index 57325d6..c4f1529 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -653,8 +653,9 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
options++;
}
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
- 0644);
+ fd = qemu_open(filename,
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+ 0644);
if (fd < 0) {
return -errno;
}
diff --git a/block/vmdk.c b/block/vmdk.c
index 18e9b4c..bba4c61 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -35,6 +35,7 @@
#define VMDK4_FLAG_RGD (1 << 1)
#define VMDK4_FLAG_COMPRESS (1 << 16)
#define VMDK4_FLAG_MARKER (1 << 17)
+#define VMDK4_GD_AT_END 0xffffffffffffffffULL
typedef struct {
uint32_t version;
@@ -57,8 +58,8 @@ typedef struct {
int64_t desc_offset;
int64_t desc_size;
int32_t num_gtes_per_gte;
- int64_t gd_offset;
int64_t rgd_offset;
+ int64_t gd_offset;
int64_t grain_offset;
char filler[1];
char check_bytes[4];
@@ -115,6 +116,13 @@ typedef struct VmdkGrainMarker {
uint8_t data[0];
} VmdkGrainMarker;
+enum {
+ MARKER_END_OF_STREAM = 0,
+ MARKER_GRAIN_TABLE = 1,
+ MARKER_GRAIN_DIRECTORY = 2,
+ MARKER_FOOTER = 3,
+};
+
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
{
uint32_t magic;
@@ -451,6 +459,54 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
if (header.capacity == 0 && header.desc_offset) {
return vmdk_open_desc_file(bs, flags, header.desc_offset << 9);
}
+
+ if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) {
+ /*
+ * The footer takes precedence over the header, so read it in. The
+ * footer starts at offset -1024 from the end: One sector for the
+ * footer, and another one for the end-of-stream marker.
+ */
+ struct {
+ struct {
+ uint64_t val;
+ uint32_t size;
+ uint32_t type;
+ uint8_t pad[512 - 16];
+ } QEMU_PACKED footer_marker;
+
+ uint32_t magic;
+ VMDK4Header header;
+ uint8_t pad[512 - 4 - sizeof(VMDK4Header)];
+
+ struct {
+ uint64_t val;
+ uint32_t size;
+ uint32_t type;
+ uint8_t pad[512 - 16];
+ } QEMU_PACKED eos_marker;
+ } QEMU_PACKED footer;
+
+ ret = bdrv_pread(file,
+ bs->file->total_sectors * 512 - 1536,
+ &footer, sizeof(footer));
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Some sanity checks for the footer */
+ if (be32_to_cpu(footer.magic) != VMDK4_MAGIC ||
+ le32_to_cpu(footer.footer_marker.size) != 0 ||
+ le32_to_cpu(footer.footer_marker.type) != MARKER_FOOTER ||
+ le64_to_cpu(footer.eos_marker.val) != 0 ||
+ le32_to_cpu(footer.eos_marker.size) != 0 ||
+ le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM)
+ {
+ return -EINVAL;
+ }
+
+ header = footer.header;
+ }
+
l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
* le64_to_cpu(header.granularity);
if (l1_entry_sectors == 0) {
@@ -1161,10 +1217,9 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
VMDK4Header header;
uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
- fd = open(
- filename,
- O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
- 0644);
+ fd = qemu_open(filename,
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+ 0644);
if (fd < 0) {
return -errno;
}
@@ -1259,7 +1314,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
ret = 0;
exit:
- close(fd);
+ qemu_close(fd);
return ret;
}
@@ -1484,15 +1539,13 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
(flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
total_size / (int64_t)(63 * 16 * 512));
if (split || flat) {
- fd = open(
- filename,
- O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
- 0644);
+ fd = qemu_open(filename,
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+ 0644);
} else {
- fd = open(
- filename,
- O_WRONLY | O_BINARY | O_LARGEFILE,
- 0644);
+ fd = qemu_open(filename,
+ O_WRONLY | O_BINARY | O_LARGEFILE,
+ 0644);
}
if (fd < 0) {
return -errno;
@@ -1509,7 +1562,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
}
ret = 0;
exit:
- close(fd);
+ qemu_close(fd);
return ret;
}
diff --git a/block/vpc.c b/block/vpc.c
index 5cd13d1..c0b82c4 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -678,7 +678,7 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
}
/* Create the file */
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
if (fd < 0) {
return -EIO;
}
@@ -744,7 +744,7 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
}
fail:
- close(fd);
+ qemu_close(fd);
return ret;
}
diff --git a/block/vvfat.c b/block/vvfat.c
index 7b1dcee..59d3c5b 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1105,7 +1105,7 @@ static inline void vvfat_close_current_file(BDRVVVFATState *s)
if(s->current_mapping) {
s->current_mapping = NULL;
if (s->current_fd) {
- close(s->current_fd);
+ qemu_close(s->current_fd);
s->current_fd = 0;
}
}
@@ -1162,7 +1162,7 @@ static int open_file(BDRVVVFATState* s,mapping_t* mapping)
if(!s->current_mapping ||
strcmp(s->current_mapping->path,mapping->path)) {
/* open file */
- int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
+ int fd = qemu_open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
if(fd<0)
return -1;
vvfat_close_current_file(s);
@@ -2221,7 +2221,7 @@ static int commit_one_file(BDRVVVFATState* s,
for (i = s->cluster_size; i < offset; i += s->cluster_size)
c = modified_fat_get(s, c);
- fd = open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
+ fd = qemu_open(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
if (fd < 0) {
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
strerror(errno), errno);
@@ -2230,7 +2230,7 @@ static int commit_one_file(BDRVVVFATState* s,
}
if (offset > 0) {
if (lseek(fd, offset, SEEK_SET) != offset) {
- close(fd);
+ qemu_close(fd);
g_free(cluster);
return -3;
}
@@ -2251,13 +2251,13 @@ static int commit_one_file(BDRVVVFATState* s,
(uint8_t*)cluster, (rest_size + 0x1ff) / 0x200);
if (ret < 0) {
- close(fd);
+ qemu_close(fd);
g_free(cluster);
return ret;
}
if (write(fd, cluster, rest_size) < 0) {
- close(fd);
+ qemu_close(fd);
g_free(cluster);
return -2;
}
@@ -2268,11 +2268,11 @@ static int commit_one_file(BDRVVVFATState* s,
if (ftruncate(fd, size)) {
perror("ftruncate()");
- close(fd);
+ qemu_close(fd);
g_free(cluster);
return -4;
}
- close(fd);
+ qemu_close(fd);
g_free(cluster);
return commit_mappings(s, first_cluster, dir_index);
diff --git a/block_int.h b/block_int.h
index 6c1d9ca..4452f6f 100644
--- a/block_int.h
+++ b/block_int.h
@@ -30,6 +30,7 @@
#include "qemu-coroutine.h"
#include "qemu-timer.h"
#include "qapi-types.h"
+#include "qerror.h"
#define BLOCK_FLAG_ENCRYPT 1
#define BLOCK_FLAG_COMPAT6 4
diff --git a/blockdev.c b/blockdev.c
index 8669142..7c83baa 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -377,6 +377,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
}
}
+ bdrv_flags |= BDRV_O_CACHE_WB;
if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) {
error_report("invalid cache option");
diff --git a/compiler.h b/compiler.h
index 736e770..07ba1f8 100644
--- a/compiler.h
+++ b/compiler.h
@@ -45,6 +45,13 @@
# define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
# define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
# endif
+#if defined(_WIN32)
+#define GCC_WEAK __attribute__((weak))
+#define GCC_WEAK_DECL GCC_WEAK
+#else
+#define GCC_WEAK __attribute__((weak))
+#define GCC_WEAK_DECL
+#endif
#else
#define GCC_ATTR /**/
#define GCC_FMT_ATTR(n, m)
diff --git a/configure b/configure
index 40f0455..e7ed9d9 100755
--- a/configure
+++ b/configure
@@ -27,16 +27,40 @@ printf " '%s'" "$0" "$@" >> config.log
echo >> config.log
echo "#" >> config.log
+do_cc() {
+ # Run the compiler, capturing its output to the log.
+ echo $cc "$@" >> config.log
+ $cc "$@" >> config.log 2>&1 || return $?
+ # Test passed. If this is an --enable-werror build, rerun
+ # the test with -Werror and bail out if it fails. This
+ # makes warning-generating-errors in configure test code
+ # obvious to developers.
+ if test "$werror" != "yes"; then
+ return 0
+ fi
+ # Don't bother rerunning the compile if we were already using -Werror
+ case "$*" in
+ *-Werror*)
+ return 0
+ ;;
+ esac
+ echo $cc -Werror "$@" >> config.log
+ $cc -Werror "$@" >> config.log 2>&1 && return $?
+ echo "ERROR: configure test passed without -Werror but failed with -Werror."
+ echo "This is probably a bug in the configure script. The failing command"
+ echo "will be at the bottom of config.log."
+ echo "You can run configure with --disable-werror to bypass this check."
+ exit 1
+}
+
compile_object() {
- echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log
- $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1
+ do_cc $QEMU_CFLAGS -c -o $TMPO $TMPC
}
compile_prog() {
local_cflags="$1"
local_ldflags="$2"
- echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log
- $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1
+ do_cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags
}
# symbolically link $1 to $2. Portable version of "ln -sf".
@@ -147,7 +171,6 @@ vhost_net="no"
kvm="no"
gprof="no"
debug_tcg="no"
-debug_mon="no"
debug="no"
strip_opt="yes"
tcg_interpreter="no"
@@ -195,6 +218,7 @@ zlib="yes"
guest_agent="yes"
libiscsi=""
coroutine=""
+seccomp=""
# If this is a Linaro QEMU tarball then default the pkgversion
# string to say so, so that we clearly distinguish ourselves
@@ -282,6 +306,41 @@ EOF
compile_object
}
+if check_define __linux__ ; then
+ targetos="Linux"
+elif check_define _WIN32 ; then
+ targetos='MINGW32'
+elif check_define __OpenBSD__ ; then
+ targetos='OpenBSD'
+elif check_define __sun__ ; then
+ targetos='SunOS'
+elif check_define __HAIKU__ ; then
+ targetos='Haiku'
+else
+ targetos=`uname -s`
+fi
+
+# Some host OSes need non-standard checks for which CPU to use.
+# Note that these checks are broken for cross-compilation: if you're
+# cross-compiling to one of these OSes then you'll need to specify
+# the correct CPU with the --cpu option.
+case $targetos in
+Darwin)
+ # on Leopard most of the system is 32-bit, so we have to ask the kernel if we can
+ # run 64-bit userspace code.
+ # If the user didn't specify a CPU explicitly and the kernel says this is
+ # 64 bit hw, then assume x86_64. Otherwise fall through to the usual detection code.
+ if test -z "$cpu" && test "$(sysctl -n hw.optional.x86_64)" = "1"; then
+ cpu="x86_64"
+ fi
+ ;;
+SunOS)
+ # `uname -m` returns i86pc even on an x86_64 box, so default based on isainfo
+ if test -z "$cpu" && test "$(isainfo -k)" = "amd64"; then
+ cpu="x86_64"
+ fi
+esac
+
if test ! -z "$cpu" ; then
# command line argument
:
@@ -356,19 +415,6 @@ if test -z "$ARCH"; then
fi
# OS specific
-if check_define __linux__ ; then
- targetos="Linux"
-elif check_define _WIN32 ; then
- targetos='MINGW32'
-elif check_define __OpenBSD__ ; then
- targetos='OpenBSD'
-elif check_define __sun__ ; then
- targetos='SunOS'
-elif check_define __HAIKU__ ; then
- targetos='Haiku'
-else
- targetos=`uname -s`
-fi
case $targetos in
CYGWIN*)
@@ -418,12 +464,6 @@ OpenBSD)
Darwin)
bsd="yes"
darwin="yes"
- # on Leopard most of the system is 32-bit, so we have to ask the kernel it if we can
- # run 64-bit userspace code
- if [ "$cpu" = "i386" ] ; then
- is_x86_64=`sysctl -n hw.optional.x86_64`
- [ "$is_x86_64" = "1" ] && cpu=x86_64
- fi
if [ "$cpu" = "x86_64" ] ; then
QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
LDFLAGS="-arch x86_64 $LDFLAGS"
@@ -435,6 +475,9 @@ Darwin)
audio_possible_drivers="coreaudio sdl fmod"
LDFLAGS="-framework CoreFoundation -framework IOKit $LDFLAGS"
libs_softmmu="-F/System/Library/Frameworks -framework Cocoa -framework IOKit $libs_softmmu"
+ # Disable attempts to use ObjectiveC features in os/object.h since they
+ # won't work when we're compiling with gcc as a C compiler.
+ QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
;;
SunOS)
solaris="yes"
@@ -444,12 +487,6 @@ SunOS)
smbd="${SMBD-/usr/sfw/sbin/smbd}"
needs_libsunmath="no"
solarisrev=`uname -r | cut -f2 -d.`
- # have to select again, because `uname -m` returns i86pc
- # even on an x86_64 box.
- solariscpu=`isainfo -k`
- if test "${solariscpu}" = "amd64" ; then
- cpu="x86_64"
- fi
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
if test "$solarisrev" -le 9 ; then
if test -f /opt/SUNWspro/prod/lib/libsunmath.so.1; then
@@ -520,6 +557,13 @@ fi
: ${python=${PYTHON-python}}
: ${smbd=${SMBD-/usr/sbin/smbd}}
+# Default objcc to clang if available, otherwise use CC
+if has clang; then
+ objcc=clang
+else
+ objcc="$cc"
+fi
+
if test "$mingw32" = "yes" ; then
EXESUF=".exe"
QEMU_CFLAGS="-DWIN32_LEAN_AND_MEAN -DWINVER=0x501 $QEMU_CFLAGS"
@@ -563,6 +607,8 @@ for opt do
;;
--host-cc=*) host_cc="$optarg"
;;
+ --objcc=*) objcc="$optarg"
+ ;;
--make=*) make="$optarg"
;;
--install=*) install="$optarg"
@@ -646,14 +692,9 @@ for opt do
;;
--disable-debug-tcg) debug_tcg="no"
;;
- --enable-debug-mon) debug_mon="yes"
- ;;
- --disable-debug-mon) debug_mon="no"
- ;;
--enable-debug)
# Enable debugging options that aren't excessively noisy
debug_tcg="yes"
- debug_mon="yes"
debug="yes"
strip_opt="no"
;;
@@ -837,6 +878,10 @@ for opt do
;;
--disable-guest-agent) guest_agent="no"
;;
+ --enable-seccomp) seccomp="yes"
+ ;;
+ --disable-seccomp) seccomp="no"
+ ;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -948,6 +993,7 @@ sparc64-softmmu \
s390x-softmmu \
xtensa-softmmu \
xtensaeb-softmmu \
+unicore32-softmmu \
"
fi
# the following are Linux specific
@@ -1009,6 +1055,7 @@ echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --host-cc=CC use C compiler CC [$host_cc] for code run at"
echo " build time"
+echo " --objcc=OBJCC use Objective-C compiler OBJCC [$objcc]"
echo " --extra-cflags=CFLAGS append extra C compiler flags QEMU_CFLAGS"
echo " --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS"
echo " --make=MAKE use specified make [$make]"
@@ -1123,6 +1170,8 @@ echo " --disable-usb-redir disable usb network redirection support"
echo " --enable-usb-redir enable usb network redirection support"
echo " --disable-guest-agent disable building of the QEMU Guest Agent"
echo " --enable-guest-agent enable building of the QEMU Guest Agent"
+echo " --disable-seccomp disable seccomp support"
+echo " --enable-seccomp enables seccomp support"
echo " --with-coroutine=BACKEND coroutine backend. Supported options:"
echo " gthread, ucontext, sigaltstack, windows"
echo ""
@@ -1385,6 +1434,20 @@ EOF
fi
##########################################
+# libseccomp check
+
+if test "$seccomp" != "no" ; then
+ if $pkg_config libseccomp --modversion >/dev/null 2>&1; then
+ LIBS=`$pkg_config --libs libseccomp`
+ seccomp="yes"
+ else
+ seccomp="no"
+ if test "$seccomp" = "yes"; then
+ feature_not_found "libseccomp"
+ fi
+ fi
+fi
+##########################################
# xen probe
if test "$xen" != "no" ; then
@@ -2244,7 +2307,7 @@ cat > $TMPC <<EOF
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
-int main(void) { return preadv == preadv; }
+int main(void) { return preadv(0, 0, 0, 0); }
EOF
preadv=no
if compile_prog "" "" ; then
@@ -2540,7 +2603,7 @@ int main(void)
* warning but not an error, and will proceed to fail the
* qemu compile where we compile with -Werror.)
*/
- return epoll_create1 == epoll_create1;
+ return (int)(uintptr_t)&epoll_create1;
}
EOF
if compile_prog "" "" ; then
@@ -2933,7 +2996,7 @@ has_environ=no
cat > $TMPC << EOF
#include <unistd.h>
int main(void) {
- environ = environ;
+ environ = 0;
return 0;
}
EOF
@@ -3039,6 +3102,7 @@ fi
echo "Source path $source_path"
echo "C compiler $cc"
echo "Host C compiler $host_cc"
+echo "Objective-C compiler $objcc"
echo "CFLAGS $CFLAGS"
echo "QEMU_CFLAGS $QEMU_CFLAGS"
echo "LDFLAGS $LDFLAGS"
@@ -3052,7 +3116,6 @@ echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
echo "tcg debug enabled $debug_tcg"
-echo "Mon debug enabled $debug_mon"
echo "gprof enabled $gprof"
echo "sparse enabled $sparse"
echo "strip binaries $strip_opt"
@@ -3114,6 +3177,7 @@ echo "usb net redir $usb_redir"
echo "OpenGL support $opengl"
echo "libiscsi support $libiscsi"
echo "build guest agent $guest_agent"
+echo "seccomp support $seccomp"
echo "coroutine backend $coroutine_backend"
if test "$sdl_too_old" = "yes"; then
@@ -3145,9 +3209,6 @@ echo "ARCH=$ARCH" >> $config_host_mak
if test "$debug_tcg" = "yes" ; then
echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
fi
-if test "$debug_mon" = "yes" ; then
- echo "CONFIG_DEBUG_MONITOR=y" >> $config_host_mak
-fi
if test "$debug" = "yes" ; then
echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak
fi
@@ -3412,6 +3473,10 @@ if test "$libiscsi" = "yes" ; then
echo "CONFIG_LIBISCSI=y" >> $config_host_mak
fi
+if test "$seccomp" = "yes"; then
+ echo "CONFIG_SECCOMP=y" >> $config_host_mak
+fi
+
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "CONFIG_BSD=y" >> $config_host_mak
@@ -3506,6 +3571,7 @@ echo "PYTHON=$python" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
echo "CC_I386=$cc_i386" >> $config_host_mak
echo "HOST_CC=$host_cc" >> $config_host_mak
+echo "OBJCC=$objcc" >> $config_host_mak
echo "AR=$ar" >> $config_host_mak
echo "OBJCOPY=$objcopy" >> $config_host_mak
echo "LD=$ld" >> $config_host_mak
@@ -3776,19 +3842,24 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile"
case "$target_arch2" in
- alpha | or32 | sparc* | xtensa* | ppc*)
+ alpha | i386 | or32 | sparc* | x86_64 | xtensa* | ppc*)
echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak
;;
esac
+upper() {
+ echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]'
+}
+
echo "TARGET_SHORT_ALIGNMENT=$target_short_alignment" >> $config_target_mak
echo "TARGET_INT_ALIGNMENT=$target_int_alignment" >> $config_target_mak
echo "TARGET_LONG_ALIGNMENT=$target_long_alignment" >> $config_target_mak
echo "TARGET_LLONG_ALIGNMENT=$target_llong_alignment" >> $config_target_mak
echo "TARGET_ARCH=$TARGET_ARCH" >> $config_target_mak
-target_arch_name="`echo $TARGET_ARCH | LC_ALL=C tr '[a-z]' '[A-Z]'`"
+target_arch_name="`upper $TARGET_ARCH`"
echo "TARGET_$target_arch_name=y" >> $config_target_mak
echo "TARGET_ARCH2=$target_arch2" >> $config_target_mak
+echo "TARGET_TYPE=TARGET_TYPE_`upper $target_arch2`" >> $config_target_mak
echo "TARGET_BASE_ARCH=$TARGET_BASE_ARCH" >> $config_target_mak
if [ "$TARGET_ABI_DIR" = "" ]; then
TARGET_ABI_DIR=$TARGET_ARCH
@@ -3879,6 +3950,11 @@ if test "$target_bsd_user" = "yes" ; then
echo "CONFIG_BSD_USER=y" >> $config_target_mak
fi
+# the static way of configuring available audio cards requires this workaround
+if test "$target_user_only" != "yes" && grep -q CONFIG_PCSPK $source_path/default-configs/$target.mak; then
+ echo "CONFIG_PCSPK=y" >> $config_target_mak
+fi
+
# generate QEMU_CFLAGS/LDFLAGS for targets
cflags=""
diff --git a/console.c b/console.c
index 4525cc7..3b5cabb 100644
--- a/console.c
+++ b/console.c
@@ -850,6 +850,26 @@ static void console_clear_xy(TextConsole *s, int x, int y)
update_xy(s, x, y);
}
+/* set cursor, checking bounds */
+static void set_cursor(TextConsole *s, int x, int y)
+{
+ if (x < 0) {
+ x = 0;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+ if (y >= s->height) {
+ y = s->height - 1;
+ }
+ if (x >= s->width) {
+ x = s->width - 1;
+ }
+
+ s->x = x;
+ s->y = y;
+}
+
static void console_putchar(TextConsole *s, int ch)
{
TextCell *c;
@@ -921,7 +941,8 @@ static void console_putchar(TextConsole *s, int ch)
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
}
} else {
- s->nb_esc_params++;
+ if (s->nb_esc_params < MAX_ESC_PARAMS)
+ s->nb_esc_params++;
if (ch == ';')
break;
#ifdef DEBUG_CONSOLE
@@ -935,59 +956,37 @@ static void console_putchar(TextConsole *s, int ch)
if (s->esc_params[0] == 0) {
s->esc_params[0] = 1;
}
- s->y -= s->esc_params[0];
- if (s->y < 0) {
- s->y = 0;
- }
+ set_cursor(s, s->x, s->y - s->esc_params[0]);
break;
case 'B':
/* move cursor down */
if (s->esc_params[0] == 0) {
s->esc_params[0] = 1;
}
- s->y += s->esc_params[0];
- if (s->y >= s->height) {
- s->y = s->height - 1;
- }
+ set_cursor(s, s->x, s->y + s->esc_params[0]);
break;
case 'C':
/* move cursor right */
if (s->esc_params[0] == 0) {
s->esc_params[0] = 1;
}
- s->x += s->esc_params[0];
- if (s->x >= s->width) {
- s->x = s->width - 1;
- }
+ set_cursor(s, s->x + s->esc_params[0], s->y);
break;
case 'D':
/* move cursor left */
if (s->esc_params[0] == 0) {
s->esc_params[0] = 1;
}
- s->x -= s->esc_params[0];
- if (s->x < 0) {
- s->x = 0;
- }
+ set_cursor(s, s->x - s->esc_params[0], s->y);
break;
case 'G':
/* move cursor to column */
- s->x = s->esc_params[0] - 1;
- if (s->x < 0) {
- s->x = 0;
- }
+ set_cursor(s, s->esc_params[0] - 1, s->y);
break;
case 'f':
case 'H':
/* move cursor to row, column */
- s->x = s->esc_params[1] - 1;
- if (s->x < 0) {
- s->x = 0;
- }
- s->y = s->esc_params[0] - 1;
- if (s->y < 0) {
- s->y = 0;
- }
+ set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
break;
case 'J':
switch (s->esc_params[0]) {
@@ -1087,7 +1086,7 @@ void console_select(unsigned int index)
if (s) {
DisplayState *ds = s->ds;
- if (active_console->cursor_timer) {
+ if (active_console && active_console->cursor_timer) {
qemu_del_timer(active_console->cursor_timer);
}
active_console = s;
diff --git a/cpu-all.h b/cpu-all.h
index 82ba1d7..5e07d28 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -274,6 +274,28 @@ extern unsigned long reserved_va;
#define cpu_ldsw_code(env1, p) ldsw_raw(p)
#define cpu_ldl_code(env1, p) ldl_raw(p)
#define cpu_ldq_code(env1, p) ldq_raw(p)
+
+#define cpu_ldub_data(env, addr) ldub_raw(addr)
+#define cpu_lduw_data(env, addr) lduw_raw(addr)
+#define cpu_ldsw_data(env, addr) ldsw_raw(addr)
+#define cpu_ldl_data(env, addr) ldl_raw(addr)
+#define cpu_ldq_data(env, addr) ldq_raw(addr)
+
+#define cpu_stb_data(env, addr, data) stb_raw(addr, data)
+#define cpu_stw_data(env, addr, data) stw_raw(addr, data)
+#define cpu_stl_data(env, addr, data) stl_raw(addr, data)
+#define cpu_stq_data(env, addr, data) stq_raw(addr, data)
+
+#define cpu_ldub_kernel(env, addr) ldub_raw(addr)
+#define cpu_lduw_kernel(env, addr) lduw_raw(addr)
+#define cpu_ldsw_kernel(env, addr) ldsw_raw(addr)
+#define cpu_ldl_kernel(env, addr) ldl_raw(addr)
+#define cpu_ldq_kernel(env, addr) ldq_raw(addr)
+
+#define cpu_stb_kernel(env, addr, data) stb_raw(addr, data)
+#define cpu_stw_kernel(env, addr, data) stw_raw(addr, data)
+#define cpu_stl_kernel(env, addr, data) stl_raw(addr, data)
+#define cpu_stq_kernel(env, addr, data) stq_raw(addr, data)
#endif
#define ldub_kernel(p) ldub_raw(p)
diff --git a/cpu-exec.c b/cpu-exec.c
index 4fee061..134b3c4 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -444,6 +444,7 @@ int cpu_exec(CPUArchState *env)
#elif defined(TARGET_UNICORE32)
if (interrupt_request & CPU_INTERRUPT_HARD
&& !(env->uncached_asr & ASR_I)) {
+ env->exception_index = UC32_EXCP_INTR;
do_interrupt(env);
next_tb = 0;
}
diff --git a/cputlb.c b/cputlb.c
index 0d1e252..d3e7b25 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -312,7 +312,9 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
/* NOTE: this function can trigger an exception */
/* NOTE2: the returned address is not exactly the physical address: it
- is the offset relative to phys_ram_base */
+ * is actually a ram_addr_t (in system mode; the user mode emulation
+ * version of this function returns a guest virtual address).
+ */
tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
{
int mmu_idx, page_index, pd;
diff --git a/cutils.c b/cutils.c
index 9d4c570..8ef648f 100644
--- a/cutils.c
+++ b/cutils.c
@@ -382,3 +382,50 @@ int qemu_parse_fd(const char *param)
}
return fd;
}
+
+int qemu_parse_fdset(const char *param)
+{
+ return qemu_parse_fd(param);
+}
+
+/* round down to the nearest power of 2*/
+int64_t pow2floor(int64_t value)
+{
+ if (!is_power_of_2(value)) {
+ value = 0x8000000000000000ULL >> clz64(value);
+ }
+ return value;
+}
+
+/*
+ * Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+ * Input is limited to 14-bit numbers
+ */
+int uleb128_encode_small(uint8_t *out, uint32_t n)
+{
+ g_assert(n <= 0x3fff);
+ if (n < 0x80) {
+ *out++ = n;
+ return 1;
+ } else {
+ *out++ = (n & 0x7f) | 0x80;
+ *out++ = n >> 7;
+ return 2;
+ }
+}
+
+int uleb128_decode_small(const uint8_t *in, uint32_t *n)
+{
+ if (!(*in & 0x80)) {
+ *n = *in++;
+ return 1;
+ } else {
+ *n = *in++ & 0x7f;
+ /* we exceed 14 bit number */
+ if (*in & 0x80) {
+ return -1;
+ }
+ *n |= *in++ << 7;
+ return 2;
+ }
+}
diff --git a/debian/changelog b/debian/changelog
index 2ebcf62..fb25626 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+qemu-linaro (1.2.0-2012.09-0ubuntu1~linaro1) precise; urgency=low
+
+ * New upstream release.
+ - repository: git://git.linaro.org/qemu/qemu-linaro.git
+ - commit: 16a706c
+ - build: https://ci.linaro.org/jenkins/job/qemu-linaro/44/
+
+ - debian/ repository: git://git.linaro.org/people/rikuvoipio/qemu-packaging.git
+ - debian/ commit: 56a8e17
+
+ -- Fathi Boudra <fathi.boudra@linaro.org> Sat, 15 Sep 2012 09:43:51 +0300
+
qemu-linaro (1.1.50-2012.08-0ubuntu1~linaro1) precise; urgency=low
* New upstream release.
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index e542b4f..f335a72 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -27,3 +27,21 @@ CONFIG_SMC91C111=y
CONFIG_DS1338=y
CONFIG_PFLASH_CFI01=y
CONFIG_PFLASH_CFI02=y
+
+CONFIG_ARM_TIMER=y
+CONFIG_PL011=y
+CONFIG_PL022=y
+CONFIG_PL031=y
+CONFIG_PL041=y
+CONFIG_PL050=y
+CONFIG_PL061=y
+CONFIG_PL080=y
+CONFIG_PL110=y
+CONFIG_PL181=y
+CONFIG_PL190=y
+CONFIG_PL310=y
+CONFIG_CADENCE=y
+CONFIG_XGMAC=y
+
+CONFIG_VERSATILE_PCI=y
+CONFIG_VERSATILE_I2C=y
diff --git a/default-configs/unicore32-softmmu.mak b/default-configs/unicore32-softmmu.mak
new file mode 100644
index 0000000..de38577
--- /dev/null
+++ b/default-configs/unicore32-softmmu.mak
@@ -0,0 +1,4 @@
+# Default configuration for unicore32-softmmu
+CONFIG_PUV3=y
+CONFIG_PTIMER=y
+CONFIG_PCKBD=y
diff --git a/dma-helpers.c b/dma-helpers.c
index 35cb500..433d8b2 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -24,8 +24,8 @@ static void do_dma_memory_set(dma_addr_t addr, uint8_t c, dma_addr_t len)
while (len > 0) {
l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE;
cpu_physical_memory_rw(addr, fillbuf, l, true);
- len -= len;
- addr += len;
+ len -= l;
+ addr += l;
}
}
@@ -65,6 +65,7 @@ void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len)
void qemu_sglist_destroy(QEMUSGList *qsg)
{
g_free(qsg->sg);
+ memset(qsg, 0, sizeof(*qsg));
}
typedef struct {
diff --git a/docs/bootindex.txt b/docs/bootindex.txt
index 16083b3..803ebfc 100644
--- a/docs/bootindex.txt
+++ b/docs/bootindex.txt
@@ -1,4 +1,4 @@
-= Bootindex propery =
+= Bootindex property =
Block and net devices have bootindex property. This property is used to
determine the order in which firmware will consider devices for booting
diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
index 0ad51aa..8349dec 100644
--- a/docs/writing-qmp-commands.txt
+++ b/docs/writing-qmp-commands.txt
@@ -210,19 +210,17 @@ if you don't see these strings, then something went wrong.
=== Errors ===
QMP commands should use the error interface exported by the error.h header
-file. The basic function used to set an error is the error_set() one.
+file. Basically, errors are set by calling the error_set() function.
Let's say we don't accept the string "message" to contain the word "love". If
-it does contain it, we want the "hello-world" command to the return the
-InvalidParameter error.
-
-Only one change is required, and it's in the C implementation:
+it does contain it, we want the "hello-world" command to return an error:
void qmp_hello_world(bool has_message, const char *message, Error **errp)
{
if (has_message) {
if (strstr(message, "love")) {
- error_set(errp, QERR_INVALID_PARAMETER, "message");
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+ "the word 'love' is not allowed");
return;
}
printf("%s\n", message);
@@ -231,30 +229,40 @@ void qmp_hello_world(bool has_message, const char *message, Error **errp)
}
}
-Let's test it. Build qemu, run it as defined in the "Testing" section, and
-then issue the following command:
+The first argument to the error_set() function is the Error pointer to pointer,
+which is passed to all QMP functions. The second argument is a ErrorClass
+value, which should be ERROR_CLASS_GENERIC_ERROR most of the time (more
+details about error classes are given below). The third argument is a human
+description of the error, this is a free-form printf-like string.
+
+Let's test the example above. Build qemu, run it as defined in the "Testing"
+section, and then issue the following command:
-{ "execute": "hello-world", "arguments": { "message": "we love qemu" } }
+{ "execute": "hello-world", "arguments": { "message": "all you need is love" } }
The QMP server's response should be:
{
"error": {
- "class": "InvalidParameter",
- "desc": "Invalid parameter 'message'",
- "data": {
- "name": "message"
- }
+ "class": "GenericError",
+ "desc": "the word 'love' is not allowed"
}
}
-Which is the InvalidParameter error.
+As a general rule, all QMP errors should use ERROR_CLASS_GENERIC_ERROR. There
+are two exceptions to this rule:
+
+ 1. A non-generic ErrorClass value exists* for the failure you want to report
+ (eg. DeviceNotFound)
+
+ 2. Management applications have to take special action on the failure you
+ want to report, hence you have to add a new ErrorClass value so that they
+ can check for it
-When you have to return an error but you're unsure what error to return or
-which arguments an error takes, you should look at the qerror.h file. Note
-that you might be required to add new errors if needed.
+If the failure you want to report doesn't fall in one of the two cases above,
+just report ERROR_CLASS_GENERIC_ERROR.
-FIXME: describe better the error API and how to add new errors.
+ * All existing ErrorClass values are defined in the qapi-schema.json file
=== Command Documentation ===
@@ -275,7 +283,6 @@ here goes "hello-world"'s new entry for the qapi-schema.json file:
# @message: #optional string to be printed
#
# Returns: Nothing on success.
-# If @message contains "love", InvalidParameter
#
# Notes: if @message is not provided, the "Hello, world" string will
# be printed instead
diff --git a/docs/xbzrle.txt b/docs/xbzrle.txt
new file mode 100644
index 0000000..cc3a26a
--- /dev/null
+++ b/docs/xbzrle.txt
@@ -0,0 +1,128 @@
+XBZRLE (Xor Based Zero Run Length Encoding)
+===========================================
+
+Using XBZRLE (Xor Based Zero Run Length Encoding) allows for the reduction
+of VM downtime and the total live-migration time of Virtual machines.
+It is particularly useful for virtual machines running memory write intensive
+workloads that are typical of large enterprise applications such as SAP ERP
+Systems, and generally speaking for any application that uses a sparse memory
+update pattern.
+
+Instead of sending the changed guest memory page this solution will send a
+compressed version of the updates, thus reducing the amount of data sent during
+live migration.
+In order to be able to calculate the update, the previous memory pages need to
+be stored on the source. Those pages are stored in a dedicated cache
+(hash table) and are accessed by their address.
+The larger the cache size the better the chances are that the page has already
+been stored in the cache.
+A small cache size will result in high cache miss rate.
+Cache size can be changed before and during migration.
+
+Format
+=======
+
+The compression format performs a XOR between the previous and current content
+of the page, where zero represents an unchanged value.
+The page data delta is represented by zero and non zero runs.
+A zero run is represented by its length (in bytes).
+A non zero run is represented by its length (in bytes) and the new data.
+The run length is encoded using ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+
+There can be more than one valid encoding, the sender may send a longer encoding
+for the benefit of reducing computation cost.
+
+page = zrun nzrun
+ | zrun nzrun page
+
+zrun = length
+
+nzrun = length byte...
+
+length = uleb128 encoded integer
+
+On the sender side XBZRLE is used as a compact delta encoding of page updates,
+retrieving the old page content from the cache (default size of 512 MB). The
+receiving side uses the existing page's content and XBZRLE to decode the new
+page's content.
+
+This work was originally based on research results published
+VEE 2011: Evaluation of Delta Compression Techniques for Efficient Live
+Migration of Large Virtual Machines by Benoit, Svard, Tordsson and Elmroth.
+Additionally the delta encoder XBRLE was improved further using the XBZRLE
+instead.
+
+XBZRLE has a sustained bandwidth of 2-2.5 GB/s for typical workloads making it
+ideal for in-line, real-time encoding such as is needed for live-migration.
+
+Example
+old buffer:
+1001 zeros
+05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 68 00 00 6b 00 6d
+3074 zeros
+
+new buffer:
+1001 zeros
+01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 68 00 00 67 00 69
+3074 zeros
+
+encoded buffer:
+
+encoded length 24
+e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
+
+Usage
+======================
+1. Verify the destination QEMU version is able to decode the new format.
+ {qemu} info migrate_capabilities
+ {qemu} xbzrle: off , ...
+
+2. Activate xbzrle on both source and destination:
+ {qemu} migrate_set_capability xbzrle on
+
+3. Set the XBZRLE cache size - the cache size is in MBytes and should be a
+power of 2. The cache default value is 64MBytes. (on source only)
+ {qemu} migrate_set_cache_size 256m
+
+4. Start outgoing migration
+ {qemu} migrate -d tcp:destination.host:4444
+ {qemu} info migrate
+ capabilities: xbzrle: on
+ Migration status: active
+ transferred ram: A kbytes
+ remaining ram: B kbytes
+ total ram: C kbytes
+ total time: D milliseconds
+ duplicate: E pages
+ normal: F pages
+ normal bytes: G kbytes
+ cache size: H bytes
+ xbzrle transferred: I kbytes
+ xbzrle pages: J pages
+ xbzrle cache miss: K
+ xbzrle overflow : L
+
+xbzrle cache-miss: the number of cache misses to date - high cache-miss rate
+indicates that the cache size is set too low.
+xbzrle overflow: the number of overflows in the decoding which where the delta
+could not be compressed. This can happen if the changes in the pages are too
+large or there are many short changes; for example, changing every second byte
+(half a page).
+
+Testing: Testing indicated that live migration with XBZRLE was completed in 110
+seconds, whereas without it would not be able to complete.
+
+A simple synthetic memory r/w load generator:
+.. include <stdlib.h>
+.. include <stdio.h>
+.. int main()
+.. {
+.. char *buf = (char *) calloc(4096, 4096);
+.. while (1) {
+.. int i;
+.. for (i = 0; i < 4096 * 4; i++) {
+.. buf[i * 4096 / 4]++;
+.. }
+.. printf(".");
+.. }
+.. }
diff --git a/error.c b/error.c
index 58f55a0..1f05fc4 100644
--- a/error.c
+++ b/error.c
@@ -14,17 +14,16 @@
#include "error.h"
#include "qjson.h"
#include "qdict.h"
-#include "error_int.h"
+#include "qapi-types.h"
#include "qerror.h"
struct Error
{
- QDict *obj;
- const char *fmt;
char *msg;
+ ErrorClass err_class;
};
-void error_set(Error **errp, const char *fmt, ...)
+void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
{
Error *err;
va_list ap;
@@ -37,9 +36,9 @@ void error_set(Error **errp, const char *fmt, ...)
err = g_malloc0(sizeof(*err));
va_start(ap, fmt);
- err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
+ err->msg = g_strdup_vprintf(fmt, ap);
va_end(ap);
- err->fmt = fmt;
+ err->err_class = err_class;
*errp = err;
}
@@ -50,9 +49,7 @@ Error *error_copy(const Error *err)
err_new = g_malloc0(sizeof(*err));
err_new->msg = g_strdup(err->msg);
- err_new->fmt = err->fmt;
- err_new->obj = err->obj;
- QINCREF(err_new->obj);
+ err_new->err_class = err->err_class;
return err_new;
}
@@ -62,75 +59,24 @@ bool error_is_set(Error **errp)
return (errp && *errp);
}
-const char *error_get_pretty(Error *err)
-{
- if (err->msg == NULL) {
- QString *str;
- str = qerror_format(err->fmt, err->obj);
- err->msg = g_strdup(qstring_get_str(str));
- QDECREF(str);
- }
-
- return err->msg;
-}
-
-const char *error_get_field(Error *err, const char *field)
-{
- if (strcmp(field, "class") == 0) {
- return qdict_get_str(err->obj, field);
- } else {
- QDict *dict = qdict_get_qdict(err->obj, "data");
- return qdict_get_str(dict, field);
- }
-}
-
-QDict *error_get_data(Error *err)
+ErrorClass error_get_class(const Error *err)
{
- QDict *data = qdict_get_qdict(err->obj, "data");
- QINCREF(data);
- return data;
+ return err->err_class;
}
-void error_set_field(Error *err, const char *field, const char *value)
+const char *error_get_pretty(Error *err)
{
- QDict *dict = qdict_get_qdict(err->obj, "data");
- qdict_put(dict, field, qstring_from_str(value));
+ return err->msg;
}
void error_free(Error *err)
{
if (err) {
- QDECREF(err->obj);
g_free(err->msg);
g_free(err);
}
}
-bool error_is_type(Error *err, const char *fmt)
-{
- const char *error_class;
- char *ptr;
- char *end;
-
- if (!err) {
- return false;
- }
-
- ptr = strstr(fmt, "'class': '");
- assert(ptr != NULL);
- ptr += strlen("'class': '");
-
- end = strchr(ptr, '\'');
- assert(end != NULL);
-
- error_class = error_get_field(err, "class");
- if (strlen(error_class) != end - ptr) {
- return false;
- }
-
- return strncmp(ptr, error_class, end - ptr) == 0;
-}
-
void error_propagate(Error **dst_err, Error *local_err)
{
if (dst_err && !*dst_err) {
@@ -139,22 +85,3 @@ void error_propagate(Error **dst_err, Error *local_err)
error_free(local_err);
}
}
-
-QObject *error_get_qobject(Error *err)
-{
- QINCREF(err->obj);
- return QOBJECT(err->obj);
-}
-
-void error_set_qobject(Error **errp, QObject *obj)
-{
- Error *err;
- if (errp == NULL) {
- return;
- }
- err = g_malloc0(sizeof(*err));
- err->obj = qobject_to_qdict(obj);
- qobject_incref(obj);
-
- *errp = err;
-}
diff --git a/error.h b/error.h
index 3d9d96d..96fc203 100644
--- a/error.h
+++ b/error.h
@@ -13,20 +13,21 @@
#define ERROR_H
#include "compiler.h"
+#include "qapi-types.h"
#include <stdbool.h>
/**
- * A class representing internal errors within QEMU. An error has a string
- * typename and optionally a set of named string parameters.
+ * A class representing internal errors within QEMU. An error has a ErrorClass
+ * code and a human message.
*/
typedef struct Error Error;
/**
- * Set an indirect pointer to an error given a printf-style format parameter.
- * Currently, qerror.h defines these error formats. This function is not
- * meant to be used outside of QEMU.
+ * Set an indirect pointer to an error given a ErrorClass value and a
+ * printf-style human message. This function is not meant to be used outside
+ * of QEMU.
*/
-void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
/**
* Returns true if an indirect pointer to an error is pointing to a valid
@@ -34,6 +35,11 @@ void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
*/
bool error_is_set(Error **err);
+/*
+ * Get the error class of an error object.
+ */
+ErrorClass error_get_class(const Error *err);
+
/**
* Returns an exact copy of the error passed as an argument.
*/
@@ -45,16 +51,6 @@ Error *error_copy(const Error *err);
const char *error_get_pretty(Error *err);
/**
- * Get an individual named error field.
- */
-const char *error_get_field(Error *err, const char *field);
-
-/**
- * Get an individual named error field.
- */
-void error_set_field(Error *err, const char *field, const char *value);
-
-/**
* Propagate an error to an indirect pointer to an error. This function will
* always transfer ownership of the error reference and handles the case where
* dst_err is NULL correctly. Errors after the first are discarded.
@@ -66,10 +62,4 @@ void error_propagate(Error **dst_err, Error *local_err);
*/
void error_free(Error *err);
-/**
- * Determine if an error is of a speific type (based on the qerror format).
- * Non-QEMU users should get the `class' field to identify the error type.
- */
-bool error_is_type(Error *err, const char *fmt);
-
#endif
diff --git a/error_int.h b/error_int.h
deleted file mode 100644
index 5e39424..0000000
--- a/error_int.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * QEMU Error Objects
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2. See
- * the COPYING.LIB file in the top-level directory.
- */
-#ifndef QEMU_ERROR_INT_H
-#define QEMU_ERROR_INT_H
-
-#include "qemu-common.h"
-#include "qobject.h"
-#include "qdict.h"
-#include "error.h"
-
-/**
- * Internal QEMU functions for working with Error.
- *
- * These are used to convert QErrors to Errors
- */
-QDict *error_get_data(Error *err);
-QObject *error_get_qobject(Error *err);
-void error_set_qobject(Error **errp, QObject *obj);
-
-#endif
diff --git a/exec.c b/exec.c
index a42a0b5..5834766 100644
--- a/exec.c
+++ b/exec.c
@@ -2475,6 +2475,24 @@ static ram_addr_t last_ram_offset(void)
return last;
}
+static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
+{
+ int ret;
+ QemuOpts *machine_opts;
+
+ /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */
+ machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+ if (machine_opts &&
+ !qemu_opt_get_bool(machine_opts, "dump-guest-core", true)) {
+ ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP);
+ if (ret) {
+ perror("qemu_madvise");
+ fprintf(stderr, "madvise doesn't support MADV_DONTDUMP, "
+ "but dump_guest_core=off specified\n");
+ }
+ }
+}
+
void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
{
RAMBlock *new_block, *block;
@@ -2550,8 +2568,12 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
last_ram_offset() >> TARGET_PAGE_BITS);
+ memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+ 0, size >> TARGET_PAGE_BITS);
cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
+ qemu_ram_setup_dump(new_block->host, size);
+
if (kvm_enabled())
kvm_setup_guest_memory(new_block->host, size);
@@ -2668,6 +2690,7 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
exit(1);
}
qemu_madvise(vaddr, length, QEMU_MADV_MERGEABLE);
+ qemu_ram_setup_dump(vaddr, length);
}
return;
}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 9bbc7f7..f6104b0 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -829,6 +829,26 @@ STEXI
@item migrate_cancel
@findex migrate_cancel
Cancel the current VM migration.
+
+ETEXI
+
+ {
+ .name = "migrate_set_cache_size",
+ .args_type = "value:o",
+ .params = "value",
+ .help = "set cache size (in bytes) for XBZRLE migrations,"
+ "the cache size will be rounded down to the nearest "
+ "power of 2.\n"
+ "The cache size affects the number of cache misses."
+ "In case of a high cache miss ratio you need to increase"
+ " the cache size",
+ .mhandler.cmd = hmp_migrate_set_cache_size,
+ },
+
+STEXI
+@item migrate_set_cache_size @var{value}
+@findex migrate_set_cache_size
+Set cache size to @var{value} (in bytes) for xbzrle migrations.
ETEXI
{
@@ -861,6 +881,20 @@ Set maximum tolerated downtime (in seconds) for migration.
ETEXI
{
+ .name = "migrate_set_capability",
+ .args_type = "capability:s,state:b",
+ .params = "capability state",
+ .help = "Enable/Disable the usage of a capability for migration",
+ .mhandler.cmd = hmp_migrate_set_capability,
+ },
+
+STEXI
+@item migrate_set_capability @var{capability} @var{state}
+@findex migrate_set_capability
+Enable/Disable the usage of a capability @var{capability} for migration.
+ETEXI
+
+ {
.name = "client_migrate_info",
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
.params = "protocol hostname port tls-port cert-subject",
@@ -1417,6 +1451,10 @@ show CPU statistics
show user network stack connection states
@item info migrate
show migration status
+@item info migrate_capabilities
+show current migration capabilities
+@item info migrate_cache_size
+show current migration XBZRLE cache size
@item info balloon
show balloon information
@item info qtree
diff --git a/hmp.c b/hmp.c
index 25688ab..81c8acb 100644
--- a/hmp.c
+++ b/hmp.c
@@ -131,11 +131,26 @@ void hmp_info_mice(Monitor *mon)
void hmp_info_migrate(Monitor *mon)
{
MigrationInfo *info;
+ MigrationCapabilityStatusList *caps, *cap;
info = qmp_query_migrate(NULL);
+ caps = qmp_query_migrate_capabilities(NULL);
+
+ /* do not display parameters during setup */
+ if (info->has_status && caps) {
+ monitor_printf(mon, "capabilities: ");
+ for (cap = caps; cap; cap = cap->next) {
+ monitor_printf(mon, "%s: %s ",
+ MigrationCapability_lookup[cap->value->capability],
+ cap->value->state ? "on" : "off");
+ }
+ monitor_printf(mon, "\n");
+ }
if (info->has_status) {
monitor_printf(mon, "Migration status: %s\n", info->status);
+ monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
+ info->total_time);
}
if (info->has_ram) {
@@ -145,8 +160,12 @@ void hmp_info_migrate(Monitor *mon)
info->ram->remaining >> 10);
monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n",
info->ram->total >> 10);
- monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
- info->ram->total_time);
+ monitor_printf(mon, "duplicate: %" PRIu64 " pages\n",
+ info->ram->duplicate);
+ monitor_printf(mon, "normal: %" PRIu64 " pages\n",
+ info->ram->normal);
+ monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
+ info->ram->normal_bytes >> 10);
}
if (info->has_disk) {
@@ -158,7 +177,46 @@ void hmp_info_migrate(Monitor *mon)
info->disk->total >> 10);
}
+ if (info->has_xbzrle_cache) {
+ monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+ info->xbzrle_cache->cache_size);
+ monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+ info->xbzrle_cache->bytes >> 10);
+ monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+ info->xbzrle_cache->pages);
+ monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+ info->xbzrle_cache->cache_miss);
+ monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+ info->xbzrle_cache->overflow);
+ }
+
qapi_free_MigrationInfo(info);
+ qapi_free_MigrationCapabilityStatusList(caps);
+}
+
+void hmp_info_migrate_capabilities(Monitor *mon)
+{
+ MigrationCapabilityStatusList *caps, *cap;
+
+ caps = qmp_query_migrate_capabilities(NULL);
+
+ if (caps) {
+ monitor_printf(mon, "capabilities: ");
+ for (cap = caps; cap; cap = cap->next) {
+ monitor_printf(mon, "%s: %s ",
+ MigrationCapability_lookup[cap->value->capability],
+ cap->value->state ? "on" : "off");
+ }
+ monitor_printf(mon, "\n");
+ }
+
+ qapi_free_MigrationCapabilityStatusList(caps);
+}
+
+void hmp_info_migrate_cache_size(Monitor *mon)
+{
+ monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n",
+ qmp_query_migrate_cache_size(NULL) >> 10);
}
void hmp_info_cpus(Monitor *mon)
@@ -612,34 +670,35 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
static void hmp_cont_cb(void *opaque, int err)
{
- Monitor *mon = opaque;
-
if (!err) {
- hmp_cont(mon, NULL);
+ qmp_cont(NULL);
}
}
+static bool key_is_missing(const BlockInfo *bdev)
+{
+ return (bdev->inserted && bdev->inserted->encryption_key_missing);
+}
+
void hmp_cont(Monitor *mon, const QDict *qdict)
{
+ BlockInfoList *bdev_list, *bdev;
Error *errp = NULL;
- qmp_cont(&errp);
- if (error_is_set(&errp)) {
- if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
- const char *device;
-
- /* The device is encrypted. Ask the user for the password
- and retry */
-
- device = error_get_field(errp, "device");
- assert(device != NULL);
-
- monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
- error_free(errp);
- return;
+ bdev_list = qmp_query_block(NULL);
+ for (bdev = bdev_list; bdev; bdev = bdev->next) {
+ if (key_is_missing(bdev->value)) {
+ monitor_read_block_device_key(mon, bdev->value->device,
+ hmp_cont_cb, NULL);
+ goto out;
}
- hmp_handle_error(mon, &errp);
}
+
+ qmp_cont(&errp);
+ hmp_handle_error(mon, &errp);
+
+out:
+ qapi_free_BlockInfoList(bdev_list);
}
void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
@@ -731,12 +790,57 @@ void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
qmp_migrate_set_downtime(value, NULL);
}
+void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict)
+{
+ int64_t value = qdict_get_int(qdict, "value");
+ Error *err = NULL;
+
+ qmp_migrate_set_cache_size(value, &err);
+ if (err) {
+ monitor_printf(mon, "%s\n", error_get_pretty(err));
+ error_free(err);
+ return;
+ }
+}
+
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
{
int64_t value = qdict_get_int(qdict, "value");
qmp_migrate_set_speed(value, NULL);
}
+void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
+{
+ const char *cap = qdict_get_str(qdict, "capability");
+ bool state = qdict_get_bool(qdict, "state");
+ Error *err = NULL;
+ MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
+ int i;
+
+ for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ if (strcmp(cap, MigrationCapability_lookup[i]) == 0) {
+ caps->value = g_malloc0(sizeof(*caps->value));
+ caps->value->capability = i;
+ caps->value->state = state;
+ caps->next = NULL;
+ qmp_migrate_set_capabilities(caps, &err);
+ break;
+ }
+ }
+
+ if (i == MIGRATION_CAPABILITY_MAX) {
+ error_set(&err, QERR_INVALID_PARAMETER, cap);
+ }
+
+ qapi_free_MigrationCapabilityStatusList(caps);
+
+ if (err) {
+ monitor_printf(mon, "migrate_set_parameter: %s\n",
+ error_get_pretty(err));
+ error_free(err);
+ }
+}
+
void hmp_set_password(Monitor *mon, const QDict *qdict)
{
const char *protocol = qdict_get_str(qdict, "protocol");
@@ -775,22 +879,6 @@ static void hmp_change_read_arg(Monitor *mon, const char *password,
monitor_read_command(mon, 1);
}
-static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
- void *opaque)
-{
- Error *encryption_err = opaque;
- Error *err = NULL;
- const char *device;
-
- device = error_get_field(encryption_err, "device");
-
- qmp_block_passwd(device, password, &err);
- hmp_handle_error(mon, &err);
- error_free(encryption_err);
-
- monitor_read_command(mon, 1);
-}
-
void hmp_change(Monitor *mon, const QDict *qdict)
{
const char *device = qdict_get_str(qdict, "device");
@@ -808,18 +896,10 @@ void hmp_change(Monitor *mon, const QDict *qdict)
}
qmp_change(device, target, !!arg, arg, &err);
- if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
- monitor_printf(mon, "%s (%s) is encrypted.\n",
- error_get_field(err, "device"),
- error_get_field(err, "filename"));
- if (!monitor_get_rs(mon)) {
- monitor_printf(mon,
- "terminal does not support password prompting\n");
- error_free(err);
- return;
- }
- readline_start(monitor_get_rs(mon), "Password: ", 1,
- cb_hmp_change_bdrv_pwd, err);
+ if (error_is_set(&err) &&
+ error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
+ error_free(err);
+ monitor_read_block_device_key(mon, device, NULL, NULL);
return;
}
hmp_handle_error(mon, &err);
diff --git a/hmp.h b/hmp.h
index 8d2b0d7..7dd93bf 100644
--- a/hmp.h
+++ b/hmp.h
@@ -16,6 +16,7 @@
#include "qemu-common.h"
#include "qapi-types.h"
+#include "qdict.h"
void hmp_info_name(Monitor *mon);
void hmp_info_version(Monitor *mon);
@@ -25,6 +26,8 @@ void hmp_info_uuid(Monitor *mon);
void hmp_info_chardev(Monitor *mon);
void hmp_info_mice(Monitor *mon);
void hmp_info_migrate(Monitor *mon);
+void hmp_info_migrate_capabilities(Monitor *mon);
+void hmp_info_migrate_cache_size(Monitor *mon);
void hmp_info_cpus(Monitor *mon);
void hmp_info_block(Monitor *mon);
void hmp_info_blockstats(Monitor *mon);
@@ -51,6 +54,8 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict);
void hmp_set_password(Monitor *mon, const QDict *qdict);
void hmp_expire_password(Monitor *mon, const QDict *qdict);
void hmp_eject(Monitor *mon, const QDict *qdict);
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 5c6ef2f..f277df2 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -65,6 +65,34 @@ hw-obj-$(CONFIG_XILINX) += xilinx_timer.o
hw-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
+hw-obj-$(CONFIG_XILINX_AXI) += stream.o
+
+# PKUnity SoC devices
+hw-obj-$(CONFIG_PUV3) += puv3_intc.o
+hw-obj-$(CONFIG_PUV3) += puv3_ost.o
+hw-obj-$(CONFIG_PUV3) += puv3_gpio.o
+hw-obj-$(CONFIG_PUV3) += puv3_pm.o
+hw-obj-$(CONFIG_PUV3) += puv3_dma.o
+
+# ARM devices
+hw-obj-$(CONFIG_ARM_TIMER) += arm_timer.o
+hw-obj-$(CONFIG_PL011) += pl011.o
+hw-obj-$(CONFIG_PL022) += pl022.o
+hw-obj-$(CONFIG_PL031) += pl031.o
+hw-obj-$(CONFIG_PL041) += pl041.o lm4549.o
+hw-obj-$(CONFIG_PL050) += pl050.o
+hw-obj-$(CONFIG_PL061) += pl061.o
+hw-obj-$(CONFIG_PL080) += pl080.o
+hw-obj-$(CONFIG_PL110) += pl110.o
+hw-obj-$(CONFIG_PL181) += pl181.o
+hw-obj-$(CONFIG_PL190) += pl190.o
+hw-obj-$(CONFIG_PL310) += arm_l2x0.o
+hw-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o
+hw-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
+hw-obj-$(CONFIG_CADENCE) += cadence_uart.o
+hw-obj-$(CONFIG_CADENCE) += cadence_ttc.o
+hw-obj-$(CONFIG_CADENCE) += cadence_gem.o
+hw-obj-$(CONFIG_XGMAC) += xgmac.o
# PCI watchdog devices
hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
@@ -106,6 +134,8 @@ hw-obj-$(CONFIG_DP8393X) += dp8393x.o
hw-obj-$(CONFIG_DS1225Y) += ds1225y.o
hw-obj-$(CONFIG_MIPSNET) += mipsnet.o
+hw-obj-y += null-machine.o
+
# Sound
sound-obj-y =
sound-obj-$(CONFIG_SB16) += sb16.o
diff --git a/hw/acpi.c b/hw/acpi.c
index effc7ec..f7950be 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -22,6 +22,7 @@
#include "hw.h"
#include "pc.h"
#include "acpi.h"
+#include "monitor.h"
struct acpi_table_header {
uint16_t _length; /* our length, not actual part of the hdr */
@@ -386,6 +387,7 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4)
break;
default:
if (sus_typ == s4) { /* S4 request */
+ monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL);
qemu_system_shutdown_request();
}
break;
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 0aace60..c56220b 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -305,7 +305,6 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
if (pc->no_hotplug) {
slot_free = false;
} else {
- object_unparent(OBJECT(dev));
qdev_free(qdev);
}
}
@@ -353,6 +352,9 @@ static void piix4_reset(void *opaque)
pci_conf[0x5a] = 0;
pci_conf[0x5b] = 0;
+ pci_conf[0x40] = 0x01; /* PM io base read only bit */
+ pci_conf[0x80] = 0;
+
if (s->kvm_enabled) {
/* Mark SMM as already inited (until KVM supports SMM). */
pci_conf[0x5B] = 0x02;
@@ -392,8 +394,6 @@ static int piix4_pm_initfn(PCIDevice *dev)
pci_conf[0x09] = 0x00;
pci_conf[0x3d] = 0x01; // interrupt pin 1
- pci_conf[0x40] = 0x01; /* PM io base read only bit */
-
/* APM */
apm_init(&s->apm, apm_ctrl_changed, s);
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
index 6735577..ea546f8 100644
--- a/hw/alpha_pci.c
+++ b/hw/alpha_pci.c
@@ -11,6 +11,7 @@
#include "qemu-log.h"
#include "sysemu.h"
#include "vmware_vga.h"
+#include "vga-pci.h"
/* PCI IO reads/writes, to byte-word addressable memory. */
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 872e112..b7cf4e2 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -15,6 +15,8 @@
#include "exec-memory.h"
+#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
+
typedef struct TyphoonCchip {
MemoryRegion region;
uint64_t misc;
@@ -40,8 +42,12 @@ typedef struct TyphoonPchip {
TyphoonWindow win[4];
} TyphoonPchip;
+#define TYPHOON_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
+
typedef struct TyphoonState {
- PCIHostState host;
+ PCIHostState parent_obj;
+
TyphoonCchip cchip;
TyphoonPchip pchip;
MemoryRegion dchip_region;
@@ -700,16 +706,16 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
MemoryRegion *addr_space = get_system_memory();
MemoryRegion *addr_space_io = get_system_io();
DeviceState *dev;
- PCIHostState *p;
TyphoonState *s;
+ PCIHostState *phb;
PCIBus *b;
int i;
- dev = qdev_create(NULL, "typhoon-pcihost");
+ dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- p = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
- s = container_of(p, TyphoonState, host);
+ s = TYPHOON_PCI_HOST_BRIDGE(dev);
+ phb = PCI_HOST_BRIDGE(dev);
/* Remember the CPUs so that we can deliver interrupts to them. */
for (i = 0; i < 4; i++) {
@@ -763,10 +769,10 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
memory_region_add_subregion(addr_space, 0x801fc000000ULL,
&s->pchip.reg_io);
- b = pci_register_bus(&s->host.busdev.qdev, "pci",
+ b = pci_register_bus(dev, "pci",
typhoon_set_irq, sys_map_irq, s,
&s->pchip.reg_mem, addr_space_io, 0, 64);
- s->host.bus = b;
+ phb->bus = b;
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b,
@@ -817,9 +823,9 @@ static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo typhoon_pcihost_info = {
- .name = "typhoon-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo typhoon_pcihost_info = {
+ .name = TYPE_TYPHOON_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(TyphoonState),
.class_init = typhoon_pcihost_class_init,
};
diff --git a/hw/apic_common.c b/hw/apic_common.c
index 58e63b0..371f95d 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -299,7 +299,9 @@ static int apic_init_common(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->io_memory);
- if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK) {
+ /* Note: We need at least 1M to map the VAPIC option ROM */
+ if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
+ ram_size >= 1024 * 1024) {
vapic = sysbus_create_simple("kvmvapic", -1, NULL);
}
s->vapic = vapic;
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 01ab3aa..87ca004 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,10 +1,5 @@
-obj-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
-obj-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
-obj-y += versatile_pci.o
-obj-y += versatile_i2c.o
-obj-y += cadence_uart.o
-obj-y += cadence_ttc.o
-obj-y += cadence_gem.o
+obj-y = integratorcp.o versatilepb.o arm_pic.o
+obj-y += arm_boot.o
obj-y += xilinx_zynq.o zynq_slcr.o
obj-y += arm_gic.o arm_gic_common.o
obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
@@ -12,12 +7,9 @@ obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
obj-y += exynos4210_rtc.o exynos4210_i2c.o
-obj-y += arm_l2x0.o
obj-y += arm_mptimer.o a15mpcore.o
-obj-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
+obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o
obj-y += highbank.o
-obj-y += pl061.o
-obj-y += xgmac.o
obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
obj-y += gumstix.o
@@ -39,7 +31,6 @@ obj-y += strongarm.o
obj-y += collie.o
obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
obj-y += kzm.o
-obj-y += pl041.o lm4549.o
obj-$(CONFIG_FDT) += ../device_tree.o
obj-$(CONFIG_KVM) += kvm/arm_gic.o
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 186ac66..55871fa 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -703,6 +703,7 @@ static TypeInfo arm_gic_info = {
.parent = TYPE_ARM_GIC_COMMON,
.instance_size = sizeof(gic_state),
.class_init = arm_gic_class_init,
+ .class_size = sizeof(ARMGICClass),
};
static void arm_gic_register_types(void)
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 8cec78d..9f66667 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -227,6 +227,11 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
big_endian = 0;
#endif
+ if (!kernel_filename) {
+ fprintf(stderr, "Guest image must be specified (using -kernel)\n");
+ exit(1);
+ }
+
image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
NULL, big_endian, ELF_MACHINE, 1);
if (image_size < 0) {
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 4867c1d..6a0832e 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -467,7 +467,7 @@ static int armv7m_nvic_init(SysBusDevice *dev)
s->gic.num_cpu = 1;
/* Tell the common code we're an NVIC */
s->gic.revision = 0xffffffff;
- s->gic.num_irq = s->num_irq;
+ s->num_irq = s->gic.num_irq;
nc->parent_init(dev);
gic_init_irqs_and_distributor(&s->gic, s->num_irq);
/* The NVIC and system controller register area looks like this:
@@ -498,14 +498,21 @@ static int armv7m_nvic_init(SysBusDevice *dev)
return 0;
}
-static Property armv7m_nvic_properties[] = {
+static void armv7m_nvic_instance_init(Object *obj)
+{
+ /* We have a different default value for the num-irq property
+ * than our superclass. This function runs after qdev init
+ * has set the defaults from the Property array and before
+ * any user-specified property setting, so just modify the
+ * value in the gic_state struct.
+ */
+ gic_state *s = ARM_GIC_COMMON(obj);
/* The ARM v7m may have anything from 0 to 496 external interrupt
* IRQ lines. We default to 64. Other boards may differ and should
- * set this property appropriately.
+ * set the num-irq property appropriately.
*/
- DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64),
- DEFINE_PROP_END_OF_LIST(),
-};
+ s->num_irq = 64;
+}
static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
{
@@ -518,12 +525,12 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
sdc->init = armv7m_nvic_init;
dc->vmsd = &vmstate_nvic;
dc->reset = armv7m_nvic_reset;
- dc->props = armv7m_nvic_properties;
}
static TypeInfo armv7m_nvic_info = {
.name = TYPE_NVIC,
.parent = TYPE_ARM_GIC_COMMON,
+ .instance_init = armv7m_nvic_instance_init,
.instance_size = sizeof(nvic_state),
.class_init = armv7m_nvic_class_init,
.class_size = sizeof(NVICClass),
diff --git a/hw/boards.h b/hw/boards.h
index 59c01d0..a2e0a54 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -12,11 +12,14 @@ typedef void QEMUMachineInitFunc(ram_addr_t ram_size,
const char *initrd_filename,
const char *cpu_model);
+typedef void QEMUMachineResetFunc(void);
+
typedef struct QEMUMachine {
const char *name;
const char *alias;
const char *desc;
QEMUMachineInitFunc *init;
+ QEMUMachineResetFunc *reset;
int use_scsi;
int max_cpus;
unsigned int no_serial:1,
diff --git a/hw/bonito.c b/hw/bonito.c
index 77786f8..6084ac4 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -180,11 +180,14 @@
#define PCI_ADDR(busno,devno,funno,regno) \
((((busno)<<16)&0xff0000) + (((devno)<<11)&0xf800) + (((funno)<<8)&0x700) + (regno))
-typedef PCIHostState BonitoState;
+#define TYPE_BONITO_PCI_HOST_BRIDGE "Bonito-pcihost"
+
+typedef struct BonitoState BonitoState;
typedef struct PCIBonitoState
{
PCIDevice dev;
+
BonitoState *pcihost;
uint32_t regs[BONITO_REGS];
@@ -218,7 +221,16 @@ typedef struct PCIBonitoState
} PCIBonitoState;
-PCIBonitoState * bonito_state;
+#define BONITO_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(BonitoState, (obj), TYPE_BONITO_PCI_HOST_BRIDGE)
+
+struct BonitoState {
+ PCIHostState parent_obj;
+
+ qemu_irq *pic;
+
+ PCIBonitoState *pci_dev;
+};
static void bonito_writel(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned size)
@@ -314,9 +326,10 @@ static void bonito_pciconf_writel(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned size)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
- s->dev.config_write(&s->dev, addr, val, 4);
+ d->config_write(d, addr, val, 4);
}
static uint64_t bonito_pciconf_readl(void *opaque, target_phys_addr_t addr,
@@ -324,9 +337,10 @@ static uint64_t bonito_pciconf_readl(void *opaque, target_phys_addr_t addr,
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
DPRINTF("bonito_pciconf_readl "TARGET_FMT_plx"\n", addr);
- return s->dev.config_read(&s->dev, addr, 4);
+ return d->config_read(d, addr, 4);
}
/* north bridge PCI configure space. 0x1fe0 0000 - 0x1fe0 00ff */
@@ -402,6 +416,7 @@ static const MemoryRegionOps bonito_cop_ops = {
static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr)
{
PCIBonitoState *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t cfgaddr;
uint32_t idsel;
uint32_t devno;
@@ -423,13 +438,13 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, target_phys_addr_t addr)
regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET;
if (idsel == 0) {
- fprintf(stderr, "error in bonito pci config address" TARGET_FMT_plx
+ fprintf(stderr, "error in bonito pci config address " TARGET_FMT_plx
",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]);
exit(1);
}
- pciaddr = PCI_ADDR(pci_bus_num(s->pcihost->bus), devno, funno, regno);
+ pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno);
DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n",
- cfgaddr, pciaddr, pci_bus_num(s->pcihost->bus), devno, funno, regno);
+ cfgaddr, pciaddr, pci_bus_num(phb->bus), devno, funno, regno);
return pciaddr;
}
@@ -438,6 +453,8 @@ static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
@@ -449,24 +466,26 @@ static void bonito_spciconf_writeb(void *opaque, target_phys_addr_t addr,
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val & 0xff, 1);
+ phb->config_reg = (pciaddr) | (1u << 31);
+ pci_data_write(phb->bus, phb->config_reg, val & 0xff, 1);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
}
static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val);
- assert((addr&0x1)==0);
+ assert((addr & 0x1) == 0);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -475,24 +494,26 @@ static void bonito_spciconf_writew(void *opaque, target_phys_addr_t addr,
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val, 2);
+ phb->config_reg = (pciaddr) | (1u << 31);
+ pci_data_write(phb->bus, phb->config_reg, val, 2);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
}
static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
- assert((addr&0x3)==0);
+ assert((addr & 0x3) == 0);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -501,18 +522,20 @@ static void bonito_spciconf_writel(void *opaque, target_phys_addr_t addr,
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
- pci_data_write(s->pcihost->bus, s->pcihost->config_reg, val, 4);
+ phb->config_reg = (pciaddr) | (1u << 31);
+ pci_data_write(phb->bus, phb->config_reg, val, 4);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
}
static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
@@ -524,24 +547,26 @@ static uint32_t bonito_spciconf_readb(void *opaque, target_phys_addr_t addr)
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
+ phb->config_reg = (pciaddr) | (1u << 31);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
- return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 1);
+ return pci_data_read(phb->bus, phb->config_reg, 1);
}
static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr);
- assert((addr&0x1)==0);
+ assert((addr & 0x1) == 0);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -550,24 +575,26 @@ static uint32_t bonito_spciconf_readw(void *opaque, target_phys_addr_t addr)
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
+ phb->config_reg = (pciaddr) | (1u << 31);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
- return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 2);
+ return pci_data_read(phb->bus, phb->config_reg, 2);
}
static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr)
{
PCIBonitoState *s = opaque;
+ PCIDevice *d = PCI_DEVICE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
uint32_t pciaddr;
uint16_t status;
DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr);
- assert((addr&0x3) == 0);
+ assert((addr & 0x3) == 0);
pciaddr = bonito_sbridge_pciaddr(s, addr);
@@ -576,14 +603,14 @@ static uint32_t bonito_spciconf_readl(void *opaque, target_phys_addr_t addr)
}
/* set the pci address in s->config_reg */
- s->pcihost->config_reg = (pciaddr) | (1u << 31);
+ phb->config_reg = (pciaddr) | (1u << 31);
/* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
- status = pci_get_word(s->dev.config + PCI_STATUS);
+ status = pci_get_word(d->config + PCI_STATUS);
status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
- pci_set_word(s->dev.config + PCI_STATUS, status);
+ pci_set_word(d->config + PCI_STATUS, status);
- return pci_data_read(s->pcihost->bus, s->pcihost->config_reg, 4);
+ return pci_data_read(phb->bus, phb->config_reg, 4);
}
/* south bridge PCI configure space. 0x1fe8 0000 - 0x1fef ffff */
@@ -607,13 +634,15 @@ static const MemoryRegionOps bonito_spciconf_ops = {
static void pci_bonito_set_irq(void *opaque, int irq_num, int level)
{
- qemu_irq *pic = opaque;
+ BonitoState *s = opaque;
+ qemu_irq *pic = s->pic;
+ PCIBonitoState *bonito_state = s->pci_dev;
int internal_irq = irq_num - BONITO_IRQ_BASE;
- if (bonito_state->regs[BONITO_INTEDGE] & (1<<internal_irq)) {
+ if (bonito_state->regs[BONITO_INTEDGE] & (1 << internal_irq)) {
qemu_irq_pulse(*pic);
} else { /* level triggered */
- if (bonito_state->regs[BONITO_INTPOL] & (1<<internal_irq)) {
+ if (bonito_state->regs[BONITO_INTPOL] & (1 << internal_irq)) {
qemu_irq_raise(*pic);
} else {
qemu_irq_lower(*pic);
@@ -673,13 +702,21 @@ static const VMStateDescription vmstate_bonito = {
static int bonito_pcihost_initfn(SysBusDevice *dev)
{
+ PCIHostState *phb = PCI_HOST_BRIDGE(dev);
+
+ phb->bus = pci_register_bus(DEVICE(dev), "pci",
+ pci_bonito_set_irq, pci_bonito_map_irq, dev,
+ get_system_memory(), get_system_io(),
+ 0x28, 32);
+
return 0;
}
static int bonito_initfn(PCIDevice *dev)
{
PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev);
- SysBusDevice *sysbus = &s->pcihost->busdev;
+ SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
/* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
pci_config_set_prog_interface(dev->config, 0x00);
@@ -691,15 +728,15 @@ static int bonito_initfn(PCIDevice *dev)
sysbus_mmio_map(sysbus, 0, BONITO_INTERNAL_REG_BASE);
/* set the north bridge pci configure mapping */
- memory_region_init_io(&s->pcihost->conf_mem, &bonito_pciconf_ops, s,
+ memory_region_init_io(&phb->conf_mem, &bonito_pciconf_ops, s,
"north-bridge-pci-config", BONITO_PCICONFIG_SIZE);
- sysbus_init_mmio(sysbus, &s->pcihost->conf_mem);
+ sysbus_init_mmio(sysbus, &phb->conf_mem);
sysbus_mmio_map(sysbus, 1, BONITO_PCICONFIG_BASE);
/* set the south bridge pci configure mapping */
- memory_region_init_io(&s->pcihost->data_mem, &bonito_spciconf_ops, s,
+ memory_region_init_io(&phb->data_mem, &bonito_spciconf_ops, s,
"south-bridge-pci-config", BONITO_SPCICONFIG_SIZE);
- sysbus_init_mmio(sysbus, &s->pcihost->data_mem);
+ sysbus_init_mmio(sysbus, &phb->data_mem);
sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE);
memory_region_init_io(&s->iomem_ldma, &bonito_ldma_ops, s,
@@ -742,28 +779,25 @@ static int bonito_initfn(PCIDevice *dev)
PCIBus *bonito_init(qemu_irq *pic)
{
DeviceState *dev;
- PCIBus *b;
BonitoState *pcihost;
+ PCIHostState *phb;
PCIBonitoState *s;
PCIDevice *d;
- dev = qdev_create(NULL, "Bonito-pcihost");
- pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev));
- b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq,
- pci_bonito_map_irq, pic, get_system_memory(),
- get_system_io(),
- 0x28, 32);
- pcihost->bus = b;
+ dev = qdev_create(NULL, TYPE_BONITO_PCI_HOST_BRIDGE);
+ phb = PCI_HOST_BRIDGE(dev);
+ pcihost = BONITO_PCI_HOST_BRIDGE(dev);
+ pcihost->pic = pic;
qdev_init_nofail(dev);
/* set the pcihost pointer before bonito_initfn is called */
- d = pci_create(b, PCI_DEVFN(0, 0), "Bonito");
+ d = pci_create(phb->bus, PCI_DEVFN(0, 0), "Bonito");
s = DO_UPCAST(PCIBonitoState, dev, d);
s->pcihost = pcihost;
- bonito_state = s;
- qdev_init_nofail(&d->qdev);
+ pcihost->pci_dev = s;
+ qdev_init_nofail(DEVICE(d));
- return b;
+ return phb->bus;
}
static void bonito_class_init(ObjectClass *klass, void *data)
@@ -781,7 +815,7 @@ static void bonito_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_bonito;
}
-static TypeInfo bonito_info = {
+static const TypeInfo bonito_info = {
.name = "Bonito",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBonitoState),
@@ -797,9 +831,9 @@ static void bonito_pcihost_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo bonito_pcihost_info = {
- .name = "Bonito-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo bonito_pcihost_info = {
+ .name = TYPE_BONITO_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(BonitoState),
.class_init = bonito_pcihost_class_init,
};
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 623dd68..e8dcc6b 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -27,8 +27,8 @@
* available at http://home.worldonline.dk/~finth/
*/
#include "hw.h"
-#include "pc.h"
#include "pci.h"
+#include "vga-pci.h"
#include "console.h"
#include "vga_int.h"
#include "loader.h"
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index 37337bf..c30ade3 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -40,9 +40,10 @@
#define DEC_DPRINTF(fmt, ...)
#endif
+#define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154)
+
typedef struct DECState {
- SysBusDevice busdev;
- PCIHostState host_state;
+ PCIHostState parent_obj;
} DECState;
static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -66,7 +67,7 @@ static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_pci_device;
}
-static TypeInfo dec_21154_pci_bridge_info = {
+static const TypeInfo dec_21154_pci_bridge_info = {
.name = "dec-21154-p2p-bridge",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBridge),
@@ -88,16 +89,16 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
static int pci_dec_21154_device_init(SysBusDevice *dev)
{
- DECState *s;
+ PCIHostState *phb;
- s = FROM_SYSBUS(DECState, dev);
+ phb = PCI_HOST_BRIDGE(dev);
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
- &s->host_state, "pci-data-idx", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops,
+ dev, "pci-data-idx", 0x1000);
+ sysbus_init_mmio(dev, &phb->conf_mem);
+ sysbus_init_mmio(dev, &phb->data_mem);
return 0;
}
@@ -119,7 +120,7 @@ static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data)
k->is_bridge = 1;
}
-static TypeInfo dec_21154_pci_host_info = {
+static const TypeInfo dec_21154_pci_host_info = {
.name = "dec-21154",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -133,9 +134,9 @@ static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
sdc->init = pci_dec_21154_device_init;
}
-static TypeInfo pci_dec_21154_device_info = {
- .name = "dec-21154-sysbus",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_dec_21154_device_info = {
+ .name = TYPE_DEC_21154,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(DECState),
.class_init = pci_dec_21154_device_class_init,
};
diff --git a/hw/dec_pci.h b/hw/dec_pci.h
index 79264ba..17dc0c2 100644
--- a/hw/dec_pci.h
+++ b/hw/dec_pci.h
@@ -3,6 +3,8 @@
#include "qemu-common.h"
+#define TYPE_DEC_21154 "dec-21154-sysbus"
+
PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn);
#endif
diff --git a/hw/esp.c b/hw/esp.c
index 52c46e6..84a4e74 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -87,7 +87,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
target = s->wregs[ESP_WBUSID] & BUSID_DID;
if (s->dma) {
- dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
+ dmalen = s->rregs[ESP_TCLO];
+ dmalen |= s->rregs[ESP_TCMID] << 8;
+ dmalen |= s->rregs[ESP_TCHI] << 16;
s->dma_memory_read(s->dma_opaque, buf, dmalen);
} else {
dmalen = s->ti_size;
@@ -226,6 +228,7 @@ static void esp_dma_done(ESPState *s)
s->rregs[ESP_RFLAGS] = 0;
s->rregs[ESP_TCLO] = 0;
s->rregs[ESP_TCMID] = 0;
+ s->rregs[ESP_TCHI] = 0;
esp_raise_irq(s);
}
@@ -328,7 +331,9 @@ static void handle_ti(ESPState *s)
return;
}
- dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
+ dmalen = s->rregs[ESP_TCLO];
+ dmalen |= s->rregs[ESP_TCMID] << 8;
+ dmalen |= s->rregs[ESP_TCHI] << 16;
if (dmalen==0) {
dmalen=0x10000;
}
@@ -429,6 +434,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
switch (saddr) {
case ESP_TCLO:
case ESP_TCMID:
+ case ESP_TCHI:
s->rregs[ESP_RSTAT] &= ~STAT_TC;
break;
case ESP_FIFO:
@@ -448,6 +454,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
/* Reload DMA counter. */
s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
+ s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
} else {
s->dma = 0;
}
@@ -530,13 +537,12 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
case ESP_WBUSID ... ESP_WSYNO:
break;
case ESP_CFG1:
+ case ESP_CFG2: case ESP_CFG3:
+ case ESP_RES3: case ESP_RES4:
s->rregs[saddr] = val;
break;
case ESP_WCCF ... ESP_WTEST:
break;
- case ESP_CFG2 ... ESP_RES4:
- s->rregs[saddr] = val;
- break;
default:
trace_esp_error_invalid_write(val, saddr);
return;
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index f4747cd..85a00a5 100644
--- a/hw/framebuffer.c
+++ b/hw/framebuffer.c
@@ -28,7 +28,7 @@ void framebuffer_update_display(
MemoryRegion *address_space,
target_phys_addr_t base,
int cols, /* Width in pixels. */
- int rows, /* Leight in pixels. */
+ int rows, /* Height in pixels. */
int src_width, /* Length of source line, in bytes. */
int dest_row_pitch, /* Bytes between adjacent horizontal output pixels. */
int dest_col_pitch, /* Bytes between adjacent vertical output pixels. */
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 81ff3a3..67da307 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -23,10 +23,9 @@
* THE SOFTWARE.
*/
-#include "sysbus.h"
+#include "pci_host.h"
#include "ppc_mac.h"
#include "pci.h"
-#include "pci_host.h"
/* debug Grackle */
//#define DEBUG_GRACKLE
@@ -38,9 +37,12 @@
#define GRACKLE_DPRINTF(fmt, ...)
#endif
+#define GRACKLE_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(GrackleState, (obj), TYPE_GRACKLE_PCI_HOST_BRIDGE)
+
typedef struct GrackleState {
- SysBusDevice busdev;
- PCIHostState host_state;
+ PCIHostState parent_obj;
+
MemoryRegion pci_mmio;
MemoryRegion pci_hole;
} GrackleState;
@@ -59,22 +61,20 @@ static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(pic[irq_num + 0x15], level);
}
-static void pci_grackle_reset(void *opaque)
-{
-}
-
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io)
{
DeviceState *dev;
SysBusDevice *s;
+ PCIHostState *phb;
GrackleState *d;
- dev = qdev_create(NULL, "grackle-pcihost");
+ dev = qdev_create(NULL, TYPE_GRACKLE_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- d = FROM_SYSBUS(GrackleState, s);
+ s = SYS_BUS_DEVICE(dev);
+ phb = PCI_HOST_BRIDGE(dev);
+ d = GRACKLE_PCI_HOST_BRIDGE(dev);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
@@ -82,36 +82,35 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
- pci_grackle_set_irq,
- pci_grackle_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- 0, 4);
+ phb->bus = pci_register_bus(dev, "pci",
+ pci_grackle_set_irq,
+ pci_grackle_map_irq,
+ pic,
+ &d->pci_mmio,
+ address_space_io,
+ 0, 4);
- pci_create_simple(d->host_state.bus, 0, "grackle");
+ pci_create_simple(phb->bus, 0, "grackle");
sysbus_mmio_map(s, 0, base);
sysbus_mmio_map(s, 1, base + 0x00200000);
- return d->host_state.bus;
+ return phb->bus;
}
static int pci_grackle_init_device(SysBusDevice *dev)
{
- GrackleState *s;
+ PCIHostState *phb;
- s = FROM_SYSBUS(GrackleState, dev);
+ phb = PCI_HOST_BRIDGE(dev);
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
- &s->host_state, "pci-data-idx", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops,
+ dev, "pci-data-idx", 0x1000);
+ sysbus_init_mmio(dev, &phb->conf_mem);
+ sysbus_init_mmio(dev, &phb->data_mem);
- qemu_register_reset(pci_grackle_reset, &s->host_state);
return 0;
}
@@ -134,7 +133,7 @@ static void grackle_pci_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo grackle_pci_info = {
+static const TypeInfo grackle_pci_info = {
.name = "grackle",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -150,9 +149,9 @@ static void pci_grackle_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo grackle_pci_host_info = {
- .name = "grackle-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo grackle_pci_host_info = {
+ .name = TYPE_GRACKLE_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(GrackleState),
.class_init = pci_grackle_class_init,
};
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index a2d0e5a..e95e664 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -229,9 +229,14 @@
target_phys_addr_t regname ##_length; \
MemoryRegion regname ##_mem
+#define TYPE_GT64120_PCI_HOST_BRIDGE "gt64120"
+
+#define GT64120_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(GT64120State, (obj), TYPE_GT64120_PCI_HOST_BRIDGE)
+
typedef struct GT64120State {
- SysBusDevice busdev;
- PCIHostState pci;
+ PCIHostState parent_obj;
+
uint32_t regs[GT_REGS];
PCI_MAPPING_ENTRY(PCI0IO);
PCI_MAPPING_ENTRY(ISD);
@@ -310,6 +315,7 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned size)
{
GT64120State *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
uint32_t saddr;
if (!(s->regs[GT_CPU] & 0x00001000))
@@ -530,13 +536,15 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
/* not implemented */
break;
case GT_PCI0_CFGADDR:
- s->pci.config_reg = val & 0x80fffffc;
+ phb->config_reg = val & 0x80fffffc;
break;
case GT_PCI0_CFGDATA:
- if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
+ if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
val = bswap32(val);
- if (s->pci.config_reg & (1u << 31))
- pci_data_write(s->pci.bus, s->pci.config_reg, val, 4);
+ }
+ if (phb->config_reg & (1u << 31)) {
+ pci_data_write(phb->bus, phb->config_reg, val, 4);
+ }
break;
/* Interrupts */
@@ -589,6 +597,7 @@ static uint64_t gt64120_readl (void *opaque,
target_phys_addr_t addr, unsigned size)
{
GT64120State *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
uint32_t val;
uint32_t saddr;
@@ -770,15 +779,17 @@ static uint64_t gt64120_readl (void *opaque,
/* PCI Internal */
case GT_PCI0_CFGADDR:
- val = s->pci.config_reg;
+ val = phb->config_reg;
break;
case GT_PCI0_CFGDATA:
- if (!(s->pci.config_reg & (1 << 31)))
+ if (!(phb->config_reg & (1 << 31))) {
val = 0xffffffff;
- else
- val = pci_data_read(s->pci.bus, s->pci.config_reg, 4);
- if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
+ } else {
+ val = pci_data_read(phb->bus, phb->config_reg, 4);
+ }
+ if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
val = bswap32(val);
+ }
break;
case GT_PCI0_CMD:
@@ -1083,31 +1094,31 @@ static void gt64120_reset(void *opaque)
PCIBus *gt64120_register(qemu_irq *pic)
{
- SysBusDevice *s;
GT64120State *d;
+ PCIHostState *phb;
DeviceState *dev;
- dev = qdev_create(NULL, "gt64120");
+ dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- d = FROM_SYSBUS(GT64120State, s);
- d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
- gt64120_pci_set_irq, gt64120_pci_map_irq,
- pic,
- get_system_memory(),
- get_system_io(),
- PCI_DEVFN(18, 0), 4);
+ d = GT64120_PCI_HOST_BRIDGE(dev);
+ phb = PCI_HOST_BRIDGE(dev);
+ phb->bus = pci_register_bus(dev, "pci",
+ gt64120_pci_set_irq, gt64120_pci_map_irq,
+ pic,
+ get_system_memory(),
+ get_system_io(),
+ PCI_DEVFN(18, 0), 4);
memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000);
- pci_create_simple(d->pci.bus, PCI_DEVFN(0, 0), "gt64120_pci");
- return d->pci.bus;
+ pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");
+ return phb->bus;
}
static int gt64120_init(SysBusDevice *dev)
{
GT64120State *s;
- s = FROM_SYSBUS(GT64120State, dev);
+ s = GT64120_PCI_HOST_BRIDGE(dev);
/* FIXME: This value is computed from registers during reset, but some
devices (e.g. VGA card) need to know it when they are registered.
@@ -1147,7 +1158,7 @@ static void gt64120_pci_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo gt64120_pci_info = {
+static const TypeInfo gt64120_pci_info = {
.name = "gt64120_pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -1161,9 +1172,9 @@ static void gt64120_class_init(ObjectClass *klass, void *data)
sdc->init = gt64120_init;
}
-static TypeInfo gt64120_info = {
- .name = "gt64120",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo gt64120_info = {
+ .name = TYPE_GT64120_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(GT64120State),
.class_init = gt64120_class_init,
};
diff --git a/hw/i82378.c b/hw/i82378.c
index 9b11d90..2123c14 100644
--- a/hw/i82378.c
+++ b/hw/i82378.c
@@ -225,7 +225,6 @@ static int pci_i82378_init(PCIDevice *dev)
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io);
memory_region_init_io(&s->mem, &i82378_mem_ops, s, "i82378-mem", 0x01000000);
- memory_region_set_coalescing(&s->mem);
pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
/* Make I/O address read only */
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index efea93f..5ea3cad 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -636,7 +636,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
}
}
-static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
+static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
{
AHCICmdHdr *cmd = ad->cur_cmd;
uint32_t opts = le32_to_cpu(cmd->opts);
@@ -647,6 +647,10 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
uint8_t *prdt;
int i;
int r = 0;
+ int sum = 0;
+ int off_idx = -1;
+ int off_pos = -1;
+ int tbl_entry_size;
if (!sglist_alloc_hint) {
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
@@ -669,10 +673,31 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
/* Get entries in the PRDT, init a qemu sglist accordingly */
if (sglist_alloc_hint > 0) {
AHCI_SG *tbl = (AHCI_SG *)prdt;
-
- qemu_sglist_init(sglist, sglist_alloc_hint, ad->hba->dma);
+ sum = 0;
for (i = 0; i < sglist_alloc_hint; i++) {
/* flags_size is zero-based */
+ tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);
+ if (offset <= (sum + tbl_entry_size)) {
+ off_idx = i;
+ off_pos = offset - sum;
+ break;
+ }
+ sum += tbl_entry_size;
+ }
+ if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
+ DPRINTF(ad->port_no, "%s: Incorrect offset! "
+ "off_idx: %d, off_pos: %d\n",
+ __func__, off_idx, off_pos);
+ r = -1;
+ goto out;
+ }
+
+ qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx), ad->hba->dma);
+ qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
+ le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);
+
+ for (i = off_idx + 1; i < sglist_alloc_hint; i++) {
+ /* flags_size is zero-based */
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
le32_to_cpu(tbl[i].flags_size) + 1);
}
@@ -745,7 +770,7 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
s->dev[port].port.ifs[0].nb_sectors - 1);
- ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
+ ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist, 0);
ncq_tfs->tag = tag;
switch(ncq_fis->command) {
@@ -970,7 +995,7 @@ static int ahci_start_transfer(IDEDMA *dma)
goto out;
}
- if (!ahci_populate_sglist(ad, &s->sg)) {
+ if (!ahci_populate_sglist(ad, &s->sg, 0)) {
has_sglist = 1;
}
@@ -1015,6 +1040,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
DPRINTF(ad->port_no, "\n");
ad->dma_cb = dma_cb;
ad->dma_status |= BM_STATUS_DMAING;
+ s->io_buffer_offset = 0;
dma_cb(s, 0);
}
@@ -1023,7 +1049,7 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
IDEState *s = &ad->port.ifs[0];
- ahci_populate_sglist(ad, &s->sg);
+ ahci_populate_sglist(ad, &s->sg, 0);
s->io_buffer_size = s->sg.size;
DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
@@ -1037,7 +1063,7 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
uint8_t *p = s->io_buffer + s->io_buffer_index;
int l = s->io_buffer_size - s->io_buffer_index;
- if (ahci_populate_sglist(ad, &s->sg)) {
+ if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset)) {
return 0;
}
@@ -1047,9 +1073,13 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
dma_buf_write(p, l, &s->sg);
}
+ /* free sglist that was created in ahci_populate_sglist() */
+ qemu_sglist_destroy(&s->sg);
+
/* update number of transferred bytes */
ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
s->io_buffer_index += l;
+ s->io_buffer_offset += l;
DPRINTF(ad->port_no, "len=%#x\n", l);
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 7170bd9..bf7d313 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -393,6 +393,7 @@ struct IDEState {
struct iovec iov;
QEMUIOVector qiov;
/* ATA DMA state */
+ int io_buffer_offset;
int io_buffer_size;
QEMUSGList sg;
/* PIO transfer handling */
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index 0c58161..62fe53a 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -366,6 +366,10 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
{
int i, guest_curr_max;
+ if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+ return;
+ }
+
guest_curr_max = s->peers[posn].nb_eventfds;
memory_region_transaction_begin();
@@ -381,17 +385,6 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
s->peers[posn].nb_eventfds = 0;
}
-static void setup_ioeventfds(IVShmemState *s) {
-
- int i, j;
-
- for (i = 0; i <= s->max_peer; i++) {
- for (j = 0; j < s->peers[i].nb_eventfds; j++) {
- ivshmem_add_eventfd(s, i, j);
- }
- }
-}
-
/* this function increase the dynamic storage need to store data about other
* guests */
static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
@@ -677,7 +670,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
}
if (s->role_val == IVSHMEM_PEER) {
- error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "ivshmem", "peer mode");
+ error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+ "peer mode", "ivshmem");
migrate_add_blocker(s->migration_blocker);
}
@@ -691,10 +685,6 @@ static int pci_ivshmem_init(PCIDevice *dev)
memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
"ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
- if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
- setup_ioeventfds(s);
- }
-
/* region for registers*/
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
&s->ivshmem_mmio);
diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c
index c5d3711..53d13e3 100644
--- a/hw/kvm/i8254.c
+++ b/hw/kvm/i8254.c
@@ -35,7 +35,8 @@
typedef struct KVMPITState {
PITCommonState pit;
LostTickPolicy lost_tick_policy;
- bool state_valid;
+ bool vm_stopped;
+ int64_t kernel_clock_offset;
} KVMPITState;
static int64_t abs64(int64_t v)
@@ -43,19 +44,11 @@ static int64_t abs64(int64_t v)
return v < 0 ? -v : v;
}
-static void kvm_pit_get(PITCommonState *pit)
+static void kvm_pit_update_clock_offset(KVMPITState *s)
{
- KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
- struct kvm_pit_state2 kpit;
- struct kvm_pit_channel_state *kchan;
- struct PITChannelState *sc;
int64_t offset, clock_offset;
struct timespec ts;
- int i, ret;
-
- if (s->state_valid) {
- return;
- }
+ int i;
/*
* Measure the delta between CLOCK_MONOTONIC, the base used for
@@ -72,6 +65,21 @@ static void kvm_pit_get(PITCommonState *pit)
clock_offset = offset;
}
}
+ s->kernel_clock_offset = clock_offset;
+}
+
+static void kvm_pit_get(PITCommonState *pit)
+{
+ KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
+ struct kvm_pit_state2 kpit;
+ struct kvm_pit_channel_state *kchan;
+ struct PITChannelState *sc;
+ int i, ret;
+
+ /* No need to re-read the state if VM is stopped. */
+ if (s->vm_stopped) {
+ return;
+ }
if (kvm_has_pit_state2()) {
ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
@@ -106,7 +114,7 @@ static void kvm_pit_get(PITCommonState *pit)
sc->mode = kchan->mode;
sc->bcd = kchan->bcd;
sc->gate = kchan->gate;
- sc->count_load_time = kchan->count_load_time + clock_offset;
+ sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
}
sc = &pit->channels[0];
@@ -114,17 +122,23 @@ static void kvm_pit_get(PITCommonState *pit)
pit_get_next_transition_time(sc, sc->count_load_time);
}
-static void kvm_pit_put(PITCommonState *s)
+static void kvm_pit_put(PITCommonState *pit)
{
+ KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
struct kvm_pit_state2 kpit;
struct kvm_pit_channel_state *kchan;
struct PITChannelState *sc;
int i, ret;
- kpit.flags = s->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
+ /* The offset keeps changing as long as the VM is stopped. */
+ if (s->vm_stopped) {
+ kvm_pit_update_clock_offset(s);
+ }
+
+ kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
for (i = 0; i < 3; i++) {
kchan = &kpit.channels[i];
- sc = &s->channels[i];
+ sc = &pit->channels[i];
kchan->count = sc->count;
kchan->latched_count = sc->latched_count;
kchan->count_latched = sc->count_latched;
@@ -137,7 +151,7 @@ static void kvm_pit_put(PITCommonState *s)
kchan->mode = sc->mode;
kchan->bcd = sc->bcd;
kchan->gate = sc->gate;
- kchan->count_load_time = sc->count_load_time;
+ kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
}
ret = kvm_vm_ioctl(kvm_state,
@@ -211,10 +225,12 @@ static void kvm_pit_vm_state_change(void *opaque, int running,
KVMPITState *s = opaque;
if (running) {
- s->state_valid = false;
+ kvm_pit_update_clock_offset(s);
+ s->vm_stopped = false;
} else {
+ kvm_pit_update_clock_offset(s);
kvm_pit_get(&s->pit);
- s->state_valid = true;
+ s->vm_stopped = true;
}
}
diff --git a/hw/megasas.c b/hw/megasas.c
index c35a15d..c728aea 100644
--- a/hw/megasas.c
+++ b/hw/megasas.c
@@ -38,6 +38,7 @@
#define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */
#define MEGASAS_MAX_ARRAYS 128
+#define MEGASAS_HBA_SERIAL "QEMU123456"
#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
@@ -93,6 +94,7 @@ typedef struct MegasasState {
int boot_event;
uint64_t sas_addr;
+ char *hba_serial;
uint64_t reply_queue_pa;
void *reply_queue;
@@ -698,8 +700,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
}
memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
- snprintf(info.serial_number, 32, "QEMU%08lx",
- (unsigned long)s & 0xFFFFFFFF);
+ snprintf(info.serial_number, 32, "%s", s->hba_serial);
snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
memcpy(info.image_component[0].name, "APP", 3);
memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
@@ -2132,6 +2133,9 @@ static int megasas_scsi_init(PCIDevice *dev)
s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
s->sas_addr |= PCI_FUNC(dev->devfn);
}
+ if (!s->hba_serial) {
+ s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
+ }
if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
} else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
@@ -2166,6 +2170,7 @@ static Property megasas_properties[] = {
MEGASAS_DEFAULT_SGE),
DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
MEGASAS_DEFAULT_FRAMES),
+ DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0),
#ifdef USE_MSIX
DEFINE_PROP_BIT("use_msix", MegasasState, flags,
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 351c88e..ad23f26 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -48,6 +48,7 @@
#include "blockdev.h"
#include "exec-memory.h"
#include "sysbus.h" /* SysBusDevice */
+#include "vga-pci.h"
//#define DEBUG_BOARD_INIT
diff --git a/hw/msix.c b/hw/msix.c
index 800fc32..d812094 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -307,13 +307,9 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
return -EINVAL;
}
- if (asprintf(&name, "%s-msix", dev->name) == -1) {
- return -ENOMEM;
- }
-
+ name = g_strdup_printf("%s-msix", dev->name);
memory_region_init(&dev->msix_exclusive_bar, name, MSIX_EXCLUSIVE_BAR_SIZE);
-
- free(name);
+ g_free(name);
ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar,
@@ -340,6 +336,15 @@ static void msix_free_irq_entries(PCIDevice *dev)
}
}
+static void msix_clear_all_vectors(PCIDevice *dev)
+{
+ int vector;
+
+ for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
+ msix_clr_pending(dev, vector);
+ }
+}
+
/* Clean up resources for the device. */
void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar)
{
@@ -394,7 +399,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
return;
}
- msix_free_irq_entries(dev);
+ msix_clear_all_vectors(dev);
qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8);
msix_update_function_masked(dev);
@@ -440,7 +445,7 @@ void msix_reset(PCIDevice *dev)
if (!msix_present(dev)) {
return;
}
- msix_free_irq_entries(dev);
+ msix_clear_all_vectors(dev);
dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE);
diff --git a/hw/null-machine.c b/hw/null-machine.c
new file mode 100644
index 0000000..69910d3
--- /dev/null
+++ b/hw/null-machine.c
@@ -0,0 +1,40 @@
+/*
+ * Empty machine
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static void machine_none_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+}
+
+static QEMUMachine machine_none = {
+ .name = "none",
+ .desc = "empty machine",
+ .init = machine_none_init,
+ .max_cpus = 0,
+};
+
+static void register_machines(void)
+{
+ qemu_register_machine(&machine_none);
+}
+
+machine_init(register_machines);
+
diff --git a/hw/openpic.c b/hw/openpic.c
index 58ef871..b9d8568 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -130,6 +130,17 @@ enum {
#define MPIC_CPU_REG_START 0x20000
#define MPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
+/*
+ * Block Revision Register1 (BRR1): QEMU does not fully emulate
+ * any version on MPIC. So to start with, set the IP version to 0.
+ *
+ * NOTE: This is Freescale MPIC specific register. Keep it here till
+ * this code is refactored for different variants of OPENPIC and MPIC.
+ */
+#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
+#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
+#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
+
enum mpic_ide_bits {
IDR_EP = 31,
IDR_CI0 = 30,
@@ -595,6 +606,8 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v
if (addr & 0xF)
return;
switch (addr) {
+ case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
+ break;
case 0x40:
case 0x50:
case 0x60:
@@ -671,6 +684,7 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
case 0x1090: /* PINT */
retval = 0x00000000;
break;
+ case 0x00: /* Block Revision Register1 (BRR1) */
case 0x40:
case 0x50:
case 0x60:
@@ -893,6 +907,9 @@ static uint32_t openpic_cpu_read_internal(void *opaque, target_phys_addr_t addr,
dst = &opp->dst[idx];
addr &= 0xFF0;
switch (addr) {
+ case 0x00: /* Block Revision Register1 (BRR1) */
+ retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
+ break;
case 0x80: /* PCTP */
retval = dst->pctp;
break;
diff --git a/hw/pc.c b/hw/pc.c
index e8bcfc0..112739a 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -51,6 +51,7 @@
#include "exec-memory.h"
#include "arch_init.h"
#include "bitmap.h"
+#include "vga-pci.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -337,32 +338,37 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
/* various important CMOS locations needed by PC/Bochs bios */
/* memory size */
- val = 640; /* base memory in K */
+ /* base memory (first MiB) */
+ val = MIN(ram_size / 1024, 640);
rtc_set_memory(s, 0x15, val);
rtc_set_memory(s, 0x16, val >> 8);
-
- val = (ram_size / 1024) - 1024;
+ /* extended memory (next 64MiB) */
+ if (ram_size > 1024 * 1024) {
+ val = (ram_size - 1024 * 1024) / 1024;
+ } else {
+ val = 0;
+ }
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x17, val);
rtc_set_memory(s, 0x18, val >> 8);
rtc_set_memory(s, 0x30, val);
rtc_set_memory(s, 0x31, val >> 8);
-
- if (above_4g_mem_size) {
- rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16);
- rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24);
- rtc_set_memory(s, 0x5d, (uint64_t)above_4g_mem_size >> 32);
- }
-
- if (ram_size > (16 * 1024 * 1024))
- val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
- else
+ /* memory between 16MiB and 4GiB */
+ if (ram_size > 16 * 1024 * 1024) {
+ val = (ram_size - 16 * 1024 * 1024) / 65536;
+ } else {
val = 0;
+ }
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x34, val);
rtc_set_memory(s, 0x35, val >> 8);
+ /* memory above 4GiB */
+ val = above_4g_mem_size / 65536;
+ rtc_set_memory(s, 0x5b, val);
+ rtc_set_memory(s, 0x5c, val >> 8);
+ rtc_set_memory(s, 0x5d, val >> 16);
/* set the number of CPU */
rtc_set_memory(s, 0x5f, smp_cpus - 1);
diff --git a/hw/pc.h b/hw/pc.h
index 54554b0..e17145f 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -195,14 +195,10 @@ static inline DeviceState *isa_vga_init(ISABus *bus)
return &dev->qdev;
}
-DeviceState *pci_vga_init(PCIBus *bus);
int isa_vga_mm_init(target_phys_addr_t vram_base,
target_phys_addr_t ctrl_base, int it_shift,
MemoryRegion *address_space);
-/* cirrus_vga.c */
-DeviceState *pci_cirrus_vga_init(PCIBus *bus);
-
/* ne2000.c */
static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
{
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 0c0096f..88ff041 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -360,6 +360,14 @@ static QEMUMachine pc_machine_v1_2 = {
#define PC_COMPAT_1_1 \
{\
+ .driver = "virtio-scsi-pci",\
+ .property = "hotplug",\
+ .value = "off",\
+ },{\
+ .driver = "virtio-scsi-pci",\
+ .property = "param_change",\
+ .value = "off",\
+ },{\
.driver = "VGA",\
.property = "vgamem_mb",\
.value = stringify(8),\
@@ -375,6 +383,10 @@ static QEMUMachine pc_machine_v1_2 = {
.driver = "qxl",\
.property = "vgamem_mb",\
.value = stringify(8),\
+ },{\
+ .driver = "virtio-blk-pci",\
+ .property = "config-wce",\
+ .value = "off",\
}
static QEMUMachine pc_machine_v1_1 = {
diff --git a/hw/pci_host.c b/hw/pci_host.c
index 8041778..3950e94 100644
--- a/hw/pci_host.c
+++ b/hw/pci_host.c
@@ -165,4 +165,16 @@ const MemoryRegionOps pci_host_data_be_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
+static const TypeInfo pci_host_type_info = {
+ .name = TYPE_PCI_HOST_BRIDGE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .abstract = true,
+ .instance_size = sizeof(PCIHostState),
+};
+
+static void pci_host_register_types(void)
+{
+ type_register_static(&pci_host_type_info);
+}
+type_init(pci_host_register_types)
diff --git a/hw/pci_host.h b/hw/pci_host.h
index 359e38f..4b9c300 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -30,8 +30,13 @@
#include "sysbus.h"
+#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
+#define PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
+
struct PCIHostState {
SysBusDevice busdev;
+
MemoryRegion conf_mem;
MemoryRegion data_mem;
MemoryRegion mmcfg;
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index 6a7d0c0..dced648 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -39,7 +39,8 @@
#include "microblaze_boot.h"
#include "microblaze_pic_cpu.h"
-#include "xilinx_axidma.h"
+
+#include "stream.h"
#define LMB_BRAM_SIZE (128 * 1024)
#define FLASH_SIZE (32 * 1024 * 1024)
@@ -76,7 +77,7 @@ petalogix_ml605_init(ram_addr_t ram_size,
const char *initrd_filename, const char *cpu_model)
{
MemoryRegion *address_space_mem = get_system_memory();
- DeviceState *dev;
+ DeviceState *dev, *dma, *eth0;
MicroBlazeCPU *cpu;
CPUMBState *env;
DriveInfo *dinfo;
@@ -125,15 +126,18 @@ petalogix_ml605_init(ram_addr_t ram_size,
/* 2 timers at irq 2 @ 100 Mhz. */
xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000);
- /* axi ethernet and dma initialization. TODO: Dynamically connect them. */
- {
- static struct XilinxDMAConnection dmach;
+ /* axi ethernet and dma initialization. */
+ dma = qdev_create(NULL, "xlnx.axi-dma");
- xilinx_axiethernet_create(&dmach, &nd_table[0], 0x82780000,
- irq[3], 0x1000, 0x1000);
- xilinx_axiethernetdma_create(&dmach, 0x84600000,
- irq[1], irq[0], 100 * 1000000);
- }
+ /* FIXME: attach to the sysbus instead */
+ object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
+ "xilinx-dma", OBJECT(dma), NULL);
+
+ eth0 = xilinx_axiethernet_create(&nd_table[0], STREAM_SLAVE(dma),
+ 0x82780000, irq[3], 0x1000, 0x1000);
+
+ xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0),
+ 0x84600000, irq[1], irq[0], 100 * 1000000);
microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE,
machine_cpu_reset);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index c497a01..537fc19 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -36,7 +36,9 @@
* http://download.intel.com/design/chipsets/datashts/29054901.pdf
*/
-typedef PCIHostState I440FXState;
+typedef struct I440FXState {
+ PCIHostState parent_obj;
+} I440FXState;
#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */
#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */
@@ -225,7 +227,7 @@ static const VMStateDescription vmstate_i440fx = {
static int i440fx_pcihost_initfn(SysBusDevice *dev)
{
- I440FXState *s = FROM_SYSBUS(I440FXState, dev);
+ PCIHostState *s = PCI_HOST_BRIDGE(dev);
memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
"pci-conf-idx", 4);
@@ -267,14 +269,14 @@ static PCIBus *i440fx_common_init(const char *device_name,
DeviceState *dev;
PCIBus *b;
PCIDevice *d;
- I440FXState *s;
+ PCIHostState *s;
PIIX3State *piix3;
PCII440FXState *f;
dev = qdev_create(NULL, "i440FX-pcihost");
- s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
+ s = PCI_HOST_BRIDGE(dev);
s->address_space = address_space_mem;
- b = pci_bus_new(&s->busdev.qdev, NULL, pci_address_space,
+ b = pci_bus_new(dev, NULL, pci_address_space,
address_space_io, 0);
s->bus = b;
object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
@@ -537,7 +539,7 @@ static void piix3_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_ISA;
}
-static TypeInfo piix3_info = {
+static const TypeInfo piix3_info = {
.name = "PIIX3",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX3State),
@@ -560,7 +562,7 @@ static void piix3_xen_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_ISA;
};
-static TypeInfo piix3_xen_info = {
+static const TypeInfo piix3_xen_info = {
.name = "PIIX3-xen",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX3State),
@@ -584,7 +586,7 @@ static void i440fx_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_i440fx;
}
-static TypeInfo i440fx_info = {
+static const TypeInfo i440fx_info = {
.name = "i440FX",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCII440FXState),
@@ -601,9 +603,9 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo i440fx_pcihost_info = {
+static const TypeInfo i440fx_pcihost_info = {
.name = "i440FX-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(I440FXState),
.class_init = i440fx_pcihost_class_init,
};
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index aa4bbeb..951e407 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -15,7 +15,7 @@ obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o spapr_iommu.o
obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
obj-y += ppc440_bamboo.o
# PowerPC E500 boards
-obj-$(CONFIG_FDT) += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
+obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o
# PowerPC 440 Xilinx ML507 reference board.
obj-y += virtex_ml507.o
# PowerPC OpenPIC
@@ -26,3 +26,5 @@ obj-$(CONFIG_FDT) += ../device_tree.o
obj-y += xilinx_ethlite.o
obj-y := $(addprefix ../,$(obj-y))
+
+obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppc/e500.c
index 8b9fd83..6f0de6d 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppc/e500.c
@@ -1,5 +1,5 @@
/*
- * QEMU PowerPC MPC8544DS board emulation
+ * QEMU PowerPC e500-based platforms
*
* Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
*
@@ -16,20 +16,21 @@
#include "config.h"
#include "qemu-common.h"
+#include "e500.h"
#include "net.h"
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
-#include "boards.h"
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "hw/pci.h"
+#include "hw/boards.h"
#include "sysemu.h"
#include "kvm.h"
#include "kvm_ppc.h"
#include "device_tree.h"
-#include "openpic.h"
-#include "ppc.h"
-#include "loader.h"
+#include "hw/openpic.h"
+#include "hw/ppc.h"
+#include "hw/loader.h"
#include "elf.h"
-#include "sysbus.h"
+#include "hw/sysbus.h"
#include "exec-memory.h"
#include "host-utils.h"
@@ -42,6 +43,7 @@
#define RAM_SIZES_ALIGN (64UL << 20)
+/* TODO: parameterize */
#define MPC8544_CCSRBAR_BASE 0xE0000000ULL
#define MPC8544_CCSRBAR_SIZE 0x00100000ULL
#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000ULL)
@@ -66,18 +68,18 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
int i;
const uint32_t tmp[] = {
/* IDSEL 0x11 J17 Slot 1 */
- 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0,
- 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0,
- 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0,
- 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
+ 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
+ 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
+ 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
+ 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
/* IDSEL 0x12 J16 Slot 2 */
- 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0,
- 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0,
- 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0,
- 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
+ 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
+ 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
+ 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
+ 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
};
- for (i = 0; i < ARRAY_SIZE(tmp); i++) {
+ for (i = 0; i < (7 * 8); i++) {
pci_map[i] = cpu_to_be32(tmp[i]);
}
}
@@ -95,7 +97,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
- qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2, 0, 0);
+ qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
@@ -104,31 +106,28 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
}
}
-static int mpc8544_load_device_tree(CPUPPCState *env,
+static int ppce500_load_device_tree(CPUPPCState *env,
+ PPCE500Params *params,
target_phys_addr_t addr,
- target_phys_addr_t ramsize,
target_phys_addr_t initrd_base,
- target_phys_addr_t initrd_size,
- const char *kernel_cmdline)
+ target_phys_addr_t initrd_size)
{
int ret = -1;
- uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
+ uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
int fdt_size;
void *fdt;
uint8_t hypercall[16];
uint32_t clock_freq = 400000000;
uint32_t tb_freq = 400000000;
int i;
- const char *compatible = "MPC8544DS\0MPC85xxDS";
- int compatible_len = sizeof("MPC8544DS\0MPC85xxDS");
+ const char *toplevel_compat = NULL; /* user override */
char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
- char model[] = "MPC8544DS";
char soc[128];
char mpic[128];
uint32_t mpic_ph;
char gutil[128];
char pci[128];
- uint32_t pci_map[9 * 8];
+ uint32_t pci_map[7 * 8];
uint32_t pci_ranges[14] =
{
0x2000000, 0x0, 0xc0000000,
@@ -145,14 +144,9 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
if (machine_opts) {
- const char *tmp;
dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
dtb_file = qemu_opt_get(machine_opts, "dtb");
- tmp = qemu_opt_get(machine_opts, "dt_compatible");
- if (tmp) {
- compatible = tmp;
- compatible_len = strlen(compatible) + 1;
- }
+ toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
}
if (dtb_file) {
@@ -175,8 +169,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
/* Manipulate device tree in memory. */
- qemu_devtree_setprop_string(fdt, "/", "model", model);
- qemu_devtree_setprop(fdt, "/", "compatible", compatible, compatible_len);
qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
@@ -201,7 +193,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
- kernel_cmdline);
+ params->kernel_cmdline);
if (ret < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
@@ -282,18 +274,15 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, mpic);
qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
- qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
+ qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
MPC8544_CCSRBAR_BASE, 0x40000);
qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
- qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4);
+ qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
mpic_ph = qemu_devtree_alloc_phandle(fdt);
qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
- qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0);
- qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0);
- qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255);
/*
* We have to generate ser1 first, because Linux takes the first
@@ -323,7 +312,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
- qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
+ qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
for (i = 0; i < 14; i++) {
pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
@@ -337,6 +326,13 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
+ params->fixup_devtree(params, fdt);
+
+ if (toplevel_compat) {
+ qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
+ strlen(toplevel_compat) + 1);
+ }
+
done:
if (dumpdtb) {
/* Dump the dtb to a file and quit */
@@ -388,7 +384,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env)
env->tlb_dirty = true;
}
-static void mpc8544ds_cpu_reset_sec(void *opaque)
+static void ppce500_cpu_reset_sec(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
@@ -401,7 +397,7 @@ static void mpc8544ds_cpu_reset_sec(void *opaque)
env->exception_index = EXCP_HLT;
}
-static void mpc8544ds_cpu_reset(void *opaque)
+static void ppce500_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
@@ -417,12 +413,7 @@ static void mpc8544ds_cpu_reset(void *opaque)
mmubooke_create_initial_mapping(env);
}
-static void mpc8544ds_init(ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- const char *cpu_model)
+void ppce500_init(PPCE500Params *params)
{
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -443,8 +434,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
CPUPPCState *firstenv = NULL;
/* Setup CPUs */
- if (cpu_model == NULL) {
- cpu_model = "e500v2_v30";
+ if (params->cpu_model == NULL) {
+ params->cpu_model = "e500v2_v30";
}
irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
@@ -453,7 +444,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
PowerPCCPU *cpu;
qemu_irq *input;
- cpu = cpu_ppc_init(cpu_model);
+ cpu = cpu_ppc_init(params->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to initialize CPU!\n");
exit(1);
@@ -478,11 +469,11 @@ static void mpc8544ds_init(ram_addr_t ram_size,
/* Primary CPU */
struct boot_info *boot_info;
boot_info = g_malloc0(sizeof(struct boot_info));
- qemu_register_reset(mpc8544ds_cpu_reset, cpu);
+ qemu_register_reset(ppce500_cpu_reset, cpu);
env->load_info = boot_info;
} else {
/* Secondary CPUs */
- qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu);
+ qemu_register_reset(ppce500_cpu_reset_sec, cpu);
}
}
@@ -542,43 +533,45 @@ static void mpc8544ds_init(ram_addr_t ram_size,
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
/* Load kernel. */
- if (kernel_filename) {
- kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
+ if (params->kernel_filename) {
+ kernel_size = load_uimage(params->kernel_filename, &entry,
+ &loadaddr, NULL);
if (kernel_size < 0) {
- kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
- &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+ kernel_size = load_elf(params->kernel_filename, NULL, NULL,
+ &elf_entry, &elf_lowaddr, NULL, 1,
+ ELF_MACHINE, 0);
entry = elf_entry;
loadaddr = elf_lowaddr;
}
/* XXX try again as binary */
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
+ params->kernel_filename);
exit(1);
}
}
/* Load initrd. */
- if (initrd_filename) {
+ if (params->initrd_filename) {
initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
ram_size - initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
+ params->initrd_filename);
exit(1);
}
}
/* If we're loading a kernel directly, we must load the device tree too. */
- if (kernel_filename) {
+ if (params->kernel_filename) {
struct boot_info *boot_info;
int dt_size;
dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
- dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
- initrd_size, kernel_cmdline);
+ dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
+ initrd_size);
if (dt_size < 0) {
fprintf(stderr, "couldn't load device tree\n");
exit(1);
@@ -594,17 +587,3 @@ static void mpc8544ds_init(ram_addr_t ram_size,
kvmppc_init();
}
}
-
-static QEMUMachine mpc8544ds_machine = {
- .name = "mpc8544ds",
- .desc = "mpc8544ds",
- .init = mpc8544ds_init,
- .max_cpus = 15,
-};
-
-static void mpc8544ds_machine_init(void)
-{
- qemu_register_machine(&mpc8544ds_machine);
-}
-
-machine_init(mpc8544ds_machine_init);
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
new file mode 100644
index 0000000..7ae87f4
--- /dev/null
+++ b/hw/ppc/e500.h
@@ -0,0 +1,21 @@
+#ifndef PPCE500_H
+#define PPCE500_H
+
+typedef struct PPCE500Params {
+ /* Standard QEMU machine init params */
+ ram_addr_t ram_size;
+ const char *boot_device;
+ const char *kernel_filename;
+ const char *kernel_cmdline;
+ const char *initrd_filename;
+ const char *cpu_model;
+
+ /* e500-specific params */
+
+ /* required -- must at least add toplevel board compatible */
+ void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
+} PPCE500Params;
+
+void ppce500_init(PPCE500Params *params);
+
+#endif
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
new file mode 100644
index 0000000..60a5cb3
--- /dev/null
+++ b/hw/ppc/e500plat.c
@@ -0,0 +1,60 @@
+/*
+ * Generic device-tree-driven paravirt PPC e500 platform
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "e500.h"
+#include "../boards.h"
+#include "device_tree.h"
+
+static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
+{
+ const char model[] = "QEMU ppce500";
+ const char compatible[] = "fsl,qemu-e500";
+
+ qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
+ qemu_devtree_setprop(fdt, "/", "compatible", compatible,
+ sizeof(compatible));
+}
+
+static void e500plat_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ PPCE500Params params = {
+ .ram_size = ram_size,
+ .boot_device = boot_device,
+ .kernel_filename = kernel_filename,
+ .kernel_cmdline = kernel_cmdline,
+ .initrd_filename = initrd_filename,
+ .cpu_model = cpu_model,
+ .fixup_devtree = e500plat_fixup_devtree,
+ };
+
+ ppce500_init(&params);
+}
+
+static QEMUMachine e500plat_machine = {
+ .name = "ppce500",
+ .desc = "generic paravirt e500 platform",
+ .init = e500plat_init,
+ .max_cpus = 15,
+};
+
+static void e500plat_machine_init(void)
+{
+ qemu_register_machine(&e500plat_machine);
+}
+
+machine_init(e500plat_machine_init);
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
new file mode 100644
index 0000000..984d21c
--- /dev/null
+++ b/hw/ppc/mpc8544ds.c
@@ -0,0 +1,61 @@
+/*
+ * Support for the PPC e500-based mpc8544ds board
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "e500.h"
+#include "../boards.h"
+#include "device_tree.h"
+
+static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
+{
+ const char model[] = "MPC8544DS";
+ const char compatible[] = "MPC8544DS\0MPC85xxDS";
+
+ qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
+ qemu_devtree_setprop(fdt, "/", "compatible", compatible,
+ sizeof(compatible));
+}
+
+static void mpc8544ds_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ PPCE500Params params = {
+ .ram_size = ram_size,
+ .boot_device = boot_device,
+ .kernel_filename = kernel_filename,
+ .kernel_cmdline = kernel_cmdline,
+ .initrd_filename = initrd_filename,
+ .cpu_model = cpu_model,
+ .fixup_devtree = mpc8544ds_fixup_devtree,
+ };
+
+ ppce500_init(&params);
+}
+
+
+static QEMUMachine ppce500_machine = {
+ .name = "mpc8544ds",
+ .desc = "mpc8544ds",
+ .init = mpc8544ds_init,
+ .max_cpus = 15,
+};
+
+static void ppce500_machine_init(void)
+{
+ qemu_register_machine(&ppce500_machine);
+}
+
+machine_init(ppce500_machine_init);
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 0dd4dab..c198071 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -216,7 +216,8 @@ static void bamboo_init(ram_addr_t ram_size,
ram_bases, ram_sizes, 1);
/* PCI */
- dev = sysbus_create_varargs("ppc4xx-pcihost", PPC440EP_PCI_CONFIG,
+ dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
+ PPC440EP_PCI_CONFIG,
pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
NULL);
diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h
index b511020..5cd78b6 100644
--- a/hw/ppc4xx.h
+++ b/hw/ppc4xx.h
@@ -53,6 +53,8 @@ void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
target_phys_addr_t *ram_sizes,
int do_init);
+#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
+
PCIBus *ppc4xx_pci_init(CPUPPCState *env, qemu_irq pci_irqs[4],
target_phys_addr_t config_space,
target_phys_addr_t int_ack,
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 203c3cd..a14fd42 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -45,11 +45,14 @@ struct PCITargetMap {
uint32_t la;
};
+#define PPC4xx_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PPC4xxPCIState, (obj), TYPE_PPC4xx_PCI_HOST_BRIDGE)
+
#define PPC4xx_PCI_NR_PMMS 3
#define PPC4xx_PCI_NR_PTMS 2
struct PPC4xxPCIState {
- PCIHostState pci_state;
+ PCIHostState parent_obj;
struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
@@ -93,16 +96,18 @@ static uint64_t pci4xx_cfgaddr_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
PPC4xxPCIState *ppc4xx_pci = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
- return ppc4xx_pci->pci_state.config_reg;
+ return phb->config_reg;
}
static void pci4xx_cfgaddr_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned size)
{
PPC4xxPCIState *ppc4xx_pci = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
- ppc4xx_pci->pci_state.config_reg = value & ~0x3;
+ phb->config_reg = value & ~0x3;
}
static const MemoryRegionOps pci4xx_cfgaddr_ops = {
@@ -335,17 +340,17 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
PCIBus *b;
int i;
- h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
- s = DO_UPCAST(PPC4xxPCIState, pci_state, h);
+ h = PCI_HOST_BRIDGE(dev);
+ s = PPC4xx_PCI_HOST_BRIDGE(dev);
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
sysbus_init_irq(dev, &s->irq[i]);
}
- b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, ppc4xx_pci_set_irq,
+ b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq,
ppc4xx_pci_map_irq, s->irq, get_system_memory(),
get_system_io(), 0, 4);
- s->pci_state.bus = b;
+ h->bus = b;
pci_create_simple(b, 0, "ppc4xx-host-bridge");
@@ -377,7 +382,7 @@ static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_OTHER;
}
-static TypeInfo ppc4xx_host_bridge_info = {
+static const TypeInfo ppc4xx_host_bridge_info = {
.name = "ppc4xx-host-bridge",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -393,9 +398,9 @@ static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_ppc4xx_pci;
}
-static TypeInfo ppc4xx_pcihost_info = {
- .name = "ppc4xx-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo ppc4xx_pcihost_info = {
+ .name = TYPE_PPC4xx_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PPC4xxPCIState),
.class_init = ppc4xx_pcihost_class_init,
};
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index af75e45..7d08418 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -55,6 +55,7 @@ qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
int nb_cpus, qemu_irq **irqs);
/* Grackle PCI */
+#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost"
PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 4e2a6e6..e95cfe8 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -52,7 +52,6 @@
#include "adb.h"
#include "mac_dbdma.h"
#include "nvram.h"
-#include "pc.h"
#include "pci.h"
#include "net.h"
#include "sysemu.h"
@@ -68,6 +67,7 @@
#include "hw/usb.h"
#include "blockdev.h"
#include "exec-memory.h"
+#include "vga-pci.h"
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index f2c6908..1dcd8a6 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -29,7 +29,6 @@
#include "adb.h"
#include "mac_dbdma.h"
#include "nvram.h"
-#include "pc.h"
#include "sysemu.h"
#include "net.h"
#include "isa.h"
@@ -44,6 +43,7 @@
#include "kvm_ppc.h"
#include "blockdev.h"
#include "exec-memory.h"
+#include "vga-pci.h"
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index be2b268..592b7b2 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -39,6 +39,7 @@
#include "blockdev.h"
#include "arch_init.h"
#include "exec-memory.h"
+#include "vga-pci.h"
//#define HARD_DEBUG_PPC_IO
//#define DEBUG_PPC_IO
@@ -470,7 +471,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
uint32_t kernel_base, initrd_base;
long kernel_size, initrd_size;
DeviceState *dev;
- SysBusDevice *sys;
PCIHostState *pcihost;
PCIBus *pci_bus;
PCIDevice *pci;
@@ -583,8 +583,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
}
dev = qdev_create(NULL, "raven-pcihost");
- sys = sysbus_from_qdev(dev);
- pcihost = DO_UPCAST(PCIHostState, busdev, sys);
+ pcihost = PCI_HOST_BRIDGE(dev);
pcihost->address_space = get_system_memory();
object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL);
qdev_init_nofail(dev);
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 0f60b24..92b1dc0 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -72,8 +72,14 @@ struct pci_inbound {
uint32_t piwar;
};
+#define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost"
+
+#define PPC_E500_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PPCE500PCIState, (obj), TYPE_PPC_E500_PCI_HOST_BRIDGE)
+
struct PPCE500PCIState {
- PCIHostState pci_state;
+ PCIHostState parent_obj;
+
struct pci_outbound pob[PPCE500_PCI_NR_POBS];
struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
uint32_t gasket_time;
@@ -310,17 +316,17 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *address_space_io = get_system_io();
- h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
- s = DO_UPCAST(PPCE500PCIState, pci_state, h);
+ h = PCI_HOST_BRIDGE(dev);
+ s = PPC_E500_PCI_HOST_BRIDGE(dev);
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
sysbus_init_irq(dev, &s->irq[i]);
}
- b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
+ b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
mpc85xx_pci_map_irq, s->irq, address_space_mem,
address_space_io, PCI_DEVFN(0x11, 0), 4);
- s->pci_state.bus = b;
+ h->bus = b;
pci_create_simple(b, 0, "e500-host-bridge");
@@ -350,7 +356,7 @@ static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
dc->desc = "Host bridge";
}
-static TypeInfo e500_host_bridge_info = {
+static const TypeInfo e500_host_bridge_info = {
.name = "e500-host-bridge",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -366,9 +372,9 @@ static void e500_pcihost_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_ppce500_pci;
}
-static TypeInfo e500_pcihost_info = {
- .name = "e500-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo e500_pcihost_info = {
+ .name = TYPE_PPC_E500_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PPCE500PCIState),
.class_init = e500_pcihost_class_init,
};
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 38dbff4..cc44e61 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -28,8 +28,14 @@
#include "pc.h"
#include "exec-memory.h"
+#define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
+
+#define RAVEN_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PREPPCIState, (obj), TYPE_RAVEN_PCI_HOST_BRIDGE)
+
typedef struct PRePPCIState {
- PCIHostState host_state;
+ PCIHostState parent_obj;
+
MemoryRegion intack;
qemu_irq irq[4];
} PREPPCIState;
@@ -42,9 +48,10 @@ static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
{
int i;
- for(i = 0; i < 11; i++) {
- if ((addr & (1 << (11 + i))) != 0)
+ for (i = 0; i < 11; i++) {
+ if ((addr & (1 << (11 + i))) != 0) {
break;
+ }
}
return (addr & 0x7ff) | (i << 11);
}
@@ -53,14 +60,16 @@ static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
PREPPCIState *s = opaque;
- pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, size);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
+ pci_data_write(phb->bus, PPC_PCIIO_config(addr), val, size);
}
static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr,
unsigned int size)
{
PREPPCIState *s = opaque;
- return pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), size);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
+ return pci_data_read(phb->bus, PPC_PCIIO_config(addr), size);
}
static const MemoryRegionOps PPC_PCIIO_ops = {
@@ -96,8 +105,8 @@ static void prep_set_irq(void *opaque, int irq_num, int level)
static int raven_pcihost_init(SysBusDevice *dev)
{
- PCIHostState *h = FROM_SYSBUS(PCIHostState, dev);
- PREPPCIState *s = DO_UPCAST(PREPPCIState, host_state, h);
+ PCIHostState *h = PCI_HOST_BRIDGE(dev);
+ PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *address_space_io = get_system_io();
PCIBus *bus;
@@ -107,7 +116,7 @@ static int raven_pcihost_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq[i]);
}
- bus = pci_register_bus(&h->busdev.qdev, NULL,
+ bus = pci_register_bus(DEVICE(dev), NULL,
prep_set_irq, prep_map_irq, s->irq,
address_space_mem, address_space_io, 0, 4);
h->bus = bus;
@@ -166,7 +175,7 @@ static void raven_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo raven_info = {
+static const TypeInfo raven_info = {
.name = "raven",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(RavenPCIState),
@@ -183,9 +192,9 @@ static void raven_pcihost_class_init(ObjectClass *klass, void *data)
dc->no_user = 1;
}
-static TypeInfo raven_pcihost_info = {
- .name = "raven-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo raven_pcihost_info = {
+ .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PREPPCIState),
.class_init = raven_pcihost_class_init,
};
diff --git a/hw/puv3.c b/hw/puv3.c
new file mode 100644
index 0000000..43f7216
--- /dev/null
+++ b/hw/puv3.c
@@ -0,0 +1,131 @@
+/*
+ * Generic PKUnity SoC machine and board descriptor
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "console.h"
+#include "elf.h"
+#include "exec-memory.h"
+#include "sysbus.h"
+#include "boards.h"
+#include "loader.h"
+#include "pc.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+#define KERNEL_LOAD_ADDR 0x03000000
+#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */
+
+static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
+{
+ CPUUniCore32State *env = opaque;
+
+ assert(irq == 0);
+ if (level) {
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void puv3_soc_init(CPUUniCore32State *env)
+{
+ qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR];
+ DeviceState *dev;
+ MemoryRegion *i8042 = g_new(MemoryRegion, 1);
+ int i;
+
+ /* Initialize interrupt controller */
+ cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1);
+ dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc);
+ for (i = 0; i < PUV3_IRQS_NR; i++) {
+ irqs[i] = qdev_get_gpio_in(dev, i);
+ }
+
+ /* Initialize minimal necessary devices for kernel booting */
+ sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
+ sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
+ sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
+ sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
+ irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
+ irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
+ irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
+ irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
+ irqs[PUV3_IRQS_GPIOHIGH], NULL);
+
+ /* Keyboard (i8042), mouse disabled for nographic */
+ i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
+ memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
+}
+
+static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
+{
+ MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
+
+ /* SDRAM at address zero. */
+ memory_region_init_ram(ram_memory, "puv3.ram", ram_size);
+ vmstate_register_ram_global(ram_memory);
+ memory_region_add_subregion(get_system_memory(), 0, ram_memory);
+}
+
+static void puv3_load_kernel(const char *kernel_filename)
+{
+ int size;
+
+ assert(kernel_filename != NULL);
+
+ /* only zImage format supported */
+ size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+ KERNEL_MAX_SIZE);
+ if (size < 0) {
+ hw_error("Load kernel error: '%s'\n", kernel_filename);
+ }
+
+ /* cheat curses that we have a graphic console, only under ocd console */
+ graphic_console_init(NULL, NULL, NULL, NULL, NULL);
+}
+
+static void puv3_init(ram_addr_t ram_size, const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ CPUUniCore32State *env;
+
+ if (initrd_filename) {
+ hw_error("Please use kernel built-in initramdisk.\n");
+ }
+
+ if (!cpu_model) {
+ cpu_model = "UniCore-II";
+ }
+
+ env = cpu_init(cpu_model);
+ if (!env) {
+ hw_error("Unable to find CPU definition\n");
+ }
+
+ puv3_soc_init(env);
+ puv3_board_init(env, ram_size);
+ puv3_load_kernel(kernel_filename);
+}
+
+static QEMUMachine puv3_machine = {
+ .name = "puv3",
+ .desc = "PKUnity Version-3 based on UniCore32",
+ .init = puv3_init,
+ .is_default = 1,
+ .use_scsi = 0,
+};
+
+static void puv3_machine_init(void)
+{
+ qemu_register_machine(&puv3_machine);
+}
+
+machine_init(puv3_machine_init)
diff --git a/hw/puv3.h b/hw/puv3.h
new file mode 100644
index 0000000..f37adcb
--- /dev/null
+++ b/hw/puv3.h
@@ -0,0 +1,49 @@
+/*
+ * Misc PKUnity SoC declarations
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_HW_PUV3_H
+#define QEMU_HW_PUV3_H
+
+#define PUV3_REGS_OFFSET (0x1000) /* 4K is reasonable */
+
+/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
+#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */
+
+/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
+#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */
+#define PUV3_INTC_BASE (0xee600000) /* APB-6 */
+#define PUV3_OST_BASE (0xee800000) /* APB-8 */
+#define PUV3_PM_BASE (0xeea00000) /* APB-10 */
+#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */
+
+/* Hardware interrupts */
+#define PUV3_IRQS_NR (32)
+
+#define PUV3_IRQS_GPIOLOW0 (0)
+#define PUV3_IRQS_GPIOLOW1 (1)
+#define PUV3_IRQS_GPIOLOW2 (2)
+#define PUV3_IRQS_GPIOLOW3 (3)
+#define PUV3_IRQS_GPIOLOW4 (4)
+#define PUV3_IRQS_GPIOLOW5 (5)
+#define PUV3_IRQS_GPIOLOW6 (6)
+#define PUV3_IRQS_GPIOLOW7 (7)
+#define PUV3_IRQS_GPIOHIGH (8)
+#define PUV3_IRQS_PS2_KBD (22)
+#define PUV3_IRQS_PS2_AUX (23)
+#define PUV3_IRQS_OST0 (26)
+
+/* All puv3_*.c use DPRINTF for debug. */
+#ifdef DEBUG_PUV3
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#endif /* !QEMU_HW_PUV3_H */
diff --git a/hw/puv3_dma.c b/hw/puv3_dma.c
new file mode 100644
index 0000000..85b97bf
--- /dev/null
+++ b/hw/puv3_dma.c
@@ -0,0 +1,109 @@
+/*
+ * DMA device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+#define PUV3_DMA_CH_NR (6)
+#define PUV3_DMA_CH_MASK (0xff)
+#define PUV3_DMA_CH(offset) ((offset) >> 8)
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ uint32_t reg_CFG[PUV3_DMA_CH_NR];
+} PUV3DMAState;
+
+static uint64_t puv3_dma_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3DMAState *s = opaque;
+ uint32_t ret = 0;
+
+ assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+ switch (offset & PUV3_DMA_CH_MASK) {
+ case 0x10:
+ ret = s->reg_CFG[PUV3_DMA_CH(offset)];
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_dma_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3DMAState *s = opaque;
+
+ assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+ switch (offset & PUV3_DMA_CH_MASK) {
+ case 0x10:
+ s->reg_CFG[PUV3_DMA_CH(offset)] = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_dma_ops = {
+ .read = puv3_dma_read,
+ .write = puv3_dma_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_dma_init(SysBusDevice *dev)
+{
+ PUV3DMAState *s = FROM_SYSBUS(PUV3DMAState, dev);
+ int i;
+
+ for (i = 0; i < PUV3_DMA_CH_NR; i++) {
+ s->reg_CFG[i] = 0x0;
+ }
+
+ memory_region_init_io(&s->iomem, &puv3_dma_ops, s, "puv3_dma",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_dma_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_dma_init;
+}
+
+static const TypeInfo puv3_dma_info = {
+ .name = "puv3_dma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3DMAState),
+ .class_init = puv3_dma_class_init,
+};
+
+static void puv3_dma_register_type(void)
+{
+ type_register_static(&puv3_dma_info);
+}
+
+type_init(puv3_dma_register_type)
diff --git a/hw/puv3_gpio.c b/hw/puv3_gpio.c
new file mode 100644
index 0000000..9436e6c
--- /dev/null
+++ b/hw/puv3_gpio.c
@@ -0,0 +1,141 @@
+/*
+ * GPIO device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq irq[9];
+
+ uint32_t reg_GPLR;
+ uint32_t reg_GPDR;
+ uint32_t reg_GPIR;
+} PUV3GPIOState;
+
+static uint64_t puv3_gpio_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3GPIOState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x00:
+ ret = s->reg_GPLR;
+ break;
+ case 0x04:
+ ret = s->reg_GPDR;
+ break;
+ case 0x20:
+ ret = s->reg_GPIR;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_gpio_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3GPIOState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x04:
+ s->reg_GPDR = value;
+ break;
+ case 0x08:
+ if (s->reg_GPDR & value) {
+ s->reg_GPLR |= value;
+ } else {
+ DPRINTF("Write gpio input port error!");
+ }
+ break;
+ case 0x0c:
+ if (s->reg_GPDR & value) {
+ s->reg_GPLR &= ~value;
+ } else {
+ DPRINTF("Write gpio input port error!");
+ }
+ break;
+ case 0x10: /* GRER */
+ case 0x14: /* GFER */
+ case 0x18: /* GEDR */
+ break;
+ case 0x20: /* GPIR */
+ s->reg_GPIR = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+}
+
+static const MemoryRegionOps puv3_gpio_ops = {
+ .read = puv3_gpio_read,
+ .write = puv3_gpio_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_gpio_init(SysBusDevice *dev)
+{
+ PUV3GPIOState *s = FROM_SYSBUS(PUV3GPIOState, dev);
+
+ s->reg_GPLR = 0;
+ s->reg_GPDR = 0;
+
+ /* FIXME: these irqs not handled yet */
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW0]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW1]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW2]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW3]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW4]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW5]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW6]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW7]);
+ sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOHIGH]);
+
+ memory_region_init_io(&s->iomem, &puv3_gpio_ops, s, "puv3_gpio",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_gpio_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_gpio_init;
+}
+
+static const TypeInfo puv3_gpio_info = {
+ .name = "puv3_gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3GPIOState),
+ .class_init = puv3_gpio_class_init,
+};
+
+static void puv3_gpio_register_type(void)
+{
+ type_register_static(&puv3_gpio_info);
+}
+
+type_init(puv3_gpio_register_type)
diff --git a/hw/puv3_intc.c b/hw/puv3_intc.c
new file mode 100644
index 0000000..9e0b975
--- /dev/null
+++ b/hw/puv3_intc.c
@@ -0,0 +1,135 @@
+/*
+ * INTC device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq parent_irq;
+
+ uint32_t reg_ICMR;
+ uint32_t reg_ICPR;
+} PUV3INTCState;
+
+/* Update interrupt status after enabled or pending bits have been changed. */
+static void puv3_intc_update(PUV3INTCState *s)
+{
+ if (s->reg_ICMR & s->reg_ICPR) {
+ qemu_irq_raise(s->parent_irq);
+ } else {
+ qemu_irq_lower(s->parent_irq);
+ }
+}
+
+/* Process a change in an external INTC input. */
+static void puv3_intc_handler(void *opaque, int irq, int level)
+{
+ PUV3INTCState *s = opaque;
+
+ DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
+ if (level) {
+ s->reg_ICPR |= (1 << irq);
+ } else {
+ s->reg_ICPR &= ~(1 << irq);
+ }
+ puv3_intc_update(s);
+}
+
+static uint64_t puv3_intc_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3INTCState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x04: /* INTC_ICMR */
+ ret = s->reg_ICMR;
+ break;
+ case 0x0c: /* INTC_ICIP */
+ ret = s->reg_ICPR; /* the same value with ICPR */
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+ return ret;
+}
+
+static void puv3_intc_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3INTCState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x00: /* INTC_ICLR */
+ case 0x14: /* INTC_ICCR */
+ break;
+ case 0x04: /* INTC_ICMR */
+ s->reg_ICMR = value;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", (int)offset);
+ return;
+ }
+ puv3_intc_update(s);
+}
+
+static const MemoryRegionOps puv3_intc_ops = {
+ .read = puv3_intc_read,
+ .write = puv3_intc_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_intc_init(SysBusDevice *dev)
+{
+ PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev);
+
+ qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR);
+ sysbus_init_irq(&s->busdev, &s->parent_irq);
+
+ s->reg_ICMR = 0;
+ s->reg_ICPR = 0;
+
+ memory_region_init_io(&s->iomem, &puv3_intc_ops, s, "puv3_intc",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_intc_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_intc_init;
+}
+
+static const TypeInfo puv3_intc_info = {
+ .name = "puv3_intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3INTCState),
+ .class_init = puv3_intc_class_init,
+};
+
+static void puv3_intc_register_type(void)
+{
+ type_register_static(&puv3_intc_info);
+}
+
+type_init(puv3_intc_register_type)
diff --git a/hw/puv3_ost.c b/hw/puv3_ost.c
new file mode 100644
index 0000000..dd30cad
--- /dev/null
+++ b/hw/puv3_ost.c
@@ -0,0 +1,151 @@
+/*
+ * OSTimer device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysbus.h"
+#include "ptimer.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+/* puv3 ostimer implementation. */
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ QEMUBH *bh;
+ qemu_irq irq;
+ ptimer_state *ptimer;
+
+ uint32_t reg_OSMR0;
+ uint32_t reg_OSCR;
+ uint32_t reg_OSSR;
+ uint32_t reg_OIER;
+} PUV3OSTState;
+
+static uint64_t puv3_ost_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3OSTState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x10: /* Counter Register */
+ ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
+ break;
+ case 0x14: /* Status Register */
+ ret = s->reg_OSSR;
+ break;
+ case 0x1c: /* Interrupt Enable Register */
+ ret = s->reg_OIER;
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+ return ret;
+}
+
+static void puv3_ost_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3OSTState *s = opaque;
+
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+ switch (offset) {
+ case 0x00: /* Match Register 0 */
+ s->reg_OSMR0 = value;
+ if (s->reg_OSMR0 > s->reg_OSCR) {
+ ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
+ } else {
+ ptimer_set_count(s->ptimer, s->reg_OSMR0 +
+ (0xffffffff - s->reg_OSCR));
+ }
+ ptimer_run(s->ptimer, 2);
+ break;
+ case 0x14: /* Status Register */
+ assert(value == 0);
+ if (s->reg_OSSR) {
+ s->reg_OSSR = value;
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case 0x1c: /* Interrupt Enable Register */
+ s->reg_OIER = value;
+ break;
+ default:
+ DPRINTF("Bad offset %x\n", (int)offset);
+ }
+}
+
+static const MemoryRegionOps puv3_ost_ops = {
+ .read = puv3_ost_read,
+ .write = puv3_ost_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void puv3_ost_tick(void *opaque)
+{
+ PUV3OSTState *s = opaque;
+
+ DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
+ s->reg_OSCR, s->reg_OSMR0);
+
+ s->reg_OSCR = s->reg_OSMR0;
+ if (s->reg_OIER) {
+ s->reg_OSSR = 1;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static int puv3_ost_init(SysBusDevice *dev)
+{
+ PUV3OSTState *s = FROM_SYSBUS(PUV3OSTState, dev);
+
+ s->reg_OIER = 0;
+ s->reg_OSSR = 0;
+ s->reg_OSMR0 = 0;
+ s->reg_OSCR = 0;
+
+ sysbus_init_irq(dev, &s->irq);
+
+ s->bh = qemu_bh_new(puv3_ost_tick, s);
+ s->ptimer = ptimer_init(s->bh);
+ ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
+
+ memory_region_init_io(&s->iomem, &puv3_ost_ops, s, "puv3_ost",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_ost_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_ost_init;
+}
+
+static const TypeInfo puv3_ost_info = {
+ .name = "puv3_ost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3OSTState),
+ .class_init = puv3_ost_class_init,
+};
+
+static void puv3_ost_register_type(void)
+{
+ type_register_static(&puv3_ost_info);
+}
+
+type_init(puv3_ost_register_type)
diff --git a/hw/puv3_pm.c b/hw/puv3_pm.c
new file mode 100644
index 0000000..621c968
--- /dev/null
+++ b/hw/puv3_pm.c
@@ -0,0 +1,149 @@
+/*
+ * Power Management device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+
+ uint32_t reg_PMCR;
+ uint32_t reg_PCGR;
+ uint32_t reg_PLL_SYS_CFG;
+ uint32_t reg_PLL_DDR_CFG;
+ uint32_t reg_PLL_VGA_CFG;
+ uint32_t reg_DIVCFG;
+} PUV3PMState;
+
+static uint64_t puv3_pm_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ PUV3PMState *s = opaque;
+ uint32_t ret = 0;
+
+ switch (offset) {
+ case 0x14:
+ ret = s->reg_PCGR;
+ break;
+ case 0x18:
+ ret = s->reg_PLL_SYS_CFG;
+ break;
+ case 0x1c:
+ ret = s->reg_PLL_DDR_CFG;
+ break;
+ case 0x20:
+ ret = s->reg_PLL_VGA_CFG;
+ break;
+ case 0x24:
+ ret = s->reg_DIVCFG;
+ break;
+ case 0x28: /* PLL SYS STATUS */
+ ret = 0x00002401;
+ break;
+ case 0x2c: /* PLL DDR STATUS */
+ ret = 0x00100c00;
+ break;
+ case 0x30: /* PLL VGA STATUS */
+ ret = 0x00003801;
+ break;
+ case 0x34: /* DIV STATUS */
+ ret = 0x22f52015;
+ break;
+ case 0x38: /* SW RESET */
+ ret = 0x0;
+ break;
+ case 0x44: /* PLL DFC DONE */
+ ret = 0x7;
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+ return ret;
+}
+
+static void puv3_pm_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ PUV3PMState *s = opaque;
+
+ switch (offset) {
+ case 0x0:
+ s->reg_PMCR = value;
+ break;
+ case 0x14:
+ s->reg_PCGR = value;
+ break;
+ case 0x18:
+ s->reg_PLL_SYS_CFG = value;
+ break;
+ case 0x1c:
+ s->reg_PLL_DDR_CFG = value;
+ break;
+ case 0x20:
+ s->reg_PLL_VGA_CFG = value;
+ break;
+ case 0x24:
+ case 0x38:
+ break;
+ default:
+ DPRINTF("Bad offset 0x%x\n", offset);
+ }
+ DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_pm_ops = {
+ .read = puv3_pm_read,
+ .write = puv3_pm_write,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_pm_init(SysBusDevice *dev)
+{
+ PUV3PMState *s = FROM_SYSBUS(PUV3PMState, dev);
+
+ s->reg_PCGR = 0x0;
+
+ memory_region_init_io(&s->iomem, &puv3_pm_ops, s, "puv3_pm",
+ PUV3_REGS_OFFSET);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ return 0;
+}
+
+static void puv3_pm_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = puv3_pm_init;
+}
+
+static const TypeInfo puv3_pm_info = {
+ .name = "puv3_pm",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PUV3PMState),
+ .class_init = puv3_pm_class_init,
+};
+
+static void puv3_pm_register_type(void)
+{
+ type_register_static(&puv3_pm_info);
+}
+
+type_init(puv3_pm_register_type)
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index b22a37a..33b7f79 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -443,7 +443,7 @@ DeviceState *qdev_device_add(QemuOpts *opts)
bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_type);
if (!bus) {
qerror_report(QERR_NO_BUS_FOR_DEVICE,
- driver, k->bus_type);
+ k->bus_type, driver);
return NULL;
}
}
@@ -543,7 +543,7 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent);
class = object_class_get_parent(class);
} while (class != object_class_by_name(TYPE_DEVICE));
- bus_print_dev(dev->parent_bus, mon, dev, indent + 2);
+ bus_print_dev(dev->parent_bus, mon, dev, indent);
QLIST_FOREACH(child, &dev->child_bus, sibling) {
qbus_print(mon, child, indent);
}
diff --git a/hw/qdev.c b/hw/qdev.c
index b5b74b9..b5a52ac 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -159,7 +159,6 @@ int qdev_init(DeviceState *dev)
rc = dc->init(dev);
if (rc < 0) {
- object_unparent(OBJECT(dev));
qdev_free(dev);
return rc;
}
@@ -243,7 +242,6 @@ void qbus_reset_all_fn(void *opaque)
int qdev_simple_unplug_cb(DeviceState *dev)
{
/* just zap it */
- object_unparent(OBJECT(dev));
qdev_free(dev);
return 0;
}
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index b8a857d..4981a02 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -761,6 +761,7 @@ static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf)
switch (length) {
case 0:
case 3: /* USB-specific. */
+ default:
xfer = 0;
break;
case 1:
@@ -784,6 +785,7 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
switch (length) {
case 0:
case 3: /* USB-specific. */
+ default:
xfer = 0;
break;
case 1:
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c8d5edd..1585683 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -175,6 +175,8 @@ static void scsi_aio_complete(void *opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
@@ -238,10 +240,9 @@ static void scsi_dma_complete(void *opaque, int ret)
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- }
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -270,10 +271,9 @@ static void scsi_read_complete(void * opaque, int ret)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
int n;
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- }
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
@@ -637,7 +637,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
{
buflen = 8;
outbuf[4] = 0;
- outbuf[5] = 0x60; /* write_same 10/16 supported */
+ outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
outbuf[7] = 0;
break;
@@ -1449,6 +1449,89 @@ invalid_field:
return;
}
+typedef struct UnmapCBData {
+ SCSIDiskReq *r;
+ uint8_t *inbuf;
+ int count;
+} UnmapCBData;
+
+static void scsi_unmap_complete(void *opaque, int ret)
+{
+ UnmapCBData *data = opaque;
+ SCSIDiskReq *r = data->r;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ uint64_t sector_num;
+ uint32_t nb_sectors;
+
+ r->req.aiocb = NULL;
+ if (ret < 0) {
+ if (scsi_handle_rw_error(r, -ret)) {
+ goto done;
+ }
+ }
+
+ if (data->count > 0 && !r->req.io_canceled) {
+ sector_num = ldq_be_p(&data->inbuf[0]);
+ nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
+ if (sector_num > sector_num + nb_sectors ||
+ sector_num + nb_sectors - 1 > s->qdev.max_lba) {
+ scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+ goto done;
+ }
+
+ r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
+ sector_num * (s->qdev.blocksize / 512),
+ nb_sectors * (s->qdev.blocksize / 512),
+ scsi_unmap_complete, data);
+ data->count--;
+ data->inbuf += 16;
+ return;
+ }
+
+done:
+ if (data->count == 0) {
+ scsi_req_complete(&r->req, GOOD);
+ }
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
+ g_free(data);
+}
+
+static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
+{
+ uint8_t *p = inbuf;
+ int len = r->req.cmd.xfer;
+ UnmapCBData *data;
+
+ if (len < 8) {
+ goto invalid_param_len;
+ }
+ if (len < lduw_be_p(&p[0]) + 2) {
+ goto invalid_param_len;
+ }
+ if (len < lduw_be_p(&p[2]) + 8) {
+ goto invalid_param_len;
+ }
+ if (lduw_be_p(&p[2]) & 15) {
+ goto invalid_param_len;
+ }
+
+ data = g_new0(UnmapCBData, 1);
+ data->r = r;
+ data->inbuf = &p[8];
+ data->count = lduw_be_p(&p[2]) >> 4;
+
+ /* The matching unref is in scsi_unmap_complete, before data is freed. */
+ scsi_req_ref(&r->req);
+ scsi_unmap_complete(data, 0);
+ return;
+
+invalid_param_len:
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+ return;
+}
+
static void scsi_disk_emulate_write_data(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1468,6 +1551,10 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
scsi_disk_emulate_mode_select(r, r->iov.iov_base);
break;
+ case UNMAP:
+ scsi_disk_emulate_unmap(r, r->iov.iov_base);
+ break;
+
default:
abort();
}
@@ -1702,6 +1789,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
case MODE_SELECT_10:
DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
break;
+ case UNMAP:
+ DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
+ break;
case WRITE_SAME_10:
nb_sectors = lduw_be_p(&req->cmd.buf[7]);
goto write_same;
@@ -1712,7 +1802,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
return 0;
}
- if (r->req.cmd.lba > s->qdev.max_lba) {
+ if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors ||
+ r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) {
goto illegal_lba;
}
@@ -2067,6 +2158,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
[SEEK_10] = &scsi_disk_emulate_reqops,
[MODE_SELECT] = &scsi_disk_emulate_reqops,
[MODE_SELECT_10] = &scsi_disk_emulate_reqops,
+ [UNMAP] = &scsi_disk_emulate_reqops,
[WRITE_SAME_10] = &scsi_disk_emulate_reqops,
[WRITE_SAME_16] = &scsi_disk_emulate_reqops,
@@ -2329,6 +2421,7 @@ static TypeInfo scsi_cd_info = {
#ifdef __linux__
static Property scsi_block_properties[] = {
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.bs),
+ DEFINE_PROP_INT32("bootindex", SCSIDiskState, qdev.conf.bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 8d51060..a5eb663 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -479,7 +479,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
}
static Property scsi_generic_properties[] = {
- DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
+ DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
+ DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/sd.c b/hw/sd.c
index a14b50a..29d03e8 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -33,6 +33,7 @@
#include "hw.h"
#include "block.h"
#include "sd.h"
+#include "bitmap.h"
//#define DEBUG_SD 1
@@ -82,8 +83,8 @@ struct SDState {
uint32_t card_status;
uint8_t sd_status[64];
uint32_t vhs;
- int wp_switch;
- int *wp_groups;
+ bool wp_switch;
+ unsigned long *wp_groups;
uint64_t size;
int blk_len;
uint32_t erase_start;
@@ -92,12 +93,12 @@ struct SDState {
int pwd_len;
int function_group[6];
- int spi, mmc;
+ bool spi, mmc;
int current_cmd;
/* True if we will handle the next command as an ACMD. Note that this does
* *not* track the APP_CMD status bit!
*/
- int expecting_acmd;
+ bool expecting_acmd;
int blk_written;
uint64_t data_start;
uint32_t data_offset;
@@ -107,7 +108,7 @@ struct SDState {
BlockDriverState *bdrv;
uint8_t *buf;
- int enable;
+ bool enable;
int buswidth, highspeed;
};
@@ -431,6 +432,11 @@ static void sd_response_r7_make(SDState *sd, uint8_t *response)
response[3] = (sd->vhs >> 0) & 0xff;
}
+static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
+{
+ return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+}
+
void sd_reset(SDState *sd)
{
uint64_t size;
@@ -443,7 +449,7 @@ void sd_reset(SDState *sd)
}
size = sect << 9;
- sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+ sect = sd_addr_to_wpnum(size) + 1;
sd->state = sd_idle_state;
sd->rca = 0x0000;
@@ -456,15 +462,15 @@ void sd_reset(SDState *sd)
if (sd->wp_groups)
g_free(sd->wp_groups);
- sd->wp_switch = sd->bdrv ? bdrv_is_read_only(sd->bdrv) : 0;
- sd->wp_groups = (int *) g_malloc0(sizeof(int) * sect);
+ sd->wp_switch = sd->bdrv ? bdrv_is_read_only(sd->bdrv) : false;
+ sd->wp_groups = bitmap_new(sect);
memset(sd->function_group, 0, sizeof(int) * 6);
sd->erase_start = 0;
sd->erase_end = 0;
sd->size = size;
sd->blk_len = 0x200;
sd->pwd_len = 0;
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
}
static void sd_cardchange(void *opaque, bool load)
@@ -486,7 +492,7 @@ static const BlockDevOps sd_block_ops = {
whether card should be in SSI or MMC/SD mode. It is also up to the
board to ensure that ssi transfers only occur when the chip select
is asserted. */
-SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc)
+SDState *sd_init(BlockDriverState *bs, bool is_spi, bool is_mmc)
{
SDState *sd;
@@ -494,7 +500,7 @@ SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc)
sd->buf = qemu_blockalign(bs, 512);
sd->spi = is_spi;
sd->mmc = is_mmc;
- sd->enable = 1;
+ sd->enable = true;
sd->bdrv = bs;
sd_reset(sd);
if (sd->bdrv) {
@@ -520,17 +526,17 @@ static void sd_erase(SDState *sd)
return;
}
- start = sd->erase_start >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
- end = sd->erase_end >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ start = sd_addr_to_wpnum(sd->erase_start);
+ end = sd_addr_to_wpnum(sd->erase_end);
sd->erase_start = 0;
sd->erase_end = 0;
sd->csd[14] |= 0x40;
- for (i = start; i <= end; i ++)
- if (sd->wp_groups[i])
+ for (i = start; i <= end; i++) {
+ if (test_bit(i, sd->wp_groups)) {
sd->card_status |= WP_ERASE_SKIP;
+ }
+ }
}
static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
@@ -538,11 +544,13 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
uint32_t i, wpnum;
uint32_t ret = 0;
- wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ wpnum = sd_addr_to_wpnum(addr);
- for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE)
- if (addr < sd->size && sd->wp_groups[wpnum])
+ for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) {
+ if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) {
ret |= (1 << i);
+ }
+ }
return ret;
}
@@ -618,10 +626,9 @@ static void mmc_function_switch(SDState *sd, uint32_t arg)
}
}
-static inline int sd_wp_addr(SDState *sd, uint32_t addr)
+static inline bool sd_wp_addr(SDState *sd, uint64_t addr)
{
- return sd->wp_groups[addr >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
+ return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
}
static void sd_lock_command(SDState *sd)
@@ -644,8 +651,7 @@ static void sd_lock_command(SDState *sd)
sd->card_status |= LOCK_UNLOCK_FAILED;
return;
}
- memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
+ bitmap_zero(sd->wp_groups, sd_addr_to_wpnum(sd->size) + 1);
sd->csd[14] &= ~0x10;
sd->card_status &= ~CARD_IS_LOCKED;
sd->pwd_len = 0;
@@ -1151,8 +1157,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
}
sd->state = sd_programming_state;
- sd->wp_groups[addr >> (HWBLOCK_SHIFT +
- SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
+ set_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
/* Bzzzzzzztt .... Operation complete. */
sd->state = sd_transfer_state;
return sd_r1b;
@@ -1171,8 +1176,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
}
sd->state = sd_programming_state;
- sd->wp_groups[addr >> (HWBLOCK_SHIFT +
- SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
+ clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
/* Bzzzzzzztt .... Operation complete. */
sd->state = sd_transfer_state;
return sd_r1b;
@@ -1290,7 +1294,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
if (sd->rca != rca)
return sd_r0;
- sd->expecting_acmd = 1;
+ sd->expecting_acmd = true;
sd->card_status |= APP_CMD;
return sd_r1;
@@ -1472,7 +1476,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
if (sd->card_status & CARD_IS_LOCKED) {
if (!cmd_valid_while_locked(sd, req)) {
sd->card_status |= ILLEGAL_COMMAND;
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
fprintf(stderr, "SD: Card is locked\n");
rtype = sd_illegal;
goto send_response;
@@ -1483,7 +1487,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
sd_set_mode(sd);
if (sd->expecting_acmd) {
- sd->expecting_acmd = 0;
+ sd->expecting_acmd = false;
rtype = sd_app_command(sd, *req);
} else {
rtype = sd_normal_command(sd, *req);
@@ -1881,17 +1885,17 @@ uint8_t sd_read_data(SDState *sd)
return ret;
}
-int sd_data_ready(SDState *sd)
+bool sd_data_ready(SDState *sd)
{
return sd->state == sd_sendingdata_state;
}
-void sd_enable(SDState *sd, int enable)
+void sd_enable(SDState *sd, bool enable)
{
sd->enable = enable;
}
-int sd_is_mmc(SDState *sd)
+bool sd_is_mmc(SDState *sd)
{
return sd->mmc;
}
diff --git a/hw/sd.h b/hw/sd.h
index 96450f2..dae2d1f 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -67,15 +67,15 @@ typedef struct {
typedef struct SDState SDState;
-SDState *sd_init(BlockDriverState *bs, int is_spi, int is_mmc);
+SDState *sd_init(BlockDriverState *bs, bool is_spi, bool is_mmc);
void sd_reset(SDState *sd);
int sd_do_command(SDState *sd, SDRequest *req,
uint8_t *response);
void sd_write_data(SDState *sd, uint8_t value);
uint8_t sd_read_data(SDState *sd);
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
-int sd_data_ready(SDState *sd);
-void sd_enable(SDState *sd, int enable);
-int sd_is_mmc(SDState *sd);
+bool sd_data_ready(SDState *sd);
+void sd_enable(SDState *sd, bool enable);
+bool sd_is_mmc(SDState *sd);
#endif /* __hw_sd_h */
diff --git a/hw/shpc.c b/hw/shpc.c
index 6b9884d..a5baf24 100644
--- a/hw/shpc.c
+++ b/hw/shpc.c
@@ -253,7 +253,6 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
++devfn) {
PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
if (affected_dev) {
- object_unparent(OBJECT(affected_dev));
qdev_free(&affected_dev->qdev);
}
}
diff --git a/hw/spapr.c b/hw/spapr.c
index 81c9343..c34b767 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -41,12 +41,15 @@
#include "hw/spapr_vio.h"
#include "hw/spapr_pci.h"
#include "hw/xics.h"
+#include "hw/msi.h"
#include "kvm.h"
#include "kvm_ppc.h"
#include "pci.h"
+#include "vga-pci.h"
#include "exec-memory.h"
+#include "hw/usb.h"
#include <libfdt.h>
@@ -78,16 +81,15 @@
#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000)
#define SPAPR_PCI_MEM_WIN_SIZE 0x20000000
#define SPAPR_PCI_IO_WIN_ADDR (0x10000000000ULL + 0x80000000)
+#define SPAPR_PCI_MSI_WIN_ADDR (0x10000000000ULL + 0x90000000)
#define PHANDLE_XICP 0x00001111
sPAPREnvironment *spapr;
-qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
- enum xics_irq_type type)
+int spapr_allocate_irq(int hint, enum xics_irq_type type)
{
- uint32_t irq;
- qemu_irq qirq;
+ int irq;
if (hint) {
irq = hint;
@@ -96,16 +98,40 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
irq = spapr->next_irq++;
}
- qirq = xics_assign_irq(spapr->icp, irq, type);
- if (!qirq) {
- return NULL;
+ /* Configure irq type */
+ if (!xics_get_qirq(spapr->icp, irq)) {
+ return 0;
}
- if (irq_num) {
- *irq_num = irq;
+ xics_set_irq_type(spapr->icp, irq, type);
+
+ return irq;
+}
+
+/* Allocate block of consequtive IRQs, returns a number of the first */
+int spapr_allocate_irq_block(int num, enum xics_irq_type type)
+{
+ int first = -1;
+ int i;
+
+ for (i = 0; i < num; ++i) {
+ int irq;
+
+ irq = spapr_allocate_irq(0, type);
+ if (!irq) {
+ return -1;
+ }
+
+ if (0 == i) {
+ first = irq;
+ }
+
+ /* If the above doesn't create a consecutive block then that's
+ * an internal bug */
+ assert(irq == (first + i));
}
- return qirq;
+ return first;
}
static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr)
@@ -257,6 +283,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
}
_FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+ _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
+ _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
+ _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
_FDT((fdt_end_node(fdt)));
@@ -481,7 +510,7 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
}
QLIST_FOREACH(phb, &spapr->phbs, list) {
- ret = spapr_populate_pci_devices(phb, PHANDLE_XICP, fdt);
+ ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
}
if (ret < 0) {
@@ -503,7 +532,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
}
}
- spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
+ if (!spapr->has_graphics) {
+ spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
+ }
_FDT((fdt_pack(fdt)));
@@ -532,8 +563,6 @@ static void spapr_reset(void *opaque)
{
sPAPREnvironment *spapr = (sPAPREnvironment *)opaque;
- fprintf(stderr, "sPAPR reset\n");
-
/* flush out the hash table */
memset(spapr->htab, 0, spapr->htab_size);
@@ -556,6 +585,23 @@ static void spapr_cpu_reset(void *opaque)
cpu_reset(CPU(cpu));
}
+/* Returns whether we want to use VGA or not */
+static int spapr_vga_init(PCIBus *pci_bus)
+{
+ switch (vga_interface_type) {
+ case VGA_STD:
+ pci_vga_init(pci_bus);
+ return 1;
+ case VGA_NONE:
+ return 0;
+ default:
+ fprintf(stderr, "This vga model is not supported,"
+ "currently it only supports -vga std\n");
+ exit(0);
+ break;
+ }
+}
+
/* pSeries LPAR / sPAPR hardware init */
static void ppc_spapr_init(ram_addr_t ram_size,
const char *boot_device,
@@ -566,6 +612,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
{
PowerPCCPU *cpu;
CPUPPCState *env;
+ PCIHostState *phb;
int i;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -576,6 +623,8 @@ static void ppc_spapr_init(ram_addr_t ram_size,
long pteg_shift = 17;
char *filename;
+ msi_supported = true;
+
spapr = g_malloc0(sizeof(*spapr));
QLIST_INIT(&spapr->phbs);
@@ -687,10 +736,14 @@ static void ppc_spapr_init(ram_addr_t ram_size,
}
/* Set up PCI */
+ spapr_pci_rtas_init();
+
spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID,
SPAPR_PCI_MEM_WIN_ADDR,
SPAPR_PCI_MEM_WIN_SIZE,
- SPAPR_PCI_IO_WIN_ADDR);
+ SPAPR_PCI_IO_WIN_ADDR,
+ SPAPR_PCI_MSI_WIN_ADDR);
+ phb = PCI_HOST_BRIDGE(QLIST_FIRST(&spapr->phbs));
for (i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
@@ -710,20 +763,25 @@ static void ppc_spapr_init(ram_addr_t ram_size,
spapr_vscsi_create(spapr->vio_bus);
}
+ /* Graphics */
+ if (spapr_vga_init(phb->bus)) {
+ spapr->has_graphics = true;
+ }
+
+ if (usb_enabled) {
+ pci_create_simple(phb->bus, -1, "pci-ohci");
+ if (spapr->has_graphics) {
+ usbdevice_create("keyboard");
+ usbdevice_create("mouse");
+ }
+ }
+
if (rma_size < (MIN_RMA_SLOF << 20)) {
fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
"%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
exit(1);
}
- fprintf(stderr, "sPAPR memory map:\n");
- fprintf(stderr, "RTAS : 0x%08lx..%08lx\n",
- (unsigned long)spapr->rtas_addr,
- (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1));
- fprintf(stderr, "FDT : 0x%08lx..%08lx\n",
- (unsigned long)spapr->fdt_addr,
- (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1));
-
if (kernel_filename) {
uint64_t lowaddr = 0;
@@ -739,8 +797,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
kernel_filename);
exit(1);
}
- fprintf(stderr, "Kernel : 0x%08x..%08lx\n",
- KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1);
/* load initrd */
if (initrd_filename) {
@@ -755,8 +811,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
initrd_filename);
exit(1);
}
- fprintf(stderr, "Ramdisk : 0x%08lx..%08lx\n",
- (long)initrd_base, (long)(initrd_base + initrd_size - 1));
} else {
initrd_base = 0;
initrd_size = 0;
@@ -770,10 +824,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
exit(1);
}
g_free(filename);
- fprintf(stderr, "Firmware load : 0x%08x..%08lx\n",
- 0, fw_size);
- fprintf(stderr, "Firmware runtime : 0x%08lx..%08lx\n",
- load_limit, (unsigned long)spapr->fdt_addr);
spapr->entry_point = 0x100;
diff --git a/hw/spapr.h b/hw/spapr.h
index 9153f29..ac34a17 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -23,6 +23,7 @@ typedef struct sPAPREnvironment {
int next_irq;
int rtc_offset;
char *cpu_model;
+ bool has_graphics;
} sPAPREnvironment;
#define H_SUCCESS 0
@@ -288,17 +289,17 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode,
target_ulong *args);
-qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num,
- enum xics_irq_type type);
+int spapr_allocate_irq(int hint, enum xics_irq_type type);
+int spapr_allocate_irq_block(int num, enum xics_irq_type type);
-static inline qemu_irq spapr_allocate_msi(uint32_t hint, uint32_t *irq_num)
+static inline int spapr_allocate_msi(int hint)
{
- return spapr_allocate_irq(hint, irq_num, XICS_MSI);
+ return spapr_allocate_irq(hint, XICS_MSI);
}
-static inline qemu_irq spapr_allocate_lsi(uint32_t hint, uint32_t *irq_num)
+static inline int spapr_allocate_lsi(int hint)
{
- return spapr_allocate_irq(hint, irq_num, XICS_LSI);
+ return spapr_allocate_irq(hint, XICS_LSI);
}
static inline uint32_t rtas_ld(target_ulong phys, int n)
@@ -336,6 +337,8 @@ void spapr_iommu_init(void);
DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size);
void spapr_tce_free(DMAContext *dma);
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
- DMAContext *dma);
+ uint32_t liobn, uint64_t window, uint32_t size);
+int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
+ DMAContext *dma);
#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c
index 388ffa4..53b7317 100644
--- a/hw/spapr_iommu.c
+++ b/hw/spapr_iommu.c
@@ -216,31 +216,47 @@ void spapr_iommu_init(void)
}
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
- DMAContext *dma)
+ uint32_t liobn, uint64_t window, uint32_t size)
{
- if (dma) {
- sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
- uint32_t dma_prop[] = {cpu_to_be32(tcet->liobn),
- 0, 0,
- 0, cpu_to_be32(tcet->window_size)};
- int ret;
-
- ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
- if (ret < 0) {
- return ret;
- }
+ uint32_t dma_prop[5];
+ int ret;
+
+ dma_prop[0] = cpu_to_be32(liobn);
+ dma_prop[1] = cpu_to_be32(window >> 32);
+ dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF);
+ dma_prop[3] = 0; /* window size is 32 bits */
+ dma_prop[4] = cpu_to_be32(size);
+
+ ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
+ if (ret < 0) {
+ return ret;
+ }
- ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
- if (ret < 0) {
- return ret;
- }
+ ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
+ if (ret < 0) {
+ return ret;
+ }
- ret = fdt_setprop(fdt, node_off, propname, dma_prop,
- sizeof(dma_prop));
- if (ret < 0) {
- return ret;
- }
+ ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop));
+ if (ret < 0) {
+ return ret;
}
return 0;
}
+
+int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
+ DMAContext *iommu)
+{
+ if (!iommu) {
+ return 0;
+ }
+
+ if (iommu->translate == spapr_tce_translate) {
+ sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, iommu);
+ return spapr_dma_dt(fdt, node_off, propname,
+ tcet->liobn, 0, tcet->window_size);
+ }
+
+ return -1;
+}
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 01e54f3..bd3f131 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -169,7 +169,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
}
if (sdev->signal_state & 1) {
- qemu_irq_pulse(sdev->qirq);
+ qemu_irq_pulse(spapr_vio_qirq(sdev));
}
return size;
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index b2e4f78..661c05b 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -24,32 +24,59 @@
*/
#include "hw.h"
#include "pci.h"
+#include "msi.h"
+#include "msix.h"
#include "pci_host.h"
#include "hw/spapr.h"
#include "hw/spapr_pci.h"
#include "exec-memory.h"
#include <libfdt.h>
+#include "trace.h"
#include "hw/pci_internals.h"
-static PCIDevice *find_dev(sPAPREnvironment *spapr,
- uint64_t buid, uint32_t config_addr)
-{
- int devfn = (config_addr >> 8) & 0xFF;
- sPAPRPHBState *phb;
+/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
+#define RTAS_QUERY_FN 0
+#define RTAS_CHANGE_FN 1
+#define RTAS_RESET_FN 2
+#define RTAS_CHANGE_MSI_FN 3
+#define RTAS_CHANGE_MSIX_FN 4
- QLIST_FOREACH(phb, &spapr->phbs, list) {
- BusChild *kid;
+/* Interrupt types to return on RTAS_CHANGE_* */
+#define RTAS_TYPE_MSI 1
+#define RTAS_TYPE_MSIX 2
+
+static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
+{
+ sPAPRPHBState *sphb;
- if (phb->buid != buid) {
+ QLIST_FOREACH(sphb, &spapr->phbs, list) {
+ if (sphb->buid != buid) {
continue;
}
+ return sphb;
+ }
+
+ return NULL;
+}
+
+static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
+ uint32_t config_addr)
+{
+ sPAPRPHBState *sphb = find_phb(spapr, buid);
+ PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
+ BusState *bus = BUS(phb->bus);
+ BusChild *kid;
+ int devfn = (config_addr >> 8) & 0xFF;
+
+ if (!phb) {
+ return NULL;
+ }
- QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) {
- PCIDevice *dev = (PCIDevice *)kid->child;
- if (dev->devfn == devfn) {
- return dev;
- }
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ PCIDevice *dev = (PCIDevice *)kid->child;
+ if (dev->devfn == devfn) {
+ return dev;
}
}
@@ -199,6 +226,191 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
finish_write_pci_config(spapr, 0, addr, size, val, rets);
}
+/*
+ * Find an entry with config_addr or returns the empty one if not found AND
+ * alloc_new is set.
+ * At the moment the msi_table entries are never released so there is
+ * no point to look till the end of the list if we need to find the free entry.
+ */
+static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
+ bool alloc_new)
+{
+ int i;
+
+ for (i = 0; i < SPAPR_MSIX_MAX_DEVS; ++i) {
+ if (!phb->msi_table[i].nvec) {
+ break;
+ }
+ if (phb->msi_table[i].config_addr == config_addr) {
+ return i;
+ }
+ }
+ if ((i < SPAPR_MSIX_MAX_DEVS) && alloc_new) {
+ trace_spapr_pci_msi("Allocating new MSI config", i, config_addr);
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+ * Set MSI/MSIX message data.
+ * This is required for msi_notify()/msix_notify() which
+ * will write at the addresses via spapr_msi_write().
+ */
+static void spapr_msi_setmsg(PCIDevice *pdev, target_phys_addr_t addr,
+ bool msix, unsigned req_num)
+{
+ unsigned i;
+ MSIMessage msg = { .address = addr, .data = 0 };
+
+ if (!msix) {
+ msi_set_message(pdev, msg);
+ trace_spapr_pci_msi_setup(pdev->name, 0, msg.address);
+ return;
+ }
+
+ for (i = 0; i < req_num; ++i) {
+ msg.address = addr | (i << 2);
+ msix_set_message(pdev, i, msg);
+ trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
+ }
+}
+
+static void rtas_ibm_change_msi(sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args, uint32_t nret,
+ target_ulong rets)
+{
+ uint32_t config_addr = rtas_ld(args, 0);
+ uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+ unsigned int func = rtas_ld(args, 3);
+ unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
+ unsigned int seq_num = rtas_ld(args, 5);
+ unsigned int ret_intr_type;
+ int ndev, irq;
+ sPAPRPHBState *phb = NULL;
+ PCIDevice *pdev = NULL;
+
+ switch (func) {
+ case RTAS_CHANGE_MSI_FN:
+ case RTAS_CHANGE_FN:
+ ret_intr_type = RTAS_TYPE_MSI;
+ break;
+ case RTAS_CHANGE_MSIX_FN:
+ ret_intr_type = RTAS_TYPE_MSIX;
+ break;
+ default:
+ fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func);
+ rtas_st(rets, 0, -3); /* Parameter error */
+ return;
+ }
+
+ /* Fins sPAPRPHBState */
+ phb = find_phb(spapr, buid);
+ if (phb) {
+ pdev = find_dev(spapr, buid, config_addr);
+ }
+ if (!phb || !pdev) {
+ rtas_st(rets, 0, -3); /* Parameter error */
+ return;
+ }
+
+ /* Releasing MSIs */
+ if (!req_num) {
+ ndev = spapr_msicfg_find(phb, config_addr, false);
+ if (ndev < 0) {
+ trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+ trace_spapr_pci_msi("Released MSIs", ndev, config_addr);
+ rtas_st(rets, 0, 0);
+ rtas_st(rets, 1, 0);
+ return;
+ }
+
+ /* Enabling MSI */
+
+ /* Find a device number in the map to add or reuse the existing one */
+ ndev = spapr_msicfg_find(phb, config_addr, true);
+ if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
+ fprintf(stderr, "No free entry for a new MSI device\n");
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+ trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
+
+ /* Check if there is an old config and MSI number has not changed */
+ if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
+ /* Unexpected behaviour */
+ fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev);
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+
+ /* There is no cached config, allocate MSIs */
+ if (!phb->msi_table[ndev].nvec) {
+ irq = spapr_allocate_irq_block(req_num, XICS_MSI);
+ if (irq < 0) {
+ fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+ phb->msi_table[ndev].irq = irq;
+ phb->msi_table[ndev].nvec = req_num;
+ phb->msi_table[ndev].config_addr = config_addr;
+ }
+
+ /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
+ spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
+ ret_intr_type == RTAS_TYPE_MSIX, req_num);
+
+ rtas_st(rets, 0, 0);
+ rtas_st(rets, 1, req_num);
+ rtas_st(rets, 2, ++seq_num);
+ rtas_st(rets, 3, ret_intr_type);
+
+ trace_spapr_pci_rtas_ibm_change_msi(func, req_num);
+}
+
+static void rtas_ibm_query_interrupt_source_number(sPAPREnvironment *spapr,
+ uint32_t token,
+ uint32_t nargs,
+ target_ulong args,
+ uint32_t nret,
+ target_ulong rets)
+{
+ uint32_t config_addr = rtas_ld(args, 0);
+ uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+ unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
+ int ndev;
+ sPAPRPHBState *phb = NULL;
+
+ /* Fins sPAPRPHBState */
+ phb = find_phb(spapr, buid);
+ if (!phb) {
+ rtas_st(rets, 0, -3); /* Parameter error */
+ return;
+ }
+
+ /* Find device descriptor and start IRQ */
+ ndev = spapr_msicfg_find(phb, config_addr, false);
+ if (ndev < 0) {
+ trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
+ rtas_st(rets, 0, -1); /* Hardware error */
+ return;
+ }
+
+ intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num;
+ trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
+ intr_src_num);
+
+ rtas_st(rets, 0, 0);
+ rtas_st(rets, 1, intr_src_num);
+ rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
+}
+
static int pci_spapr_swizzle(int slot, int pin)
{
return (slot + pin) % PCI_NUM_PINS;
@@ -223,7 +435,8 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
*/
sPAPRPHBState *phb = opaque;
- qemu_set_irq(phb->lsi_table[irq_num].qirq, level);
+ trace_spapr_pci_lsi_set(phb->busname, irq_num, phb->lsi_table[irq_num].irq);
+ qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
}
static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr,
@@ -264,6 +477,33 @@ static const MemoryRegionOps spapr_io_ops = {
};
/*
+ * MSI/MSIX memory region implementation.
+ * The handler handles both MSI and MSIX.
+ * For MSI-X, the vector number is encoded as a part of the address,
+ * data is set to 0.
+ * For MSI, the vector number is encoded in least bits in data.
+ */
+static void spapr_msi_write(void *opaque, target_phys_addr_t addr,
+ uint64_t data, unsigned size)
+{
+ sPAPRPHBState *phb = opaque;
+ int ndev = addr >> 16;
+ int vec = ((addr & 0xFFFF) >> 2) | data;
+ uint32_t irq = phb->msi_table[ndev].irq + vec;
+
+ trace_spapr_pci_msi_write(addr, data, irq);
+
+ qemu_irq_pulse(xics_get_qirq(spapr->icp, irq));
+}
+
+static const MemoryRegionOps spapr_msi_ops = {
+ /* There is no .read as the read result is undefined by PCI spec */
+ .read = NULL,
+ .write = spapr_msi_write,
+ .endianness = DEVICE_LITTLE_ENDIAN
+};
+
+/*
* PHB PCI device
*/
static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
@@ -276,24 +516,24 @@ static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
static int spapr_phb_init(SysBusDevice *s)
{
- sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s);
+ sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
char *namebuf;
int i;
PCIBus *bus;
- uint32_t liobn;
- phb->dtbusname = g_strdup_printf("pci@%" PRIx64, phb->buid);
- namebuf = alloca(strlen(phb->dtbusname) + 32);
+ sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
+ namebuf = alloca(strlen(sphb->dtbusname) + 32);
/* Initialize memory regions */
- sprintf(namebuf, "%s.mmio", phb->dtbusname);
- memory_region_init(&phb->memspace, namebuf, INT64_MAX);
+ sprintf(namebuf, "%s.mmio", sphb->dtbusname);
+ memory_region_init(&sphb->memspace, namebuf, INT64_MAX);
- sprintf(namebuf, "%s.mmio-alias", phb->dtbusname);
- memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace,
- SPAPR_PCI_MEM_WIN_BUS_OFFSET, phb->mem_win_size);
- memory_region_add_subregion(get_system_memory(), phb->mem_win_addr,
- &phb->memwindow);
+ sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname);
+ memory_region_init_alias(&sphb->memwindow, namebuf, &sphb->memspace,
+ SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size);
+ memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
+ &sphb->memwindow);
/* On ppc, we only have MMIO no specific IO space from the CPU
* perspective. In theory we ought to be able to embed the PCI IO
@@ -303,42 +543,53 @@ static int spapr_phb_init(SysBusDevice *s)
* system io address space. This hack to bounce things via
* system_io works around the problem until all the users of
* old_portion are updated */
- sprintf(namebuf, "%s.io", phb->dtbusname);
- memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
+ sprintf(namebuf, "%s.io", sphb->dtbusname);
+ memory_region_init(&sphb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
/* FIXME: fix to support multiple PHBs */
- memory_region_add_subregion(get_system_io(), 0, &phb->iospace);
+ memory_region_add_subregion(get_system_io(), 0, &sphb->iospace);
- sprintf(namebuf, "%s.io-alias", phb->dtbusname);
- memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb,
+ sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
+ memory_region_init_io(&sphb->iowindow, &spapr_io_ops, sphb,
namebuf, SPAPR_PCI_IO_WIN_SIZE);
- memory_region_add_subregion(get_system_memory(), phb->io_win_addr,
- &phb->iowindow);
+ memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
+ &sphb->iowindow);
+
+ /* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
+ * we need to allocate some memory to catch those writes coming
+ * from msi_notify()/msix_notify() */
+ if (msi_supported) {
+ sprintf(namebuf, "%s.msi", sphb->dtbusname);
+ memory_region_init_io(&sphb->msiwindow, &spapr_msi_ops, sphb,
+ namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
+ memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr,
+ &sphb->msiwindow);
+ }
- bus = pci_register_bus(&phb->busdev.qdev,
- phb->busname ? phb->busname : phb->dtbusname,
- pci_spapr_set_irq, pci_spapr_map_irq, phb,
- &phb->memspace, &phb->iospace,
+ bus = pci_register_bus(DEVICE(s),
+ sphb->busname ? sphb->busname : sphb->dtbusname,
+ pci_spapr_set_irq, pci_spapr_map_irq, sphb,
+ &sphb->memspace, &sphb->iospace,
PCI_DEVFN(0, 0), PCI_NUM_PINS);
- phb->host_state.bus = bus;
+ phb->bus = bus;
- liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16);
- phb->dma = spapr_tce_new_dma_context(liobn, 0x40000000);
- pci_setup_iommu(bus, spapr_pci_dma_context_fn, phb);
+ sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16);
+ sphb->dma_window_start = 0;
+ sphb->dma_window_size = 0x40000000;
+ sphb->dma = spapr_tce_new_dma_context(sphb->dma_liobn, sphb->dma_window_size);
+ pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb);
- QLIST_INSERT_HEAD(&spapr->phbs, phb, list);
+ QLIST_INSERT_HEAD(&spapr->phbs, sphb, list);
/* Initialize the LSI table */
for (i = 0; i < PCI_NUM_PINS; i++) {
- qemu_irq qirq;
- uint32_t num;
+ uint32_t irq;
- qirq = spapr_allocate_lsi(0, &num);
- if (!qirq) {
+ irq = spapr_allocate_lsi(0);
+ if (!irq) {
return -1;
}
- phb->lsi_table[i].dt_irq = num;
- phb->lsi_table[i].qirq = qirq;
+ sphb->lsi_table[i].irq = irq;
}
return 0;
@@ -351,6 +602,7 @@ static Property spapr_phb_properties[] = {
DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000),
DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0),
DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000),
+ DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -361,16 +613,11 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
sdc->init = spapr_phb_init;
dc->props = spapr_phb_properties;
-
- spapr_rtas_register("read-pci-config", rtas_read_pci_config);
- spapr_rtas_register("write-pci-config", rtas_write_pci_config);
- spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
- spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
}
-static TypeInfo spapr_phb_info = {
- .name = "spapr-pci-host-bridge",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo spapr_phb_info = {
+ .name = TYPE_SPAPR_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(sPAPRPHBState),
.class_init = spapr_phb_class_init,
};
@@ -378,11 +625,11 @@ static TypeInfo spapr_phb_info = {
void spapr_create_phb(sPAPREnvironment *spapr,
const char *busname, uint64_t buid,
uint64_t mem_win_addr, uint64_t mem_win_size,
- uint64_t io_win_addr)
+ uint64_t io_win_addr, uint64_t msi_win_addr)
{
DeviceState *dev;
- dev = qdev_create(NULL, spapr_phb_info.name);
+ dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
if (busname) {
qdev_prop_set_string(dev, "busname", g_strdup(busname));
@@ -391,6 +638,7 @@ void spapr_create_phb(sPAPREnvironment *spapr,
qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr);
qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size);
qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr);
+ qdev_prop_set_uint64(dev, "msi_win_addr", msi_win_addr);
qdev_init_nofail(dev);
}
@@ -406,9 +654,9 @@ void spapr_create_phb(sPAPREnvironment *spapr,
#define b_fff(x) b_x((x), 8, 3) /* function number */
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
-int spapr_populate_pci_devices(sPAPRPHBState *phb,
- uint32_t xics_phandle,
- void *fdt)
+int spapr_populate_pci_dt(sPAPRPHBState *phb,
+ uint32_t xics_phandle,
+ void *fdt)
{
int bus_off, i, j;
char nodename[256];
@@ -477,7 +725,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
irqmap[2] = 0;
irqmap[3] = cpu_to_be32(j+1);
irqmap[4] = cpu_to_be32(xics_phandle);
- irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].dt_irq);
+ irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq);
irqmap[6] = cpu_to_be32(0x8);
}
}
@@ -485,13 +733,29 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
sizeof(interrupt_map)));
- spapr_dma_dt(fdt, bus_off, "ibm,dma-window", phb->dma);
+ spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
+ phb->dma_liobn, phb->dma_window_start,
+ phb->dma_window_size);
return 0;
}
-static void register_types(void)
+void spapr_pci_rtas_init(void)
+{
+ spapr_rtas_register("read-pci-config", rtas_read_pci_config);
+ spapr_rtas_register("write-pci-config", rtas_write_pci_config);
+ spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
+ spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+ if (msi_supported) {
+ spapr_rtas_register("ibm,query-interrupt-source-number",
+ rtas_ibm_query_interrupt_source_number);
+ spapr_rtas_register("ibm,change-msi", rtas_ibm_change_msi);
+ }
+}
+
+static void spapr_pci_register_types(void)
{
type_register_static(&spapr_phb_info);
}
-type_init(register_types)
+
+type_init(spapr_pci_register_types)
diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h
index d9e46e2..670dc62 100644
--- a/hw/spapr_pci.h
+++ b/hw/spapr_pci.h
@@ -27,9 +27,15 @@
#include "hw/pci_host.h"
#include "hw/xics.h"
+#define SPAPR_MSIX_MAX_DEVS 32
+
+#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge"
+
+#define SPAPR_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
+
typedef struct sPAPRPHBState {
- SysBusDevice busdev;
- PCIHostState host_state;
+ PCIHostState parent_obj;
uint64_t buid;
char *busname;
@@ -37,27 +43,44 @@ typedef struct sPAPRPHBState {
MemoryRegion memspace, iospace;
target_phys_addr_t mem_win_addr, mem_win_size, io_win_addr, io_win_size;
- MemoryRegion memwindow, iowindow;
+ target_phys_addr_t msi_win_addr;
+ MemoryRegion memwindow, iowindow, msiwindow;
+
+ uint32_t dma_liobn;
+ uint64_t dma_window_start;
+ uint64_t dma_window_size;
DMAContext *dma;
struct {
- uint32_t dt_irq;
- qemu_irq qirq;
+ uint32_t irq;
} lsi_table[PCI_NUM_PINS];
+ struct {
+ uint32_t config_addr;
+ uint32_t irq;
+ int nvec;
+ } msi_table[SPAPR_MSIX_MAX_DEVS];
+
QLIST_ENTRY(sPAPRPHBState) list;
} sPAPRPHBState;
+static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
+{
+ return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
+}
+
#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
void spapr_create_phb(sPAPREnvironment *spapr,
const char *busname, uint64_t buid,
uint64_t mem_win_addr, uint64_t mem_win_size,
- uint64_t io_win_addr);
+ uint64_t io_win_addr, uint64_t msi_win_addr);
+
+int spapr_populate_pci_dt(sPAPRPHBState *phb,
+ uint32_t xics_phandle,
+ void *fdt);
-int spapr_populate_pci_devices(sPAPRPHBState *phb,
- uint32_t xics_phandle,
- void *fdt);
+void spapr_pci_rtas_init(void);
#endif /* __HW_SPAPR_PCI_H__ */
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 05b5503..7ca4452 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -49,7 +49,7 @@
#endif
static Property spapr_vio_props[] = {
- DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
+ DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \
DEFINE_PROP_END_OF_LIST(),
};
@@ -132,8 +132,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
}
- if (dev->qirq) {
- uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
+ if (dev->irq) {
+ uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
sizeof(ints_prop));
@@ -142,7 +142,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
}
- ret = spapr_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
+ ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
if (ret < 0) {
return ret;
}
@@ -306,7 +306,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
if (dev->signal_state & 1) {
- qemu_irq_pulse(dev->qirq);
+ qemu_irq_pulse(spapr_vio_qirq(dev));
}
return 0;
@@ -459,8 +459,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
dev->qdev.id = id;
}
- dev->qirq = spapr_allocate_msi(dev->vio_irq_num, &dev->vio_irq_num);
- if (!dev->qirq) {
+ dev->irq = spapr_allocate_msi(dev->irq);
+ if (!dev->irq) {
return -1;
}
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 6f9a498..ea6aa43 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -61,8 +61,7 @@ struct VIOsPAPRDevice {
DeviceState qdev;
uint32_t reg;
uint32_t flags;
- qemu_irq qirq;
- uint32_t vio_irq_num;
+ uint32_t irq;
target_ulong signal_state;
VIOsPAPR_CRQ crq;
DMAContext *dma;
@@ -85,6 +84,11 @@ extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev)
+{
+ return xics_get_qirq(spapr->icp, dev->irq);
+}
+
static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
uint32_t size, DMADirection dir)
{
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 99e52cc..5da17a3 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -26,7 +26,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
if ((dev->in == dev->out) && size) {
/* toggle line to simulate edge interrupt */
- qemu_irq_pulse(dev->sdev.qirq);
+ qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
}
for (i = 0; i < size; i++) {
assert((dev->in - dev->out) < VTERM_BUFSIZE);
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index b0b2e94..b101c51 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -19,7 +19,9 @@
#define DPRINTF(fmt, ...) \
do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+do { \
+ fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); abort(); \
+} while (0)
#else
#define DPRINTF(fmt, ...) do {} while(0)
#define BADF(fmt, ...) \
diff --git a/hw/stream.c b/hw/stream.c
new file mode 100644
index 0000000..be57e8b
--- /dev/null
+++ b/hw/stream.c
@@ -0,0 +1,23 @@
+#include "stream.h"
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
+{
+ StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink);
+
+ k->push(sink, buf, len, app);
+}
+
+static TypeInfo stream_slave_info = {
+ .name = TYPE_STREAM_SLAVE,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(StreamSlaveClass),
+};
+
+
+static void stream_slave_register_types(void)
+{
+ type_register_static(&stream_slave_info);
+}
+
+type_init(stream_slave_register_types)
diff --git a/hw/stream.h b/hw/stream.h
new file mode 100644
index 0000000..21123a9
--- /dev/null
+++ b/hw/stream.h
@@ -0,0 +1,31 @@
+#ifndef STREAM_H
+#define STREAM_H 1
+
+#include "qemu-common.h"
+#include "qemu/object.h"
+
+/* stream slave. Used until qdev provides a generic way. */
+#define TYPE_STREAM_SLAVE "stream-slave"
+
+#define STREAM_SLAVE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(StreamSlaveClass, (klass), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(StreamSlaveClass, (obj), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE(obj) \
+ INTERFACE_CHECK(StreamSlave, (obj), TYPE_STREAM_SLAVE)
+
+typedef struct StreamSlave {
+ Object Parent;
+} StreamSlave;
+
+typedef struct StreamSlaveClass {
+ InterfaceClass parent;
+
+ void (*push)(StreamSlave *obj, unsigned char *buf, size_t len,
+ uint32_t *app);
+} StreamSlaveClass;
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app);
+
+#endif /* STREAM_H */
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 137a7c6..07cd042 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -39,6 +39,7 @@
#include "elf.h"
#include "blockdev.h"
#include "exec-memory.h"
+#include "vga-pci.h"
//#define DEBUG_IRQ
//#define DEBUG_EBUS
diff --git a/hw/unicore32/Makefile.objs b/hw/unicore32/Makefile.objs
new file mode 100644
index 0000000..0725ce3
--- /dev/null
+++ b/hw/unicore32/Makefile.objs
@@ -0,0 +1,6 @@
+# For UniCore32 machines and boards
+
+# PKUnity-v3 SoC and board information
+obj-${CONFIG_PUV3} += puv3.o
+
+obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 409bcd4..d1cc680 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -38,8 +38,23 @@
static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
+#define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost"
+#define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost"
+#define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost"
+#define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost"
+
+#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
+#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
+#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
+#define U3_AGP_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
+
typedef struct UNINState {
- PCIHostState host_state;
+ PCIHostState parent_obj;
+
MemoryRegion pci_mmio;
MemoryRegion pci_hole;
} UNINState;
@@ -100,10 +115,11 @@ static void unin_data_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned len)
{
UNINState *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
addr, len, val);
- pci_data_write(s->host_state.bus,
- unin_get_config_reg(s->host_state.config_reg, addr),
+ pci_data_write(phb->bus,
+ unin_get_config_reg(phb->config_reg, addr),
val, len);
}
@@ -111,10 +127,11 @@ static uint64_t unin_data_read(void *opaque, target_phys_addr_t addr,
unsigned len)
{
UNINState *s = opaque;
+ PCIHostState *phb = PCI_HOST_BRIDGE(s);
uint32_t val;
- val = pci_data_read(s->host_state.bus,
- unin_get_config_reg(s->host_state.config_reg, addr),
+ val = pci_data_read(phb->bus,
+ unin_get_config_reg(phb->config_reg, addr),
len);
UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
addr, len, val);
@@ -130,19 +147,17 @@ static const MemoryRegionOps unin_data_ops = {
static int pci_unin_main_init_device(SysBusDevice *dev)
{
PCIHostState *h;
- UNINState *s;
/* Use values found on a real PowerMac */
/* Uninorth main bus */
- h = FROM_SYSBUS(PCIHostState, dev);
- s = DO_UPCAST(UNINState, host_state, h);
+ h = PCI_HOST_BRIDGE(dev);
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
"pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ sysbus_init_mmio(dev, &h->conf_mem);
+ sysbus_init_mmio(dev, &h->data_mem);
return 0;
}
@@ -151,18 +166,16 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
static int pci_u3_agp_init_device(SysBusDevice *dev)
{
PCIHostState *h;
- UNINState *s;
/* Uninorth U3 AGP bus */
- h = FROM_SYSBUS(PCIHostState, dev);
- s = DO_UPCAST(UNINState, host_state, h);
+ h = PCI_HOST_BRIDGE(dev);
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
"pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ sysbus_init_mmio(dev, &h->conf_mem);
+ sysbus_init_mmio(dev, &h->data_mem);
return 0;
}
@@ -170,36 +183,32 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
static int pci_unin_agp_init_device(SysBusDevice *dev)
{
PCIHostState *h;
- UNINState *s;
/* Uninorth AGP bus */
- h = FROM_SYSBUS(PCIHostState, dev);
- s = DO_UPCAST(UNINState, host_state, h);
-
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
- &s->host_state, "pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ h = PCI_HOST_BRIDGE(dev);
+
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
+ dev, "pci-conf-data", 0x1000);
+ sysbus_init_mmio(dev, &h->conf_mem);
+ sysbus_init_mmio(dev, &h->data_mem);
return 0;
}
static int pci_unin_internal_init_device(SysBusDevice *dev)
{
PCIHostState *h;
- UNINState *s;
/* Uninorth internal bus */
- h = FROM_SYSBUS(PCIHostState, dev);
- s = DO_UPCAST(UNINState, host_state, h);
-
- memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
- &s->host_state, "pci-conf-idx", 0x1000);
- memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
- &s->host_state, "pci-conf-data", 0x1000);
- sysbus_init_mmio(dev, &s->host_state.conf_mem);
- sysbus_init_mmio(dev, &s->host_state.data_mem);
+ h = PCI_HOST_BRIDGE(dev);
+
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+ dev, "pci-conf-idx", 0x1000);
+ memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
+ dev, "pci-conf-data", 0x1000);
+ sysbus_init_mmio(dev, &h->conf_mem);
+ sysbus_init_mmio(dev, &h->data_mem);
return 0;
}
@@ -214,26 +223,26 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
/* Use values found on a real PowerMac */
/* Uninorth main bus */
- dev = qdev_create(NULL, "uni-north-pci-pcihost");
+ dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- h = FROM_SYSBUS(PCIHostState, s);
- d = DO_UPCAST(UNINState, host_state, h);
+ s = SYS_BUS_DEVICE(dev);
+ h = PCI_HOST_BRIDGE(s);
+ d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
0x80000000ULL, 0x70000000ULL);
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(dev, "pci",
- pci_unin_set_irq, pci_unin_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- PCI_DEVFN(11, 0), 4);
+ h->bus = pci_register_bus(dev, "pci",
+ pci_unin_set_irq, pci_unin_map_irq,
+ pic,
+ &d->pci_mmio,
+ address_space_io,
+ PCI_DEVFN(11, 0), 4);
#if 0
- pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north");
+ pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
#endif
sysbus_mmio_map(s, 0, 0xf2800000);
@@ -242,30 +251,30 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
/* DEC 21154 bridge */
#if 0
/* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
- pci_create_simple(d->host_state.bus, PCI_DEVFN(12, 0), "dec-21154");
+ pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154");
#endif
/* Uninorth AGP bus */
- pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp");
- dev = qdev_create(NULL, "uni-north-agp-pcihost");
+ pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp");
+ dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
+ s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, 0xf0800000);
sysbus_mmio_map(s, 1, 0xf0c00000);
/* Uninorth internal bus */
#if 0
/* XXX: not needed for now */
- pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0),
+ pci_create_simple(h->bus, PCI_DEVFN(14, 0),
"uni-north-internal-pci");
- dev = qdev_create(NULL, "uni-north-internal-pci-pcihost");
+ dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
+ s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, 0xf4800000);
sysbus_mmio_map(s, 1, 0xf4c00000);
#endif
- return d->host_state.bus;
+ return h->bus;
}
PCIBus *pci_pmac_u3_init(qemu_irq *pic,
@@ -279,11 +288,11 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
/* Uninorth AGP bus */
- dev = qdev_create(NULL, "u3-agp-pcihost");
+ dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE);
qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- h = FROM_SYSBUS(PCIHostState, s);
- d = DO_UPCAST(UNINState, host_state, h);
+ s = SYS_BUS_DEVICE(dev);
+ h = PCI_HOST_BRIDGE(dev);
+ d = U3_AGP_HOST_BRIDGE(dev);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
@@ -291,19 +300,19 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(dev, "pci",
- pci_unin_set_irq, pci_unin_map_irq,
- pic,
- &d->pci_mmio,
- address_space_io,
- PCI_DEVFN(11, 0), 4);
+ h->bus = pci_register_bus(dev, "pci",
+ pci_unin_set_irq, pci_unin_map_irq,
+ pic,
+ &d->pci_mmio,
+ address_space_io,
+ PCI_DEVFN(11, 0), 4);
sysbus_mmio_map(s, 0, 0xf0800000);
sysbus_mmio_map(s, 1, 0xf0c00000);
- pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp");
+ pci_create_simple(h->bus, 11 << 3, "u3-agp");
- return d->host_state.bus;
+ return h->bus;
}
static int unin_main_pci_host_init(PCIDevice *d)
@@ -350,7 +359,7 @@ static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo unin_main_pci_host_info = {
+static const TypeInfo unin_main_pci_host_info = {
.name = "uni-north-pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -368,7 +377,7 @@ static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo u3_agp_pci_host_info = {
+static const TypeInfo u3_agp_pci_host_info = {
.name = "u3-agp",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -386,7 +395,7 @@ static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo unin_agp_pci_host_info = {
+static const TypeInfo unin_agp_pci_host_info = {
.name = "uni-north-agp",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -404,7 +413,7 @@ static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
-static TypeInfo unin_internal_pci_host_info = {
+static const TypeInfo unin_internal_pci_host_info = {
.name = "uni-north-internal-pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
@@ -418,9 +427,9 @@ static void pci_unin_main_class_init(ObjectClass *klass, void *data)
sbc->init = pci_unin_main_init_device;
}
-static TypeInfo pci_unin_main_info = {
- .name = "uni-north-pci-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_unin_main_info = {
+ .name = TYPE_UNI_NORTH_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(UNINState),
.class_init = pci_unin_main_class_init,
};
@@ -432,9 +441,9 @@ static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
sbc->init = pci_u3_agp_init_device;
}
-static TypeInfo pci_u3_agp_info = {
- .name = "u3-agp-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_u3_agp_info = {
+ .name = TYPE_U3_AGP_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(UNINState),
.class_init = pci_u3_agp_class_init,
};
@@ -446,9 +455,9 @@ static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
sbc->init = pci_unin_agp_init_device;
}
-static TypeInfo pci_unin_agp_info = {
- .name = "uni-north-agp-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_unin_agp_info = {
+ .name = TYPE_UNI_NORTH_AGP_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(UNINState),
.class_init = pci_unin_agp_class_init,
};
@@ -460,9 +469,9 @@ static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
sbc->init = pci_unin_internal_init_device;
}
-static TypeInfo pci_unin_internal_info = {
- .name = "uni-north-internal-pci-pcihost",
- .parent = TYPE_SYS_BUS_DEVICE,
+static const TypeInfo pci_unin_internal_info = {
+ .name = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(UNINState),
.class_init = pci_unin_internal_class_init,
};
diff --git a/hw/usb.h b/hw/usb.h
index 432ccae..b8fceec 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -179,6 +179,7 @@ struct USBEndpoint {
uint8_t ifnum;
int max_packet_size;
bool pipeline;
+ bool halted;
USBDevice *dev;
QTAILQ_HEAD(, USBPacket) queue;
};
@@ -331,6 +332,7 @@ typedef enum USBPacketState {
struct USBPacket {
/* Data fields for use by the driver. */
int pid;
+ uint64_t id;
USBEndpoint *ep;
QEMUIOVector iov;
uint64_t parameter; /* control transfers */
@@ -343,7 +345,7 @@ struct USBPacket {
void usb_packet_init(USBPacket *p);
void usb_packet_set_state(USBPacket *p, USBPacketState state);
void usb_packet_check_state(USBPacket *p, USBPacketState expected);
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep);
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id);
void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl);
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 01a7622..2da38e7 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -107,6 +107,7 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
}
usb_packet_copy(p, s->setup_buf, p->iov.size);
+ p->result = 0;
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
s->setup_index = 0;
@@ -381,12 +382,23 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
usb_packet_check_state(p, USB_PACKET_SETUP);
assert(p->ep != NULL);
+ /* Submitting a new packet clears halt */
+ if (p->ep->halted) {
+ assert(QTAILQ_EMPTY(&p->ep->queue));
+ p->ep->halted = false;
+ }
+
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) {
ret = usb_process_one(p);
if (ret == USB_RET_ASYNC) {
usb_packet_set_state(p, USB_PACKET_ASYNC);
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
} else {
+ /*
+ * When pipelining is enabled usb-devices must always return async,
+ * otherwise packets can complete out of order!
+ */
+ assert(!p->ep->pipeline);
p->result = ret;
usb_packet_set_state(p, USB_PACKET_COMPLETE);
}
@@ -398,6 +410,20 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
return ret;
}
+static void __usb_packet_complete(USBDevice *dev, USBPacket *p)
+{
+ USBEndpoint *ep = p->ep;
+
+ assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK);
+
+ if (p->result < 0) {
+ ep->halted = true;
+ }
+ usb_packet_set_state(p, USB_PACKET_COMPLETE);
+ QTAILQ_REMOVE(&ep->queue, p, queue);
+ dev->port->ops->complete(dev->port, p);
+}
+
/* Notify the controller that an async packet is complete. This should only
be called for packets previously deferred by returning USB_RET_ASYNC from
handle_packet. */
@@ -408,11 +434,9 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
usb_packet_check_state(p, USB_PACKET_ASYNC);
assert(QTAILQ_FIRST(&ep->queue) == p);
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
- QTAILQ_REMOVE(&ep->queue, p, queue);
- dev->port->ops->complete(dev->port, p);
+ __usb_packet_complete(dev, p);
- while (!QTAILQ_EMPTY(&ep->queue)) {
+ while (!ep->halted && !QTAILQ_EMPTY(&ep->queue)) {
p = QTAILQ_FIRST(&ep->queue);
if (p->state == USB_PACKET_ASYNC) {
break;
@@ -424,9 +448,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
break;
}
p->result = ret;
- usb_packet_set_state(p, USB_PACKET_COMPLETE);
- QTAILQ_REMOVE(&ep->queue, p, queue);
- dev->port->ops->complete(dev->port, p);
+ __usb_packet_complete(ep->dev, p);
}
}
@@ -498,10 +520,11 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state)
p->state = state;
}
-void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep)
+void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id)
{
assert(!usb_packet_is_inflight(p));
assert(p->iov.iov != NULL);
+ p->id = id;
p->pid = pid;
p->ep = ep;
p->result = 0;
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index 9b02ff4..5a0057a 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -223,7 +223,7 @@ static const USBDescDevice desc_device_high = {
static const USBDesc desc = {
.id = {
.idVendor = 0x46f4, /* CRC16() of "QEMU" */
- .idProduct = 0x0002,
+ .idProduct = 0x0003,
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
@@ -424,6 +424,7 @@ static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv)
}
QTAILQ_REMOVE(&uas->requests, req, next);
g_free(req);
+ usb_uas_start_next_transfer(uas);
}
static UASRequest *usb_uas_find_request(UASDevice *uas, uint16_t tag)
@@ -456,7 +457,6 @@ static void usb_uas_scsi_command_complete(SCSIRequest *r,
uint32_t status, size_t resid)
{
UASRequest *req = r->hba_private;
- UASDevice *uas = req->uas;
trace_usb_uas_scsi_complete(req->uas->dev.addr, req->tag, status, resid);
req->complete = true;
@@ -465,7 +465,6 @@ static void usb_uas_scsi_command_complete(SCSIRequest *r,
}
usb_uas_queue_sense(req, status);
scsi_req_unref(req->req);
- usb_uas_start_next_transfer(uas);
}
static void usb_uas_scsi_request_cancelled(SCSIRequest *r)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index b043e7c..017342b 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -575,7 +575,12 @@ static inline void ehci_update_irq(EHCIState *s)
/* flag interrupt condition */
static inline void ehci_raise_irq(EHCIState *s, int intr)
{
- s->usbsts_pending |= intr;
+ if (intr & (USBSTS_PCD | USBSTS_FLR | USBSTS_HSE)) {
+ s->usbsts |= intr;
+ ehci_update_irq(s);
+ } else {
+ s->usbsts_pending |= intr;
+ }
}
/*
@@ -761,15 +766,27 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
return q;
}
+static void ehci_cancel_queue(EHCIQueue *q)
+{
+ EHCIPacket *p;
+
+ p = QTAILQ_FIRST(&q->packets);
+ if (p == NULL) {
+ return;
+ }
+
+ trace_usb_ehci_queue_action(q, "cancel");
+ do {
+ ehci_free_packet(p);
+ } while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
+}
+
static void ehci_free_queue(EHCIQueue *q)
{
EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
- EHCIPacket *p;
trace_usb_ehci_queue_action(q, "free");
- while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
- ehci_free_packet(p);
- }
+ ehci_cancel_queue(q);
QTAILQ_REMOVE(head, q, next);
g_free(q);
}
@@ -1182,22 +1199,32 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
break;
}
+ /* not supporting dynamic frame list size at the moment */
+ if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
+ fprintf(stderr, "attempt to set frame list size -- value %d\n",
+ val & USBCMD_FLS);
+ val &= ~USBCMD_FLS;
+ }
+
+ if (val & USBCMD_IAAD) {
+ /*
+ * Process IAAD immediately, otherwise the Linux IAAD watchdog may
+ * trigger and re-use a qh without us seeing the unlink.
+ */
+ s->async_stepdown = 0;
+ qemu_bh_schedule(s->async_bh);
+ }
+
if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) !=
((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) {
if (s->pstate == EST_INACTIVE) {
SET_LAST_RUN_CLOCK(s);
}
+ s->usbcmd = val; /* Set usbcmd for ehci_update_halt() */
ehci_update_halt(s);
s->async_stepdown = 0;
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
}
-
- /* not supporting dynamic frame list size at the moment */
- if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
- fprintf(stderr, "attempt to set frame list size -- value %d\n",
- val & USBCMD_FLS);
- val &= ~USBCMD_FLS;
- }
break;
case USBSTS:
@@ -1524,7 +1551,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
ep = usb_ep_get(p->queue->dev, p->pid, endp);
- usb_packet_setup(&p->packet, p->pid, ep);
+ usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
usb_packet_map(&p->packet, &p->sgl);
trace_usb_ehci_packet_action(p->queue, p, action);
@@ -1546,7 +1573,8 @@ static int ehci_execute(EHCIPacket *p, const char *action)
*/
static int ehci_process_itd(EHCIState *ehci,
- EHCIitd *itd)
+ EHCIitd *itd,
+ uint32_t addr)
{
USBDevice *dev;
USBEndpoint *ep;
@@ -1591,8 +1619,8 @@ static int ehci_process_itd(EHCIState *ehci,
dev = ehci_find_device(ehci, devaddr);
ep = usb_ep_get(dev, pid, endp);
- if (ep->type == USB_ENDPOINT_XFER_ISOC) {
- usb_packet_setup(&ehci->ipacket, pid, ep);
+ if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
+ usb_packet_setup(&ehci->ipacket, pid, ep, addr);
usb_packet_map(&ehci->ipacket, &ehci->isgl);
ret = usb_handle_packet(dev, &ehci->ipacket);
assert(ret != USB_RET_ASYNC);
@@ -1780,9 +1808,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
if (q->dev != NULL && q->dev->addr != devaddr) {
if (!QTAILQ_EMPTY(&q->packets)) {
/* should not happen (guest bug) */
- while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
- ehci_free_packet(p);
- }
+ ehci_cancel_queue(q);
}
q->dev = NULL;
}
@@ -1790,11 +1816,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
q->dev = ehci_find_device(q->ehci, devaddr);
}
- if (p && p->async == EHCI_ASYNC_INFLIGHT) {
- /* I/O still in progress -- skip queue */
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
- goto out;
- }
if (p && p->async == EHCI_ASYNC_FINISHED) {
/* I/O finished -- continue processing queue */
trace_usb_ehci_packet_action(p->queue, p, "complete");
@@ -1856,7 +1877,7 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
sizeof(EHCIitd) >> 2);
ehci_trace_itd(ehci, entry, &itd);
- if (ehci_process_itd(ehci, &itd) != 0) {
+ if (ehci_process_itd(ehci, &itd, entry) != 0) {
return -1;
}
@@ -1943,29 +1964,50 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
p = QTAILQ_FIRST(&q->packets);
- while (p != NULL && p->qtdaddr != q->qtdaddr) {
- /* should not happen (guest bug) */
- ehci_free_packet(p);
- p = QTAILQ_FIRST(&q->packets);
- }
if (p != NULL) {
- ehci_qh_do_overlay(q);
- ehci_flush_qh(q);
- if (p->async == EHCI_ASYNC_INFLIGHT) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
+ if (p->qtdaddr != q->qtdaddr ||
+ (!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) ||
+ (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
+ p->qtd.bufptr[0] != qtd.bufptr[0]) {
+ /* guest bug: guest updated active QH or qTD underneath us */
+ ehci_cancel_queue(q);
+ p = NULL;
} else {
+ p->qtd = qtd;
+ ehci_qh_do_overlay(q);
+ }
+ }
+
+ if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
+ if (p != NULL) {
+ /* transfer canceled by guest (clear active) */
+ ehci_cancel_queue(q);
+ p = NULL;
+ }
+ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
+ again = 1;
+ } else if (p != NULL) {
+ switch (p->async) {
+ case EHCI_ASYNC_NONE:
+ /* Previously nacked packet (likely interrupt ep) */
+ ehci_set_state(q->ehci, q->async, EST_EXECUTE);
+ break;
+ case EHCI_ASYNC_INFLIGHT:
+ /* Unfinyshed async handled packet, go horizontal */
+ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
+ break;
+ case EHCI_ASYNC_FINISHED:
+ /* Should never happen, as this case is caught by fetchqh */
ehci_set_state(q->ehci, q->async, EST_EXECUTING);
+ break;
}
again = 1;
- } else if (qtd.token & QTD_TOKEN_ACTIVE) {
+ } else {
p = ehci_alloc_packet(q);
p->qtdaddr = q->qtdaddr;
p->qtd = qtd;
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
again = 1;
- } else {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- again = 1;
}
return again;
@@ -2010,7 +2052,7 @@ static void ehci_fill_queue(EHCIPacket *p)
p->qtdaddr = qtdaddr;
p->qtd = qtd;
p->usb_status = ehci_execute(p, "queue");
- assert(p->usb_status = USB_RET_ASYNC);
+ assert(p->usb_status == USB_RET_ASYNC);
p->async = EHCI_ASYNC_INFLIGHT;
}
}
@@ -2069,19 +2111,11 @@ out:
static int ehci_state_executing(EHCIQueue *q)
{
EHCIPacket *p = QTAILQ_FIRST(&q->packets);
- int again = 0;
assert(p != NULL);
assert(p->qtdaddr == q->qtdaddr);
ehci_execute_complete(q);
- if (p->usb_status == USB_RET_ASYNC) {
- goto out;
- }
- if (p->usb_status == USB_RET_PROCERR) {
- again = -1;
- goto out;
- }
// 4.10.3
if (!q->async) {
@@ -2099,11 +2133,8 @@ static int ehci_state_executing(EHCIQueue *q)
ehci_set_state(q->ehci, q->async, EST_WRITEBACK);
}
- again = 1;
-
-out:
ehci_flush_qh(q);
- return again;
+ return 1;
}
@@ -2132,6 +2163,19 @@ static int ehci_state_writeback(EHCIQueue *q)
* bit is clear.
*/
if (q->qh.token & QTD_TOKEN_HALT) {
+ /*
+ * We should not do any further processing on a halted queue!
+ * This is esp. important for bulk endpoints with pipelining enabled
+ * (redirection to a real USB device), where we must cancel all the
+ * transfers after this one so that:
+ * 1) If they've completed already, they are not processed further
+ * causing more stalls, originating from the same failed transfer
+ * 2) If still in flight, they are cancelled before the guest does
+ * a clear stall, otherwise the guest and device can loose sync!
+ */
+ while ((p = QTAILQ_FIRST(&q->packets)) != NULL) {
+ ehci_free_packet(p);
+ }
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
again = 1;
} else {
@@ -2466,13 +2510,16 @@ static int usb_ehci_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_ehci = {
.name = "ehci",
- .version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 1,
.post_load = usb_ehci_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, EHCIState),
/* mmio registers */
VMSTATE_UINT32(usbcmd, EHCIState),
VMSTATE_UINT32(usbsts, EHCIState),
+ VMSTATE_UINT32_V(usbsts_pending, EHCIState, 2),
+ VMSTATE_UINT32_V(usbsts_frindex, EHCIState, 2),
VMSTATE_UINT32(usbintr, EHCIState),
VMSTATE_UINT32(frindex, EHCIState),
VMSTATE_UINT32(ctrldssegment, EHCIState),
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
index 0e860da..e77e0b2 100644
--- a/hw/usb/hcd-musb.c
+++ b/hw/usb/hcd-musb.c
@@ -627,7 +627,8 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
/* A wild guess on the FADDR semantics... */
dev = usb_find_device(&s->port, ep->faddr[idx]);
uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
- usb_packet_setup(&ep->packey[dir].p, pid, uep);
+ usb_packet_setup(&ep->packey[dir].p, pid, uep,
+ (dev->addr << 16) | (uep->nr << 8) | pid);
usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 844e7ed..c36184a 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -812,7 +812,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
} else {
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep);
+ usb_packet_setup(&ohci->usb_packet, pid, ep, addr);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret == USB_RET_ASYNC) {
@@ -1011,7 +1011,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep);
+ usb_packet_setup(&ohci->usb_packet, pid, ep, addr);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
ret = usb_handle_packet(dev, &ohci->usb_packet);
#ifdef DEBUG_PACKET
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 1ace2a4..b0db921 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -748,6 +748,22 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
return TD_RESULT_COMPLETE;
out:
+ /*
+ * We should not do any further processing on a queue with errors!
+ * This is esp. important for bulk endpoints with pipelining enabled
+ * (redirection to a real USB device), where we must cancel all the
+ * transfers after this one so that:
+ * 1) If they've completed already, they are not processed further
+ * causing more stalls, originating from the same failed transfer
+ * 2) If still in flight, they are cancelled before the guest does
+ * a clear stall, otherwise the guest and device can loose sync!
+ */
+ while (!QTAILQ_EMPTY(&async->queue->asyncs)) {
+ UHCIAsync *as = QTAILQ_FIRST(&async->queue->asyncs);
+ uhci_async_unlink(as);
+ uhci_async_cancel(as);
+ }
+
switch(ret) {
case USB_RET_STALL:
td->ctrl |= TD_CTRL_STALL;
@@ -843,14 +859,14 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
* for initial isochronous requests
*/
async->queue->valid = 32;
- async->isoc = td->ctrl & TD_CTRL_IOS;
+ async->isoc = td->ctrl & TD_CTRL_IOS;
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
- usb_packet_setup(&async->packet, pid, ep);
+ usb_packet_setup(&async->packet, pid, ep, addr);
qemu_sglist_add(&async->sgl, td->buffer, max_len);
usb_packet_map(&async->packet, &async->sgl);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 6c2ff02..3eb27fa 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -1392,7 +1392,7 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT;
ep = usb_ep_get(dev, dir, xfer->epid >> 1);
- usb_packet_setup(&xfer->packet, dir, ep);
+ usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr);
usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
xfer->packet.pid, dev->addr, ep->nr);
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index d55be87..8df9207 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -1045,6 +1045,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
/* Note request is (bRequestType << 8) | bRequest */
trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
+ assert(p->result == 0);
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 4fd5d9b..7a92034 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -162,7 +162,7 @@ static int vpb_sic_init(SysBusDevice *dev)
/* Board init. */
/* The AB and PB boards both use the same core, just with different
- peripherans and expansion busses. For now we emulate a subset of the
+ peripherals and expansion busses. For now we emulate a subset of the
PB peripherals and just change the board ID. */
static struct arm_boot_info versatile_binfo;
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index 37dc019..9abbada 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -23,8 +23,8 @@
*/
#include "hw.h"
#include "console.h"
-#include "pc.h"
#include "pci.h"
+#include "vga-pci.h"
#include "vga_int.h"
#include "pixel_ops.h"
#include "qemu-timer.h"
diff --git a/hw/vga-pci.h b/hw/vga-pci.h
new file mode 100644
index 0000000..49abf13
--- /dev/null
+++ b/hw/vga-pci.h
@@ -0,0 +1,12 @@
+#ifndef VGA_PCI_H
+#define VGA_PCI_H
+
+#include "qemu-common.h"
+
+/* vga-pci.c */
+DeviceState *pci_vga_init(PCIBus *bus);
+
+/* cirrus_vga.c */
+DeviceState *pci_cirrus_vga_init(PCIBus *bus);
+
+#endif
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index f21757e..6f6d172 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -254,6 +254,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
virtio_blk_req_complete(req, status);
g_free(req);
+ return;
#else
abort();
#endif
@@ -509,9 +510,19 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
blkcfg.size_max = 0;
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
blkcfg.alignment_offset = 0;
+ blkcfg.wce = bdrv_enable_write_cache(s->bs);
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
}
+static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+ VirtIOBlock *s = to_virtio_blk(vdev);
+ struct virtio_blk_config blkcfg;
+
+ memcpy(&blkcfg, config, sizeof(blkcfg));
+ bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
+}
+
static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
{
VirtIOBlock *s = to_virtio_blk(vdev);
@@ -523,14 +534,27 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
features |= (1 << VIRTIO_BLK_F_SCSI);
if (bdrv_enable_write_cache(s->bs))
- features |= (1 << VIRTIO_BLK_F_WCACHE);
-
+ features |= (1 << VIRTIO_BLK_F_WCE);
+
if (bdrv_is_read_only(s->bs))
features |= 1 << VIRTIO_BLK_F_RO;
return features;
}
+static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
+{
+ VirtIOBlock *s = to_virtio_blk(vdev);
+ uint32_t features;
+
+ if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ return;
+ }
+
+ features = vdev->guest_features;
+ bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
+}
+
static void virtio_blk_save(QEMUFile *f, void *opaque)
{
VirtIOBlock *s = opaque;
@@ -609,7 +633,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk)
sizeof(VirtIOBlock));
s->vdev.get_config = virtio_blk_update_config;
+ s->vdev.set_config = virtio_blk_set_config;
s->vdev.get_features = virtio_blk_get_features;
+ s->vdev.set_status = virtio_blk_set_status;
s->vdev.reset = virtio_blk_reset;
s->bs = blk->conf.bs;
s->conf = &blk->conf;
diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h
index 79ebccc..f0740d0 100644
--- a/hw/virtio-blk.h
+++ b/hw/virtio-blk.h
@@ -31,8 +31,9 @@
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
/* #define VIRTIO_BLK_F_IDENTIFY 8 ATA IDENTIFY supported, DEPRECATED */
-#define VIRTIO_BLK_F_WCACHE 9 /* write cache enabled */
+#define VIRTIO_BLK_F_WCE 9 /* write cache enabled */
#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
+#define VIRTIO_BLK_F_CONFIG_WCE 11 /* write cache configurable */
#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */
@@ -49,6 +50,7 @@ struct virtio_blk_config
uint8_t alignment_offset;
uint16_t min_io_size;
uint32_t opt_io_size;
+ uint8_t wce;
} QEMU_PACKED;
/* These two define direction. */
@@ -102,9 +104,11 @@ struct VirtIOBlkConf
BlockConf conf;
char *serial;
uint32_t scsi;
+ uint32_t config_wce;
};
#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
- DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
+ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
+ DEFINE_PROP_BIT("config-wce", _state, _field, VIRTIO_BLK_F_CONFIG_WCE, true)
#endif
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 5e6e09e..b3f0710 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -131,6 +131,7 @@ static int virtio_pci_load_config(void * opaque, QEMUFile *f)
if (ret) {
return ret;
}
+ msix_unuse_all_vectors(&proxy->pci_dev);
msix_load(&proxy->pci_dev, f);
if (msix_present(&proxy->pci_dev)) {
qemu_get_be16s(f, &proxy->vdev->config_vector);
@@ -246,6 +247,7 @@ void virtio_pci_reset(DeviceState *d)
VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
virtio_pci_stop_ioeventfd(proxy);
virtio_reset(proxy->vdev);
+ msix_unuse_all_vectors(&proxy->pci_dev);
proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
}
@@ -886,6 +888,7 @@ static Property virtio_blk_properties[] = {
#ifdef __linux__
DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true),
#endif
+ DEFINE_PROP_BIT("config-wce", VirtIOPCIProxy, blk.config_wce, 0, true),
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index c4a5b22..c1b47a8 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -24,11 +24,6 @@
#define VIRTIO_SCSI_MAX_TARGET 255
#define VIRTIO_SCSI_MAX_LUN 16383
-/* Feature Bits */
-#define VIRTIO_SCSI_F_INOUT 0
-#define VIRTIO_SCSI_F_HOTPLUG 1
-#define VIRTIO_SCSI_F_CHANGE 2
-
/* Response codes */
#define VIRTIO_SCSI_S_OK 0
#define VIRTIO_SCSI_S_OVERRUN 1
@@ -305,11 +300,17 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
goto incorrect_lun;
}
QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
- if (r->tag == req->req.tmf->tag) {
+ VirtIOSCSIReq *cmd_req = r->hba_private;
+ if (cmd_req && cmd_req->req.cmd->tag == req->req.tmf->tag) {
break;
}
}
- if (r && r->hba_private) {
+ if (r) {
+ /*
+ * Assert that the request has not been completed yet, we
+ * check for it in the loop above.
+ */
+ assert(r->hba_private);
if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
/* "If the specified command is present in the task set, then
* return a service response set to FUNCTION SUCCEEDED".
@@ -555,8 +556,6 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
uint32_t requested_features)
{
- requested_features |= (1UL << VIRTIO_SCSI_F_HOTPLUG);
- requested_features |= (1UL << VIRTIO_SCSI_F_CHANGE);
return requested_features;
}
diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h
index 4bc889d..91924f6 100644
--- a/hw/virtio-scsi.h
+++ b/hw/virtio-scsi.h
@@ -21,6 +21,11 @@
/* The ID for virtio_scsi */
#define VIRTIO_ID_SCSI 8
+/* Feature Bits */
+#define VIRTIO_SCSI_F_INOUT 0
+#define VIRTIO_SCSI_F_HOTPLUG 1
+#define VIRTIO_SCSI_F_CHANGE 2
+
struct VirtIOSCSIConf {
uint32_t num_queues;
uint32_t max_sectors;
@@ -31,6 +36,8 @@ struct VirtIOSCSIConf {
DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \
DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \
DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \
- DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128)
+ DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128), \
+ DEFINE_PROP_BIT("hotplug", _state, _features_field, VIRTIO_SCSI_F_HOTPLUG, true), \
+ DEFINE_PROP_BIT("param_change", _state, _features_field, VIRTIO_SCSI_F_CHANGE, true)
#endif /* _QEMU_VIRTIO_SCSI_H */
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index c1fe984..0d6c2ff 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -87,9 +87,6 @@ static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
{
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
PCI_CLASS_NETWORK_ETHERNET) {
- /* Until qdev_free includes a call to object_unparent, we call it here
- */
- object_unparent(&d->qdev.parent_obj);
qdev_free(&d->qdev);
}
}
diff --git a/hw/xics.c b/hw/xics.c
index 668a0d6..b674771 100644
--- a/hw/xics.c
+++ b/hw/xics.c
@@ -315,18 +315,24 @@ static void ics_eoi(struct ics_state *ics, int nr)
* Exported functions
*/
-qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
- enum xics_irq_type type)
+qemu_irq xics_get_qirq(struct icp_state *icp, int irq)
{
if ((irq < icp->ics->offset)
|| (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
return NULL;
}
+ return icp->ics->qirqs[irq - icp->ics->offset];
+}
+
+void xics_set_irq_type(struct icp_state *icp, int irq,
+ enum xics_irq_type type)
+{
+ assert((irq >= icp->ics->offset)
+ && (irq < (icp->ics->offset + icp->ics->nr_irqs)));
assert((type == XICS_MSI) || (type == XICS_LSI));
icp->ics->irqs[irq - icp->ics->offset].type = type;
- return icp->ics->qirqs[irq - icp->ics->offset];
}
static target_ulong h_cppr(CPUPPCState *env, sPAPREnvironment *spapr,
diff --git a/hw/xics.h b/hw/xics.h
index 2080159..99b96ac 100644
--- a/hw/xics.h
+++ b/hw/xics.h
@@ -36,8 +36,9 @@ enum xics_irq_type {
XICS_LSI, /* Level-signalled interrupt */
};
-qemu_irq xics_assign_irq(struct icp_state *icp, int irq,
- enum xics_irq_type type);
+qemu_irq xics_get_qirq(struct icp_state *icp, int irq);
+void xics_set_irq_type(struct icp_state *icp, int irq,
+ enum xics_irq_type type);
struct icp_state *xics_system_init(int nr_irqs);
diff --git a/hw/xilinx.h b/hw/xilinx.h
index 7df21eb..556c5aa 100644
--- a/hw/xilinx.h
+++ b/hw/xilinx.h
@@ -1,3 +1,4 @@
+#include "stream.h"
#include "qemu-common.h"
#include "net.h"
@@ -49,8 +50,8 @@ xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
}
static inline DeviceState *
-xilinx_axiethernet_create(void *dmach,
- NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
+xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer,
+ target_phys_addr_t base, qemu_irq irq,
int txmem, int rxmem)
{
DeviceState *dev;
@@ -60,7 +61,7 @@ xilinx_axiethernet_create(void *dmach,
qdev_set_nic_properties(dev, nd);
qdev_prop_set_uint32(dev, "rxmem", rxmem);
qdev_prop_set_uint32(dev, "txmem", txmem);
- qdev_prop_set_ptr(dev, "dmach", dmach);
+ object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
@@ -68,21 +69,16 @@ xilinx_axiethernet_create(void *dmach,
return dev;
}
-static inline DeviceState *
-xilinx_axiethernetdma_create(void *dmach,
- target_phys_addr_t base, qemu_irq irq,
- qemu_irq irq2, int freqhz)
+static inline void
+xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer,
+ target_phys_addr_t base, qemu_irq irq,
+ qemu_irq irq2, int freqhz)
{
- DeviceState *dev = NULL;
-
- dev = qdev_create(NULL, "xlnx.axi-dma");
qdev_prop_set_uint32(dev, "freqhz", freqhz);
- qdev_prop_set_ptr(dev, "dmach", dmach);
+ object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq2);
-
- return dev;
}
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index f4bec37..0e28c51 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -29,7 +29,7 @@
#include "qemu-log.h"
#include "qdev-addr.h"
-#include "xilinx_axidma.h"
+#include "stream.h"
#define D(x)
@@ -77,7 +77,7 @@ enum {
SDESC_STATUS_COMPLETE = (1 << 31)
};
-struct AXIStream {
+struct Stream {
QEMUBH *bh;
ptimer_state *ptimer;
qemu_irq irq;
@@ -94,9 +94,9 @@ struct XilinxAXIDMA {
SysBusDevice busdev;
MemoryRegion iomem;
uint32_t freqhz;
- void *dmach;
+ StreamSlave *tx_dev;
- struct AXIStream streams[2];
+ struct Stream streams[2];
};
/*
@@ -113,27 +113,27 @@ static inline int stream_desc_eof(struct SDesc *d)
return d->control & SDESC_CTRL_EOF;
}
-static inline int stream_resetting(struct AXIStream *s)
+static inline int stream_resetting(struct Stream *s)
{
return !!(s->regs[R_DMACR] & DMACR_RESET);
}
-static inline int stream_running(struct AXIStream *s)
+static inline int stream_running(struct Stream *s)
{
return s->regs[R_DMACR] & DMACR_RUNSTOP;
}
-static inline int stream_halted(struct AXIStream *s)
+static inline int stream_halted(struct Stream *s)
{
return s->regs[R_DMASR] & DMASR_HALTED;
}
-static inline int stream_idle(struct AXIStream *s)
+static inline int stream_idle(struct Stream *s)
{
return !!(s->regs[R_DMASR] & DMASR_IDLE);
}
-static void stream_reset(struct AXIStream *s)
+static void stream_reset(struct Stream *s)
{
s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */
s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold. */
@@ -159,7 +159,7 @@ static void stream_desc_show(struct SDesc *d)
}
#endif
-static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
+static void stream_desc_load(struct Stream *s, target_phys_addr_t addr)
{
struct SDesc *d = &s->desc;
int i;
@@ -176,7 +176,7 @@ static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
}
}
-static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
+static void stream_desc_store(struct Stream *s, target_phys_addr_t addr)
{
struct SDesc *d = &s->desc;
int i;
@@ -192,7 +192,7 @@ static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
cpu_physical_memory_write(addr, (void *) d, sizeof *d);
}
-static void stream_update_irq(struct AXIStream *s)
+static void stream_update_irq(struct Stream *s)
{
unsigned int pending, mask, irq;
@@ -204,7 +204,7 @@ static void stream_update_irq(struct AXIStream *s)
qemu_set_irq(s->irq, !!irq);
}
-static void stream_reload_complete_cnt(struct AXIStream *s)
+static void stream_reload_complete_cnt(struct Stream *s)
{
unsigned int comp_th;
comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
@@ -213,14 +213,14 @@ static void stream_reload_complete_cnt(struct AXIStream *s)
static void timer_hit(void *opaque)
{
- struct AXIStream *s = opaque;
+ struct Stream *s = opaque;
stream_reload_complete_cnt(s);
s->regs[R_DMASR] |= DMASR_DLY_IRQ;
stream_update_irq(s);
}
-static void stream_complete(struct AXIStream *s)
+static void stream_complete(struct Stream *s)
{
unsigned int comp_delay;
@@ -240,8 +240,8 @@ static void stream_complete(struct AXIStream *s)
}
}
-static void stream_process_mem2s(struct AXIStream *s,
- struct XilinxDMAConnection *dmach)
+static void stream_process_mem2s(struct Stream *s,
+ StreamSlave *tx_dev)
{
uint32_t prev_d;
unsigned char txbuf[16 * 1024];
@@ -276,7 +276,7 @@ static void stream_process_mem2s(struct AXIStream *s,
s->pos += txlen;
if (stream_desc_eof(&s->desc)) {
- xlx_dma_push_to_client(dmach, txbuf, s->pos, app);
+ stream_push(tx_dev, txbuf, s->pos, app);
s->pos = 0;
stream_complete(s);
}
@@ -295,7 +295,7 @@ static void stream_process_mem2s(struct AXIStream *s,
}
}
-static void stream_process_s2mem(struct AXIStream *s,
+static void stream_process_s2mem(struct Stream *s,
unsigned char *buf, size_t len, uint32_t *app)
{
uint32_t prev_d;
@@ -351,11 +351,11 @@ static void stream_process_s2mem(struct AXIStream *s,
}
}
-static
-void axidma_push(void *opaque, unsigned char *buf, size_t len, uint32_t *app)
+static void
+axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app)
{
- struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s = &d->streams[1];
+ struct XilinxAXIDMA *d = FROM_SYSBUS(typeof(*d), SYS_BUS_DEVICE(obj));
+ struct Stream *s = &d->streams[1];
if (!app) {
hw_error("No stream app data!\n");
@@ -368,7 +368,7 @@ static uint64_t axidma_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s;
+ struct Stream *s;
uint32_t r = 0;
int sid;
@@ -403,7 +403,7 @@ static void axidma_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned size)
{
struct XilinxAXIDMA *d = opaque;
- struct AXIStream *s;
+ struct Stream *s;
int sid;
sid = streamid_from_addr(addr);
@@ -440,7 +440,7 @@ static void axidma_write(void *opaque, target_phys_addr_t addr,
s->regs[addr] = value;
s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle. */
if (!sid) {
- stream_process_mem2s(s, d->dmach);
+ stream_process_mem2s(s, d->tx_dev);
}
break;
default:
@@ -466,12 +466,6 @@ static int xilinx_axidma_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->streams[0].irq);
sysbus_init_irq(dev, &s->streams[1].irq);
- if (!s->dmach) {
- hw_error("Unconnected DMA channel.\n");
- }
-
- xlx_dma_connect_dma(s->dmach, s, axidma_push);
-
memory_region_init_io(&s->iomem, &axidma_ops, s,
"xlnx.axi-dma", R_MAX * 4 * 2);
sysbus_init_mmio(dev, &s->iomem);
@@ -486,9 +480,16 @@ static int xilinx_axidma_init(SysBusDevice *dev)
return 0;
}
+static void xilinx_axidma_initfn(Object *obj)
+{
+ struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+ object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+ (Object **) &s->tx_dev, NULL);
+}
+
static Property axidma_properties[] = {
DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
DEFINE_PROP_END_OF_LIST(),
};
@@ -496,9 +497,11 @@ static void axidma_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
k->init = xilinx_axidma_init;
dc->props = axidma_properties;
+ ssc->push = axidma_push;
}
static TypeInfo axidma_info = {
@@ -506,6 +509,11 @@ static TypeInfo axidma_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct XilinxAXIDMA),
.class_init = axidma_class_init,
+ .instance_init = xilinx_axidma_initfn,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SLAVE },
+ { }
+ }
};
static void xilinx_axidma_register_types(void)
diff --git a/hw/xilinx_axidma.h b/hw/xilinx_axidma.h
deleted file mode 100644
index 37cb6f0..0000000
--- a/hw/xilinx_axidma.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* AXI DMA connection. Used until qdev provides a generic way. */
-typedef void (*DMAPushFn)(void *opaque,
- unsigned char *buf, size_t len, uint32_t *app);
-
-struct XilinxDMAConnection {
- void *dma;
- void *client;
-
- DMAPushFn to_dma;
- DMAPushFn to_client;
-};
-
-static inline void xlx_dma_connect_client(struct XilinxDMAConnection *dmach,
- void *c, DMAPushFn f)
-{
- dmach->client = c;
- dmach->to_client = f;
-}
-
-static inline void xlx_dma_connect_dma(struct XilinxDMAConnection *dmach,
- void *d, DMAPushFn f)
-{
- dmach->dma = d;
- dmach->to_dma = f;
-}
-
-static inline
-void xlx_dma_push_to_dma(struct XilinxDMAConnection *dmach,
- uint8_t *buf, size_t len, uint32_t *app)
-{
- dmach->to_dma(dmach->dma, buf, len, app);
-}
-static inline
-void xlx_dma_push_to_client(struct XilinxDMAConnection *dmach,
- uint8_t *buf, size_t len, uint32_t *app)
-{
- dmach->to_client(dmach->client, buf, len, app);
-}
-
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index 9b08c62..eec155d 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -28,7 +28,7 @@
#include "net.h"
#include "net/checksum.h"
-#include "xilinx_axidma.h"
+#include "stream.h"
#define DPHY(x)
@@ -310,7 +310,7 @@ struct XilinxAXIEnet {
SysBusDevice busdev;
MemoryRegion iomem;
qemu_irq irq;
- void *dmach;
+ StreamSlave *tx_dev;
NICState *nic;
NICConf conf;
@@ -772,7 +772,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
/* Good frame. */
app[2] |= 1 << 6;
- xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app);
+ stream_push(s->tx_dev, (void *)s->rxmem, size, app);
s->regs[R_IS] |= IS_RX_COMPLETE;
enet_update_irq(s);
@@ -788,9 +788,9 @@ static void eth_cleanup(NetClientState *nc)
}
static void
-axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr)
+axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
{
- struct XilinxAXIEnet *s = opaque;
+ struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
/* TX enable ? */
if (!(s->tc & TC_TX)) {
@@ -844,12 +844,6 @@ static int xilinx_enet_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq);
- if (!s->dmach) {
- hw_error("Unconnected Xilinx Ethernet MAC.\n");
- }
-
- xlx_dma_connect_client(s->dmach, s, axienet_stream_push);
-
memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
sysbus_init_mmio(dev, &s->iomem);
@@ -869,11 +863,18 @@ static int xilinx_enet_init(SysBusDevice *dev)
return 0;
}
+static void xilinx_enet_initfn(Object *obj)
+{
+ struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+ object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+ (Object **) &s->tx_dev, NULL);
+}
+
static Property xilinx_enet_properties[] = {
DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
DEFINE_PROP_UINT32("rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
DEFINE_PROP_UINT32("txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
DEFINE_PROP_END_OF_LIST(),
};
@@ -882,9 +883,11 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
k->init = xilinx_enet_init;
dc->props = xilinx_enet_properties;
+ ssc->push = axienet_stream_push;
}
static TypeInfo xilinx_enet_info = {
@@ -892,6 +895,11 @@ static TypeInfo xilinx_enet_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct XilinxAXIEnet),
.class_init = xilinx_enet_class_init,
+ .instance_init = xilinx_enet_initfn,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SLAVE },
+ { }
+ }
};
static void xilinx_enet_register_types(void)
diff --git a/include/qemu/object.h b/include/qemu/object.h
index 8b17776..cc75fee 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -239,6 +239,7 @@ struct ObjectClass
{
/*< private >*/
Type type;
+ GSList *interfaces;
};
/**
@@ -260,7 +261,6 @@ struct Object
{
/*< private >*/
ObjectClass *class;
- GSList *interfaces;
QTAILQ_HEAD(, ObjectProperty) properties;
uint32_t ref;
Object *parent;
@@ -387,6 +387,16 @@ struct TypeInfo
OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
/**
+ * InterfaceInfo:
+ * @type: The name of the interface.
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo {
+ const char *type;
+};
+
+/**
* InterfaceClass:
* @parent_class: the base class
*
@@ -396,26 +406,30 @@ struct TypeInfo
struct InterfaceClass
{
ObjectClass parent_class;
+ /*< private >*/
+ ObjectClass *concrete_class;
};
+#define TYPE_INTERFACE "interface"
+
/**
- * InterfaceInfo:
- * @type: The name of the interface.
- * @interface_initfn: This method is called during class initialization and is
- * used to initialize an interface associated with a class. This function
- * should initialize any default virtual functions for a class and/or override
- * virtual functions in a parent class.
- *
- * The information associated with an interface.
+ * INTERFACE_CLASS:
+ * @klass: class to cast from
+ * Returns: An #InterfaceClass or raise an error if cast is invalid
*/
-struct InterfaceInfo
-{
- const char *type;
+#define INTERFACE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(InterfaceClass, klass, TYPE_INTERFACE)
- void (*interface_initfn)(ObjectClass *class, void *data);
-};
-
-#define TYPE_INTERFACE "interface"
+/**
+ * INTERFACE_CHECK:
+ * @interface: the type to return
+ * @obj: the object to convert to an interface
+ * @name: the interface type name
+ *
+ * Returns: @obj casted to @interface if cast is valid, otherwise raise error.
+ */
+#define INTERFACE_CHECK(interface, obj, name) \
+ ((interface *)object_dynamic_cast_assert(OBJECT((obj)), (name)))
/**
* object_new:
diff --git a/include/qemu/page_cache.h b/include/qemu/page_cache.h
new file mode 100644
index 0000000..3839ac7
--- /dev/null
+++ b/include/qemu/page_cache.h
@@ -0,0 +1,79 @@
+/*
+ * Page cache for QEMU
+ * The cache is base on a hash of the page address
+ *
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Orit Wasserman <owasserm@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef PAGE_CACHE_H
+#define PAGE_CACHE_H
+
+/* Page cache for storing guest pages */
+typedef struct PageCache PageCache;
+
+/**
+ * cache_init: Initialize the page cache
+ *
+ *
+ * Returns new allocated cache or NULL on error
+ *
+ * @cache pointer to the PageCache struct
+ * @num_pages: cache maximal number of cached pages
+ * @page_size: cache page size
+ */
+PageCache *cache_init(int64_t num_pages, unsigned int page_size);
+
+/**
+ * cache_fini: free all cache resources
+ * @cache pointer to the PageCache struct
+ */
+void cache_fini(PageCache *cache);
+
+/**
+ * cache_is_cached: Checks to see if the page is cached
+ *
+ * Returns %true if page is cached
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page addr
+ */
+bool cache_is_cached(const PageCache *cache, uint64_t addr);
+
+/**
+ * get_cached_data: Get the data cached for an addr
+ *
+ * Returns pointer to the data cached or NULL if not cached
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page addr
+ */
+uint8_t *get_cached_data(const PageCache *cache, uint64_t addr);
+
+/**
+ * cache_insert: insert the page into the cache. the previous value will be overwritten
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page address
+ * @pdata: pointer to the page
+ */
+void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata);
+
+/**
+ * cache_resize: resize the page cache. In case of size reduction the extra
+ * pages will be freed
+ *
+ * Returns -1 on error new cache size on success
+ *
+ * @cache pointer to the PageCache struct
+ * @num_pages: new page cache size (in pages)
+ */
+int64_t cache_resize(PageCache *cache, int64_t num_pages);
+
+#endif
diff --git a/iohandler.c b/iohandler.c
index 3c74de6..dea4355 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -77,6 +77,7 @@ int qemu_set_fd_handler2(int fd,
ioh->fd_write = fd_write;
ioh->opaque = opaque;
ioh->deleted = 0;
+ qemu_notify_event();
}
return 0;
}
diff --git a/iov.c b/iov.c
index b333061..60705c7 100644
--- a/iov.c
+++ b/iov.c
@@ -146,6 +146,13 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
{
ssize_t ret;
unsigned si, ei; /* start and end indexes */
+ if (bytes == 0) {
+ /* Catch the do-nothing case early, as otherwise we will pass an
+ * empty iovec to sendmsg/recvmsg(), and not all implementations
+ * accept this.
+ */
+ return 0;
+ }
/* Find the start position, skipping `offset' bytes:
* first, skip all full-sized vector elements, */
diff --git a/json-parser.c b/json-parser.c
index 849e215..457291b 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -27,6 +27,11 @@
typedef struct JSONParserContext
{
Error *err;
+ struct {
+ QObject **buf;
+ size_t pos;
+ size_t count;
+ } tokens;
} JSONParserContext;
#define BUG_ON(cond) assert(!(cond))
@@ -40,7 +45,7 @@ typedef struct JSONParserContext
* 4) deal with premature EOI
*/
-static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap);
+static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
/**
* Token manipulators
@@ -270,27 +275,111 @@ out:
return NULL;
}
+static QObject *parser_context_pop_token(JSONParserContext *ctxt)
+{
+ QObject *token;
+ g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+ token = ctxt->tokens.buf[ctxt->tokens.pos];
+ ctxt->tokens.pos++;
+ return token;
+}
+
+/* Note: parser_context_{peek|pop}_token do not increment the
+ * token object's refcount. In both cases the references will continue
+ * to be tracked and cleaned up in parser_context_free(), so do not
+ * attempt to free the token object.
+ */
+static QObject *parser_context_peek_token(JSONParserContext *ctxt)
+{
+ QObject *token;
+ g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+ token = ctxt->tokens.buf[ctxt->tokens.pos];
+ return token;
+}
+
+static JSONParserContext parser_context_save(JSONParserContext *ctxt)
+{
+ JSONParserContext saved_ctxt = {0};
+ saved_ctxt.tokens.pos = ctxt->tokens.pos;
+ saved_ctxt.tokens.count = ctxt->tokens.count;
+ saved_ctxt.tokens.buf = ctxt->tokens.buf;
+ return saved_ctxt;
+}
+
+static void parser_context_restore(JSONParserContext *ctxt,
+ JSONParserContext saved_ctxt)
+{
+ ctxt->tokens.pos = saved_ctxt.tokens.pos;
+ ctxt->tokens.count = saved_ctxt.tokens.count;
+ ctxt->tokens.buf = saved_ctxt.tokens.buf;
+}
+
+static void tokens_append_from_iter(QObject *obj, void *opaque)
+{
+ JSONParserContext *ctxt = opaque;
+ g_assert(ctxt->tokens.pos < ctxt->tokens.count);
+ ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
+ qobject_incref(obj);
+}
+
+static JSONParserContext *parser_context_new(QList *tokens)
+{
+ JSONParserContext *ctxt;
+ size_t count;
+
+ if (!tokens) {
+ return NULL;
+ }
+
+ count = qlist_size(tokens);
+ if (count == 0) {
+ return NULL;
+ }
+
+ ctxt = g_malloc0(sizeof(JSONParserContext));
+ ctxt->tokens.pos = 0;
+ ctxt->tokens.count = count;
+ ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
+ qlist_iter(tokens, tokens_append_from_iter, ctxt);
+ ctxt->tokens.pos = 0;
+
+ return ctxt;
+}
+
+/* to support error propagation, ctxt->err must be freed separately */
+static void parser_context_free(JSONParserContext *ctxt)
+{
+ int i;
+ if (ctxt) {
+ for (i = 0; i < ctxt->tokens.count; i++) {
+ qobject_decref(ctxt->tokens.buf[i]);
+ }
+ g_free(ctxt->tokens.buf);
+ g_free(ctxt);
+ }
+}
+
/**
* Parsing rules
*/
-static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_list *ap)
+static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
{
QObject *key = NULL, *token = NULL, *value, *peek;
- QList *working = qlist_copy(*tokens);
+ JSONParserContext saved_ctxt = parser_context_save(ctxt);
- peek = qlist_peek(working);
+ peek = parser_context_peek_token(ctxt);
if (peek == NULL) {
parse_error(ctxt, NULL, "premature EOI");
goto out;
}
- key = parse_value(ctxt, &working, ap);
+ key = parse_value(ctxt, ap);
if (!key || qobject_type(key) != QTYPE_QSTRING) {
parse_error(ctxt, peek, "key is not a string in object");
goto out;
}
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
parse_error(ctxt, NULL, "premature EOI");
goto out;
@@ -301,7 +390,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
goto out;
}
- value = parse_value(ctxt, &working, ap);
+ value = parse_value(ctxt, ap);
if (value == NULL) {
parse_error(ctxt, token, "Missing value in dict");
goto out;
@@ -309,28 +398,24 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
qdict_put_obj(dict, qstring_get_str(qobject_to_qstring(key)), value);
- qobject_decref(token);
qobject_decref(key);
- QDECREF(*tokens);
- *tokens = working;
return 0;
out:
- qobject_decref(token);
+ parser_context_restore(ctxt, saved_ctxt);
qobject_decref(key);
- QDECREF(working);
return -1;
}
-static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
{
QDict *dict = NULL;
QObject *token, *peek;
- QList *working = qlist_copy(*tokens);
+ JSONParserContext saved_ctxt = parser_context_save(ctxt);
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
goto out;
}
@@ -338,23 +423,22 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
if (!token_is_operator(token, '{')) {
goto out;
}
- qobject_decref(token);
token = NULL;
dict = qdict_new();
- peek = qlist_peek(working);
+ peek = parser_context_peek_token(ctxt);
if (peek == NULL) {
parse_error(ctxt, NULL, "premature EOI");
goto out;
}
if (!token_is_operator(peek, '}')) {
- if (parse_pair(ctxt, dict, &working, ap) == -1) {
+ if (parse_pair(ctxt, dict, ap) == -1) {
goto out;
}
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
parse_error(ctxt, NULL, "premature EOI");
goto out;
@@ -365,59 +449,52 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
parse_error(ctxt, token, "expected separator in dict");
goto out;
}
- qobject_decref(token);
token = NULL;
- if (parse_pair(ctxt, dict, &working, ap) == -1) {
+ if (parse_pair(ctxt, dict, ap) == -1) {
goto out;
}
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
parse_error(ctxt, NULL, "premature EOI");
goto out;
}
}
- qobject_decref(token);
token = NULL;
} else {
- token = qlist_pop(working);
- qobject_decref(token);
+ token = parser_context_pop_token(ctxt);
token = NULL;
}
- QDECREF(*tokens);
- *tokens = working;
-
return QOBJECT(dict);
out:
- qobject_decref(token);
- QDECREF(working);
+ parser_context_restore(ctxt, saved_ctxt);
QDECREF(dict);
return NULL;
}
-static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
{
QList *list = NULL;
QObject *token, *peek;
- QList *working = qlist_copy(*tokens);
+ JSONParserContext saved_ctxt = parser_context_save(ctxt);
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
goto out;
}
if (!token_is_operator(token, '[')) {
+ token = NULL;
goto out;
}
- qobject_decref(token);
token = NULL;
list = qlist_new();
- peek = qlist_peek(working);
+ peek = parser_context_peek_token(ctxt);
if (peek == NULL) {
parse_error(ctxt, NULL, "premature EOI");
goto out;
@@ -426,7 +503,7 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
if (!token_is_operator(peek, ']')) {
QObject *obj;
- obj = parse_value(ctxt, &working, ap);
+ obj = parse_value(ctxt, ap);
if (obj == NULL) {
parse_error(ctxt, token, "expecting value");
goto out;
@@ -434,7 +511,7 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
qlist_append_obj(list, obj);
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
parse_error(ctxt, NULL, "premature EOI");
goto out;
@@ -446,10 +523,9 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
goto out;
}
- qobject_decref(token);
token = NULL;
- obj = parse_value(ctxt, &working, ap);
+ obj = parse_value(ctxt, ap);
if (obj == NULL) {
parse_error(ctxt, token, "expecting value");
goto out;
@@ -457,39 +533,33 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
qlist_append_obj(list, obj);
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
parse_error(ctxt, NULL, "premature EOI");
goto out;
}
}
- qobject_decref(token);
token = NULL;
} else {
- token = qlist_pop(working);
- qobject_decref(token);
+ token = parser_context_pop_token(ctxt);
token = NULL;
}
- QDECREF(*tokens);
- *tokens = working;
-
return QOBJECT(list);
out:
- qobject_decref(token);
- QDECREF(working);
+ parser_context_restore(ctxt, saved_ctxt);
QDECREF(list);
return NULL;
}
-static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
+static QObject *parse_keyword(JSONParserContext *ctxt)
{
QObject *token, *ret;
- QList *working = qlist_copy(*tokens);
+ JSONParserContext saved_ctxt = parser_context_save(ctxt);
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
goto out;
}
@@ -507,29 +577,24 @@ static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
goto out;
}
- qobject_decref(token);
- QDECREF(*tokens);
- *tokens = working;
-
return ret;
out:
- qobject_decref(token);
- QDECREF(working);
+ parser_context_restore(ctxt, saved_ctxt);
return NULL;
}
-static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
{
QObject *token = NULL, *obj;
- QList *working = qlist_copy(*tokens);
+ JSONParserContext saved_ctxt = parser_context_save(ctxt);
if (ap == NULL) {
goto out;
}
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
goto out;
}
@@ -553,25 +618,20 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a
goto out;
}
- qobject_decref(token);
- QDECREF(*tokens);
- *tokens = working;
-
return obj;
out:
- qobject_decref(token);
- QDECREF(working);
+ parser_context_restore(ctxt, saved_ctxt);
return NULL;
}
-static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
+static QObject *parse_literal(JSONParserContext *ctxt)
{
QObject *token, *obj;
- QList *working = qlist_copy(*tokens);
+ JSONParserContext saved_ctxt = parser_context_save(ctxt);
- token = qlist_pop(working);
+ token = parser_context_pop_token(ctxt);
if (token == NULL) {
goto out;
}
@@ -591,35 +651,30 @@ static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
goto out;
}
- qobject_decref(token);
- QDECREF(*tokens);
- *tokens = working;
-
return obj;
out:
- qobject_decref(token);
- QDECREF(working);
+ parser_context_restore(ctxt, saved_ctxt);
return NULL;
}
-static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap)
+static QObject *parse_value(JSONParserContext *ctxt, va_list *ap)
{
QObject *obj;
- obj = parse_object(ctxt, tokens, ap);
+ obj = parse_object(ctxt, ap);
if (obj == NULL) {
- obj = parse_array(ctxt, tokens, ap);
+ obj = parse_array(ctxt, ap);
}
if (obj == NULL) {
- obj = parse_escape(ctxt, tokens, ap);
+ obj = parse_escape(ctxt, ap);
}
if (obj == NULL) {
- obj = parse_keyword(ctxt, tokens);
+ obj = parse_keyword(ctxt);
}
if (obj == NULL) {
- obj = parse_literal(ctxt, tokens);
+ obj = parse_literal(ctxt);
}
return obj;
@@ -632,19 +687,18 @@ QObject *json_parser_parse(QList *tokens, va_list *ap)
QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
{
- JSONParserContext ctxt = {};
- QList *working;
+ JSONParserContext *ctxt = parser_context_new(tokens);
QObject *result;
- if (!tokens) {
+ if (!ctxt) {
return NULL;
}
- working = qlist_copy(tokens);
- result = parse_value(&ctxt, &working, ap);
- QDECREF(working);
+ result = parse_value(ctxt, ap);
+
+ error_propagate(errp, ctxt->err);
- error_propagate(errp, ctxt.err);
+ parser_context_free(ctxt);
return result;
}
diff --git a/kvm-all.c b/kvm-all.c
index 9a1f001..b713c03 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1214,6 +1214,26 @@ static int kvm_irqchip_create(KVMState *s)
return 0;
}
+static int kvm_max_vcpus(KVMState *s)
+{
+ int ret;
+
+ /* Find number of supported CPUs using the recommended
+ * procedure from the kernel API documentation to cope with
+ * older kernels that may be missing capabilities.
+ */
+ ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS);
+ if (ret) {
+ return ret;
+ }
+ ret = kvm_check_extension(s, KVM_CAP_NR_VCPUS);
+ if (ret) {
+ return ret;
+ }
+
+ return 4;
+}
+
int kvm_init(void)
{
static const char upgrade_note[] =
@@ -1223,6 +1243,7 @@ int kvm_init(void)
const KVMCapabilityInfo *missing_cap;
int ret;
int i;
+ int max_vcpus;
s = g_malloc0(sizeof(KVMState));
@@ -1263,6 +1284,14 @@ int kvm_init(void)
goto err;
}
+ max_vcpus = kvm_max_vcpus(s);
+ if (smp_cpus > max_vcpus) {
+ ret = -EINVAL;
+ fprintf(stderr, "Number of SMP cpus requested (%d) exceeds max cpus "
+ "supported by KVM (%d)\n", smp_cpus, max_vcpus);
+ goto err;
+ }
+
s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0);
if (s->vmfd < 0) {
#ifdef TARGET_S390X
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index bdcbe0f..d25da59 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -1,7 +1,7 @@
#ifndef __LINUX_KVM_S390_H
#define __LINUX_KVM_S390_H
/*
- * asm-s390/kvm.h - KVM s390 specific structures and definitions
+ * KVM s390 specific structures and definitions
*
* Copyright IBM Corp. 2008
*
diff --git a/linux-headers/asm-s390/kvm_para.h b/linux-headers/asm-s390/kvm_para.h
index 8e2dd67..870051f 100644
--- a/linux-headers/asm-s390/kvm_para.h
+++ b/linux-headers/asm-s390/kvm_para.h
@@ -1,5 +1,5 @@
/*
- * asm-s390/kvm_para.h - definition for paravirtual devices on s390
+ * definition for paravirtual devices on s390
*
* Copyright IBM Corp. 2008
*
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index e7d1c19..246617e 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -12,6 +12,7 @@
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_PIT
#define __KVM_HAVE_IOAPIC
+#define __KVM_HAVE_IRQ_LINE
#define __KVM_HAVE_DEVICE_ASSIGNMENT
#define __KVM_HAVE_MSI
#define __KVM_HAVE_USER_NMI
diff --git a/linux-headers/asm-x86/kvm_para.h b/linux-headers/asm-x86/kvm_para.h
index f2ac46a..a1c3d72 100644
--- a/linux-headers/asm-x86/kvm_para.h
+++ b/linux-headers/asm-x86/kvm_para.h
@@ -22,6 +22,7 @@
#define KVM_FEATURE_CLOCKSOURCE2 3
#define KVM_FEATURE_ASYNC_PF 4
#define KVM_FEATURE_STEAL_TIME 5
+#define KVM_FEATURE_PV_EOI 6
/* The last 8 bits are used to indicate how to interpret the flags field
* in pvclock structure. If no bits are set, all flags are ignored.
@@ -37,6 +38,7 @@
#define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01
#define MSR_KVM_ASYNC_PF_EN 0x4b564d02
#define MSR_KVM_STEAL_TIME 0x4b564d03
+#define MSR_KVM_PV_EOI_EN 0x4b564d04
struct kvm_steal_time {
__u64 steal;
@@ -89,5 +91,10 @@ struct kvm_vcpu_pv_apf_data {
__u32 enabled;
};
+#define KVM_PV_EOI_BIT 0
+#define KVM_PV_EOI_MASK (0x1 << KVM_PV_EOI_BIT)
+#define KVM_PV_EOI_ENABLED KVM_PV_EOI_MASK
+#define KVM_PV_EOI_DISABLED 0x0
+
#endif /* _ASM_X86_KVM_PARA_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 0afbbab..ded8cc4 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -618,6 +618,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_SIGNAL_MSI 77
#define KVM_CAP_PPC_GET_SMMU_INFO 78
#define KVM_CAP_S390_COW 79
+#define KVM_CAP_PPC_ALLOC_HTAB 80
#ifdef KVM_CAP_IRQ_ROUTING
@@ -829,6 +830,8 @@ struct kvm_s390_ucas_mapping {
#define KVM_SIGNAL_MSI _IOW(KVMIO, 0xa5, struct kvm_msi)
/* Available with KVM_CAP_PPC_GET_SMMU_INFO */
#define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info)
+/* Available with KVM_CAP_PPC_ALLOC_HTAB */
+#define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32)
/*
* ioctls for vcpu fds
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 6b622d4..819fdd5 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -332,9 +332,17 @@ enum
ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
};
-#define TARGET_HAS_GUEST_VALIDATE_BASE
-/* We want the opportunity to check the suggested base */
-bool guest_validate_base(unsigned long guest_base)
+#define TARGET_HAS_VALIDATE_GUEST_SPACE
+/* Return 1 if the proposed guest space is suitable for the guest.
+ * Return 0 if the proposed guest space isn't suitable, but another
+ * address space should be tried.
+ * Return -1 if there is no way the proposed guest space can be
+ * valid regardless of the base.
+ * The guest code may leave a page mapped and populate it if the
+ * address is suitable.
+ */
+static int validate_guest_space(unsigned long guest_base,
+ unsigned long guest_size)
{
unsigned long real_start, test_page_addr;
@@ -342,6 +350,15 @@ bool guest_validate_base(unsigned long guest_base)
* commpage at 0xffff0fxx
*/
test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
+
+ /* If the commpage lies within the already allocated guest space,
+ * then there is no way we can allocate it.
+ */
+ if (test_page_addr >= guest_base
+ && test_page_addr <= (guest_base + guest_size)) {
+ return -1;
+ }
+
/* Note it needs to be writeable to let us initialise it */
real_start = (unsigned long)
mmap((void *)test_page_addr, qemu_host_page_size,
@@ -1418,14 +1435,105 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
return sp;
}
-#ifndef TARGET_HAS_GUEST_VALIDATE_BASE
+#ifndef TARGET_HAS_VALIDATE_GUEST_SPACE
/* If the guest doesn't have a validation function just agree */
-bool guest_validate_base(unsigned long guest_base)
+static int validate_guest_space(unsigned long guest_base,
+ unsigned long guest_size)
{
return 1;
}
#endif
+unsigned long init_guest_space(unsigned long host_start,
+ unsigned long host_size,
+ unsigned long guest_start,
+ bool fixed)
+{
+ unsigned long current_start, real_start;
+ int flags;
+
+ assert(host_start || host_size);
+
+ /* If just a starting address is given, then just verify that
+ * address. */
+ if (host_start && !host_size) {
+ if (validate_guest_space(host_start, host_size) == 1) {
+ return host_start;
+ } else {
+ return (unsigned long)-1;
+ }
+ }
+
+ /* Setup the initial flags and start address. */
+ current_start = host_start & qemu_host_page_mask;
+ flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
+ if (fixed) {
+ flags |= MAP_FIXED;
+ }
+
+ /* Otherwise, a non-zero size region of memory needs to be mapped
+ * and validated. */
+ while (1) {
+ unsigned long real_size = host_size;
+
+ /* Do not use mmap_find_vma here because that is limited to the
+ * guest address space. We are going to make the
+ * guest address space fit whatever we're given.
+ */
+ real_start = (unsigned long)
+ mmap((void *)current_start, host_size, PROT_NONE, flags, -1, 0);
+ if (real_start == (unsigned long)-1) {
+ return (unsigned long)-1;
+ }
+
+ /* Ensure the address is properly aligned. */
+ if (real_start & ~qemu_host_page_mask) {
+ munmap((void *)real_start, host_size);
+ real_size = host_size + qemu_host_page_size;
+ real_start = (unsigned long)
+ mmap((void *)real_start, real_size, PROT_NONE, flags, -1, 0);
+ if (real_start == (unsigned long)-1) {
+ return (unsigned long)-1;
+ }
+ real_start = HOST_PAGE_ALIGN(real_start);
+ }
+
+ /* Check to see if the address is valid. */
+ if (!host_start || real_start == current_start) {
+ int valid = validate_guest_space(real_start - guest_start,
+ real_size);
+ if (valid == 1) {
+ break;
+ } else if (valid == -1) {
+ return (unsigned long)-1;
+ }
+ /* valid == 0, so try again. */
+ }
+
+ /* That address didn't work. Unmap and try a different one.
+ * The address the host picked because is typically right at
+ * the top of the host address space and leaves the guest with
+ * no usable address space. Resort to a linear search. We
+ * already compensated for mmap_min_addr, so this should not
+ * happen often. Probably means we got unlucky and host
+ * address space randomization put a shared library somewhere
+ * inconvenient.
+ */
+ munmap((void *)real_start, host_size);
+ current_start += qemu_host_page_size;
+ if (host_start == current_start) {
+ /* Theoretically possible if host doesn't have any suitably
+ * aligned areas. Normally the first mmap will fail.
+ */
+ return (unsigned long)-1;
+ }
+ }
+
+ qemu_log("Reserved 0x%lx bytes of guest address space\n", host_size);
+
+ return real_start;
+}
+
static void probe_guest_base(const char *image_name,
abi_ulong loaddr, abi_ulong hiaddr)
{
@@ -1452,46 +1560,23 @@ static void probe_guest_base(const char *image_name,
}
}
host_size = hiaddr - loaddr;
- while (1) {
- /* Do not use mmap_find_vma here because that is limited to the
- guest address space. We are going to make the
- guest address space fit whatever we're given. */
- real_start = (unsigned long)
- mmap((void *)host_start, host_size, PROT_NONE,
- MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
- if (real_start == (unsigned long)-1) {
- goto exit_perror;
- }
- guest_base = real_start - loaddr;
- if ((real_start == host_start) &&
- guest_validate_base(guest_base)) {
- break;
- }
- /* That address didn't work. Unmap and try a different one.
- The address the host picked because is typically right at
- the top of the host address space and leaves the guest with
- no usable address space. Resort to a linear search. We
- already compensated for mmap_min_addr, so this should not
- happen often. Probably means we got unlucky and host
- address space randomization put a shared library somewhere
- inconvenient. */
- munmap((void *)real_start, host_size);
- host_start += qemu_host_page_size;
- if (host_start == loaddr) {
- /* Theoretically possible if host doesn't have any suitably
- aligned areas. Normally the first mmap will fail. */
- errmsg = "Unable to find space for application";
- goto exit_errmsg;
- }
+
+ /* Setup the initial guest memory space with ranges gleaned from
+ * the ELF image that is being loaded.
+ */
+ real_start = init_guest_space(host_start, host_size, loaddr, false);
+ if (real_start == (unsigned long)-1) {
+ errmsg = "Unable to find space for application";
+ goto exit_errmsg;
}
+ guest_base = real_start - loaddr;
+
qemu_log("Relocating guest address space from 0x"
TARGET_ABI_FMT_lx " to 0x%lx\n",
loaddr, real_start);
}
return;
-exit_perror:
- errmsg = strerror(errno);
exit_errmsg:
fprintf(stderr, "%s: %s\n", image_name, errmsg);
exit(-1);
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
index be79496..58f679e 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -660,7 +660,7 @@ static int load_flat_file(struct linux_binprm * bprm,
}
/* zero the BSS. */
- memset((void *)((unsigned long)datapos + data_len), 0, bss_len);
+ memset(g2h(datapos + data_len), 0, bss_len);
return 0;
}
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index eb96a08..8a47767 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -186,8 +186,8 @@
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT))
+ IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_buffmem_desc)))
+ IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_buffmem_desc)))
IOCTL(SNDCTL_DSP_NONBLOCK, 0, TYPE_NULL)
IOCTL(SNDCTL_DSP_POST, 0, TYPE_NULL)
IOCTL(SNDCTL_DSP_RESET, 0, TYPE_NULL)
diff --git a/linux-user/main.c b/linux-user/main.c
index 53714de..1a1c661 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -822,8 +822,7 @@ void cpu_loop(CPUARMState *env)
} else if (n == ARM_NR_semihosting
|| n == ARM_NR_thumb_semihosting) {
env->regs[0] = do_arm_semihosting (env);
- } else if (n == 0 || n >= ARM_SYSCALL_BASE
- || (env->thumb && n == ARM_THUMB_SYSCALL)) {
+ } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
/* linux syscall */
if (env->thumb || n == 0) {
n = env->regs[7];
@@ -958,7 +957,8 @@ void cpu_loop(CPUUniCore32State *env)
}
}
break;
- case UC32_EXCP_TRAP:
+ case UC32_EXCP_DTRAP:
+ case UC32_EXCP_ITRAP:
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
@@ -3222,7 +3222,7 @@ struct qemu_argument {
const char *help;
};
-struct qemu_argument arg_table[] = {
+static const struct qemu_argument arg_table[] = {
{"h", "", false, handle_arg_help,
"", "print this help"},
{"g", "QEMU_GDB", true, handle_arg_gdb,
@@ -3264,7 +3264,7 @@ struct qemu_argument arg_table[] = {
static void usage(void)
{
- struct qemu_argument *arginfo;
+ const struct qemu_argument *arginfo;
int maxarglen;
int maxenvlen;
@@ -3330,7 +3330,7 @@ static int parse_args(int argc, char **argv)
{
const char *r;
int optind;
- struct qemu_argument *arginfo;
+ const struct qemu_argument *arginfo;
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (arginfo->env == NULL) {
@@ -3515,39 +3515,19 @@ int main(int argc, char **argv, char **envp)
*/
guest_base = HOST_PAGE_ALIGN(guest_base);
- if (reserved_va) {
- void *p;
- int flags;
-
- flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
- if (have_guest_base) {
- flags |= MAP_FIXED;
- }
- p = mmap((void *)guest_base, reserved_va, PROT_NONE, flags, -1, 0);
- if (p == MAP_FAILED) {
- fprintf(stderr, "Unable to reserve guest address space\n");
+ if (reserved_va || have_guest_base) {
+ guest_base = init_guest_space(guest_base, reserved_va, 0,
+ have_guest_base);
+ if (guest_base == (unsigned long)-1) {
+ fprintf(stderr, "Unable to reserve 0x%lx bytes of virtual address "
+ "space for use as guest address space (check your virtual "
+ "memory ulimit setting or reserve less using -R option)\n",
+ reserved_va);
exit(1);
}
- guest_base = (unsigned long)p;
- /* Make sure the address is properly aligned. */
- if (guest_base & ~qemu_host_page_mask) {
- munmap(p, reserved_va);
- p = mmap((void *)guest_base, reserved_va + qemu_host_page_size,
- PROT_NONE, flags, -1, 0);
- if (p == MAP_FAILED) {
- fprintf(stderr, "Unable to reserve guest address space\n");
- exit(1);
- }
- guest_base = HOST_PAGE_ALIGN((unsigned long)p);
- }
- qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
- mmap_next_start = reserved_va;
- }
- if (reserved_va || have_guest_base) {
- if (!guest_validate_base(guest_base)) {
- fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
- exit(1);
+ if (reserved_va) {
+ mmap_next_start = reserved_va;
}
}
#endif /* CONFIG_USE_GUEST_BASE */
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 7b299b7..69b27d7 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -204,11 +204,18 @@ int get_osversion(void);
void fork_start(void);
void fork_end(int child);
-/* Return true if the proposed guest_base is suitable for the guest.
- * The guest code may leave a page mapped and populate it if the
- * address is suitable.
+/* Creates the initial guest address space in the host memory space using
+ * the given host start address hint and size. The guest_start parameter
+ * specifies the start address of the guest space. guest_base will be the
+ * difference between the host start address computed by this function and
+ * guest_start. If fixed is specified, then the mapped address space must
+ * start at host_start. The real start address of the mapped memory space is
+ * returned or -1 if there was an error.
*/
-bool guest_validate_base(unsigned long guest_base);
+unsigned long init_guest_space(unsigned long host_start,
+ unsigned long host_size,
+ unsigned long guest_start,
+ bool fixed);
#include "qemu-log.h"
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 3ba3ef5..6257a04 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -60,6 +60,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <linux/wireless.h>
+#include <linux/icmp.h>
#include "qemu-common.h"
#ifdef TARGET_GPROF
#include <sys/gmon.h>
@@ -1268,7 +1269,6 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr,
return 0;
}
-/* ??? Should this also swap msgh->name? */
static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
struct target_msghdr *target_msgh)
{
@@ -1325,7 +1325,6 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
return 0;
}
-/* ??? Should this also swap msgh->name? */
static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
struct msghdr *msgh)
{
@@ -1360,16 +1359,28 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
- if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
- gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
- memcpy(target_data, data, len);
- } else {
+ if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+ (cmsg->cmsg_type == SCM_RIGHTS)) {
int *fd = (int *)data;
int *target_fd = (int *)target_data;
int i, numfds = len / sizeof(int);
for (i = 0; i < numfds; i++)
target_fd[i] = tswap32(fd[i]);
+ } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+ (cmsg->cmsg_type == SO_TIMESTAMP) &&
+ (len == sizeof(struct timeval))) {
+ /* copy struct timeval to target */
+ struct timeval *tv = (struct timeval *)data;
+ struct target_timeval *target_tv =
+ (struct target_timeval *)target_data;
+
+ target_tv->tv_sec = tswapal(tv->tv_sec);
+ target_tv->tv_usec = tswapal(tv->tv_usec);
+ } else {
+ gemu_log("Unsupported ancillary data: %d/%d\n",
+ cmsg->cmsg_level, cmsg->cmsg_type);
+ memcpy(target_data, data, len);
}
cmsg = CMSG_NXTHDR(msgh, cmsg);
@@ -1454,6 +1465,25 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
goto unimplemented;
}
break;
+ case SOL_RAW:
+ switch (optname) {
+ case ICMP_FILTER:
+ /* struct icmp_filter takes an u32 value */
+ if (optlen < sizeof(uint32_t)) {
+ return -TARGET_EINVAL;
+ }
+
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, level, optname,
+ &val, sizeof(val)));
+ break;
+
+ default:
+ goto unimplemented;
+ }
+ break;
case TARGET_SOL_SOCKET:
switch (optname) {
/* Options with 'int' argument. */
@@ -1885,10 +1915,22 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
if (!is_error(ret)) {
len = ret;
ret = host_to_target_cmsg(msgp, &msg);
- if (!is_error(ret))
+ if (!is_error(ret)) {
+ msgp->msg_namelen = tswap32(msg.msg_namelen);
+ if (msg.msg_name != NULL) {
+ ret = host_to_target_sockaddr(tswapal(msgp->msg_name),
+ msg.msg_name, msg.msg_namelen);
+ if (ret) {
+ goto out;
+ }
+ }
+
ret = len;
+ }
}
}
+
+out:
unlock_iovec(vec, target_vec, count, !send);
unlock_user_struct(msgp, target_msg, send ? 0 : 1);
return ret;
@@ -2806,7 +2848,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
return -TARGET_EFAULT;
- host_mb = malloc(msgsz+sizeof(long));
+ host_mb = g_malloc(msgsz+sizeof(long));
ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
if (ret > 0) {
@@ -2821,11 +2863,11 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
}
target_mb->mtype = tswapal(host_mb->mtype);
- free(host_mb);
end:
if (target_mb)
unlock_user_struct(target_mb, msgp, 1);
+ g_free(host_mb);
return ret;
}
@@ -4606,6 +4648,12 @@ void syscall_init(void)
#undef STRUCT
#undef STRUCT_SPECIAL
+ /* Build target_to_host_errno_table[] table from
+ * host_to_target_errno_table[]. */
+ for (i = 0; i < ERRNO_TABLE_SIZE; i++) {
+ target_to_host_errno_table[host_to_target_errno_table[i]] = i;
+ }
+
/* we patch the ioctl size if necessary. We rely on the fact that
no ioctl has all the bits at '1' in the size field */
ie = ioctl_entries;
@@ -4625,11 +4673,6 @@ void syscall_init(void)
(size << TARGET_IOC_SIZESHIFT);
}
- /* Build target_to_host_errno_table[] table from
- * host_to_target_errno_table[]. */
- for (i=0; i < ERRNO_TABLE_SIZE; i++)
- target_to_host_errno_table[host_to_target_errno_table[i]] = i;
-
/* automatic consistency check if same arch */
#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
(defined(__x86_64__) && defined(TARGET_X86_64))
@@ -6982,15 +7025,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
tde = target_dirp;
while (len > 0) {
reclen = de->d_reclen;
- treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
+ tnamelen = reclen - offsetof(struct linux_dirent, d_name);
+ assert(tnamelen >= 0);
+ treclen = tnamelen + offsetof(struct target_dirent, d_name);
+ assert(count1 + treclen <= count);
tde->d_reclen = tswap16(treclen);
tde->d_ino = tswapal(de->d_ino);
tde->d_off = tswapal(de->d_off);
- tnamelen = treclen - (2 * sizeof(abi_long) + 2);
- if (tnamelen > 256)
- tnamelen = 256;
- /* XXX: may not be correct */
- pstrcpy(tde->d_name, tnamelen, de->d_name);
+ memcpy(tde->d_name, de->d_name, tnamelen);
de = (struct linux_dirent *)((char *)de + reclen);
len -= reclen;
tde = (struct target_dirent *)((char *)tde + treclen);
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index ba9a58c..a98cbf7 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -255,10 +255,10 @@ struct kernel_statfs {
};
struct target_dirent {
- abi_long d_ino;
- abi_long d_off;
- unsigned short d_reclen;
- char d_name[256]; /* We must not include limits.h! */
+ abi_long d_ino;
+ abi_long d_off;
+ unsigned short d_reclen;
+ char d_name[];
};
struct target_dirent64 {
@@ -880,8 +880,8 @@ struct target_pollfd {
#define TARGET_BLKSECTGET TARGET_IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
#define TARGET_BLKSSZGET TARGET_IO(0x12,104)/* get block device sector size */
/* A jump here: 108-111 have been used for various private purposes. */
-#define TARGET_BLKBSZGET TARGET_IOR(0x12,112,int)
-#define TARGET_BLKBSZSET TARGET_IOW(0x12,113,int)
+#define TARGET_BLKBSZGET TARGET_IOR(0x12, 112, abi_ulong)
+#define TARGET_BLKBSZSET TARGET_IOW(0x12, 113, abi_ulong)
#define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,abi_ulong)
/* return device size in bytes
(u64 *arg) */
@@ -2226,8 +2226,8 @@ struct target_eabi_flock64 {
#define TARGET_SNDCTL_DSP_GETTRIGGER TARGET_IOR('P',16, int)
#define TARGET_SNDCTL_DSP_GETIPTR TARGET_IORU('P',17)
#define TARGET_SNDCTL_DSP_GETOPTR TARGET_IORU('P',18)
-#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013
-#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014
+#define TARGET_SNDCTL_DSP_MAPINBUF TARGET_IORU('P', 19)
+#define TARGET_SNDCTL_DSP_MAPOUTBUF TARGET_IORU('P', 20)
#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e
#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005
#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index 601618d..44b6a58 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -77,6 +77,9 @@ STRUCT(audio_buf_info,
STRUCT(count_info,
TYPE_INT, TYPE_INT, TYPE_INT)
+STRUCT(buffmem_desc,
+ TYPE_PTRVOID, TYPE_INT)
+
STRUCT(mixer_info,
MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10))
diff --git a/memory.c b/memory.c
index 643871b..d528d1f 100644
--- a/memory.c
+++ b/memory.c
@@ -426,7 +426,7 @@ static void memory_region_iorange_write(IORange *iorange,
if (mrp) {
mrp->write(mr->opaque, offset, data);
} else if (width == 2) {
- mrp = find_portio(mr, offset - mrio->offset, 1, false);
+ mrp = find_portio(mr, offset - mrio->offset, 1, true);
assert(mrp);
mrp->write(mr->opaque, offset, data & 0xff);
mrp->write(mr->opaque, offset + 1, data >> 8);
diff --git a/migration-tcp.c b/migration-tcp.c
index 440804d..ac891c3 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -82,27 +82,23 @@ static void tcp_wait_for_connect(void *opaque)
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
Error **errp)
{
+ bool in_progress;
+
s->get_error = socket_errno;
s->write = socket_write;
s->close = tcp_close;
- s->fd = inet_connect(host_port, false, errp);
+ s->fd = inet_connect(host_port, false, &in_progress, errp);
+ if (error_is_set(errp)) {
+ migrate_fd_error(s);
+ return -1;
+ }
- if (!error_is_set(errp)) {
- migrate_fd_connect(s);
- } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) {
+ if (in_progress) {
DPRINTF("connect in progress\n");
qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
- } else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) {
- DPRINTF("connect failed\n");
- return -1;
- } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED)) {
- DPRINTF("connect failed\n");
- migrate_fd_error(s);
- return -1;
} else {
- DPRINTF("unknown error\n");
- return -1;
+ migrate_fd_connect(s);
}
return 0;
diff --git a/migration.c b/migration.c
index 8db1b43..1edeec5 100644
--- a/migration.c
+++ b/migration.c
@@ -43,6 +43,9 @@ enum {
#define MAX_THROTTLE (32 << 20) /* Migration speed throttling */
+/* Migration XBZRLE default cache size */
+#define DEFAULT_MIGRATE_CACHE_SIZE (64 * 1024 * 1024)
+
static NotifierList migration_state_notifiers =
NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
@@ -55,6 +58,7 @@ static MigrationState *migrate_get_current(void)
static MigrationState current_migration = {
.state = MIG_STATE_SETUP,
.bandwidth_limit = MAX_THROTTLE,
+ .xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE,
};
return &current_migration;
@@ -113,6 +117,43 @@ uint64_t migrate_max_downtime(void)
return max_downtime;
}
+MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
+{
+ MigrationCapabilityStatusList *head = NULL;
+ MigrationCapabilityStatusList *caps;
+ MigrationState *s = migrate_get_current();
+ int i;
+
+ for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+ if (head == NULL) {
+ head = g_malloc0(sizeof(*caps));
+ caps = head;
+ } else {
+ caps->next = g_malloc0(sizeof(*caps));
+ caps = caps->next;
+ }
+ caps->value =
+ g_malloc(sizeof(*caps->value));
+ caps->value->capability = i;
+ caps->value->state = s->enabled_capabilities[i];
+ }
+
+ return head;
+}
+
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+ if (migrate_use_xbzrle()) {
+ info->has_xbzrle_cache = true;
+ info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+ info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+ info->xbzrle_cache->bytes = xbzrle_mig_bytes_transferred();
+ info->xbzrle_cache->pages = xbzrle_mig_pages_transferred();
+ info->xbzrle_cache->cache_miss = xbzrle_mig_pages_cache_miss();
+ info->xbzrle_cache->overflow = xbzrle_mig_pages_overflow();
+ }
+}
+
MigrationInfo *qmp_query_migrate(Error **errp)
{
MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -125,14 +166,18 @@ MigrationInfo *qmp_query_migrate(Error **errp)
case MIG_STATE_ACTIVE:
info->has_status = true;
info->status = g_strdup("active");
+ info->has_total_time = true;
+ info->total_time = qemu_get_clock_ms(rt_clock)
+ - s->total_time;
info->has_ram = true;
info->ram = g_malloc0(sizeof(*info->ram));
info->ram->transferred = ram_bytes_transferred();
info->ram->remaining = ram_bytes_remaining();
info->ram->total = ram_bytes_total();
- info->ram->total_time = qemu_get_clock_ms(rt_clock)
- - s->total_time;
+ info->ram->duplicate = dup_mig_pages_transferred();
+ info->ram->normal = norm_mig_pages_transferred();
+ info->ram->normal_bytes = norm_mig_bytes_transferred();
if (blk_mig_active()) {
info->has_disk = true;
@@ -141,17 +186,24 @@ MigrationInfo *qmp_query_migrate(Error **errp)
info->disk->remaining = blk_mig_bytes_remaining();
info->disk->total = blk_mig_bytes_total();
}
+
+ get_xbzrle_cache_stats(info);
break;
case MIG_STATE_COMPLETED:
+ get_xbzrle_cache_stats(info);
+
info->has_status = true;
info->status = g_strdup("completed");
+ info->total_time = s->total_time;
info->has_ram = true;
info->ram = g_malloc0(sizeof(*info->ram));
info->ram->transferred = ram_bytes_transferred();
info->ram->remaining = 0;
info->ram->total = ram_bytes_total();
- info->ram->total_time = s->total_time;
+ info->ram->duplicate = dup_mig_pages_transferred();
+ info->ram->normal = norm_mig_pages_transferred();
+ info->ram->normal_bytes = norm_mig_bytes_transferred();
break;
case MIG_STATE_ERROR:
info->has_status = true;
@@ -166,6 +218,22 @@ MigrationInfo *qmp_query_migrate(Error **errp)
return info;
}
+void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+ Error **errp)
+{
+ MigrationState *s = migrate_get_current();
+ MigrationCapabilityStatusList *cap;
+
+ if (s->state == MIG_STATE_ACTIVE) {
+ error_set(errp, QERR_MIGRATION_ACTIVE);
+ return;
+ }
+
+ for (cap = params; cap; cap = cap->next) {
+ s->enabled_capabilities[cap->value->capability] = cap->value->state;
+ }
+}
+
/* shared migration helpers */
static int migrate_fd_cleanup(MigrationState *s)
@@ -375,10 +443,18 @@ static MigrationState *migrate_init(const MigrationParams *params)
{
MigrationState *s = migrate_get_current();
int64_t bandwidth_limit = s->bandwidth_limit;
+ bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+ int64_t xbzrle_cache_size = s->xbzrle_cache_size;
+
+ memcpy(enabled_capabilities, s->enabled_capabilities,
+ sizeof(enabled_capabilities));
memset(s, 0, sizeof(*s));
s->bandwidth_limit = bandwidth_limit;
s->params = *params;
+ memcpy(s->enabled_capabilities, enabled_capabilities,
+ sizeof(enabled_capabilities));
+ s->xbzrle_cache_size = xbzrle_cache_size;
s->bandwidth_limit = bandwidth_limit;
s->state = MIG_STATE_SETUP;
@@ -459,6 +535,25 @@ void qmp_migrate_cancel(Error **errp)
migrate_fd_cancel(migrate_get_current());
}
+void qmp_migrate_set_cache_size(int64_t value, Error **errp)
+{
+ MigrationState *s = migrate_get_current();
+
+ /* Check for truncation */
+ if (value != (size_t)value) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+ "exceeding address space");
+ return;
+ }
+
+ s->xbzrle_cache_size = xbzrle_cache_resize(value);
+}
+
+int64_t qmp_query_migrate_cache_size(Error **errp)
+{
+ return migrate_xbzrle_cache_size();
+}
+
void qmp_migrate_set_speed(int64_t value, Error **errp)
{
MigrationState *s;
@@ -478,3 +573,21 @@ void qmp_migrate_set_downtime(double value, Error **errp)
value = MAX(0, MIN(UINT64_MAX, value));
max_downtime = (uint64_t)value;
}
+
+int migrate_use_xbzrle(void)
+{
+ MigrationState *s;
+
+ s = migrate_get_current();
+
+ return s->enabled_capabilities[MIGRATION_CAPABILITY_XBZRLE];
+}
+
+int64_t migrate_xbzrle_cache_size(void)
+{
+ MigrationState *s;
+
+ s = migrate_get_current();
+
+ return s->xbzrle_cache_size;
+}
diff --git a/migration.h b/migration.h
index 57572a6..a9852fc 100644
--- a/migration.h
+++ b/migration.h
@@ -19,6 +19,7 @@
#include "notify.h"
#include "error.h"
#include "vmstate.h"
+#include "qapi-types.h"
struct MigrationParams {
bool blk;
@@ -39,6 +40,8 @@ struct MigrationState
void *opaque;
MigrationParams params;
int64_t total_time;
+ bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+ int64_t xbzrle_cache_size;
};
void process_incoming_migration(QEMUFile *f);
@@ -84,6 +87,15 @@ uint64_t ram_bytes_total(void);
extern SaveVMHandlers savevm_ram_handlers;
+uint64_t dup_mig_bytes_transferred(void);
+uint64_t dup_mig_pages_transferred(void);
+uint64_t norm_mig_bytes_transferred(void);
+uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
+
/**
* @migrate_add_blocker - prevent migration from proceeding
*
@@ -98,4 +110,13 @@ void migrate_add_blocker(Error *reason);
*/
void migrate_del_blocker(Error *reason);
+int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
+ uint8_t *dst, int dlen);
+int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen);
+
+int migrate_use_xbzrle(void);
+int64_t migrate_xbzrle_cache_size(void);
+
+int64_t xbzrle_cache_resize(int64_t new_size);
+
#endif
diff --git a/monitor.c b/monitor.c
index 49dccfe..b17b1bb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -140,6 +140,24 @@ struct mon_fd_t {
QLIST_ENTRY(mon_fd_t) next;
};
+/* file descriptor associated with a file descriptor set */
+typedef struct MonFdsetFd MonFdsetFd;
+struct MonFdsetFd {
+ int fd;
+ bool removed;
+ char *opaque;
+ QLIST_ENTRY(MonFdsetFd) next;
+};
+
+/* file descriptor set containing fds passed via SCM_RIGHTS */
+typedef struct MonFdset MonFdset;
+struct MonFdset {
+ int64_t id;
+ QLIST_HEAD(, MonFdsetFd) fds;
+ QLIST_HEAD(, MonFdsetFd) dup_fds;
+ QLIST_ENTRY(MonFdset) next;
+};
+
typedef struct MonitorControl {
QObject *id;
JSONMessageParser parser;
@@ -172,45 +190,17 @@ struct Monitor {
CPUArchState *mon_cpu;
BlockDriverCompletionFunc *password_completion_cb;
void *password_opaque;
-#ifdef CONFIG_DEBUG_MONITOR
- int print_calls_nr;
-#endif
QError *error;
QLIST_HEAD(,mon_fd_t) fds;
QLIST_ENTRY(Monitor) entry;
};
-#ifdef CONFIG_DEBUG_MONITOR
-#define MON_DEBUG(fmt, ...) do { \
- fprintf(stderr, "Monitor: "); \
- fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-
-static inline void mon_print_count_inc(Monitor *mon)
-{
- mon->print_calls_nr++;
-}
-
-static inline void mon_print_count_init(Monitor *mon)
-{
- mon->print_calls_nr = 0;
-}
-
-static inline int mon_print_count_get(const Monitor *mon)
-{
- return mon->print_calls_nr;
-}
-
-#else /* !CONFIG_DEBUG_MONITOR */
-#define MON_DEBUG(fmt, ...) do { } while (0)
-static inline void mon_print_count_inc(Monitor *mon) { }
-static inline void mon_print_count_init(Monitor *mon) { }
-static inline int mon_print_count_get(const Monitor *mon) { return 0; }
-#endif /* CONFIG_DEBUG_MONITOR */
-
/* QMP checker flags */
#define QMP_ACCEPT_UNKNOWNS 1
static QLIST_HEAD(mon_list, Monitor) mon_list;
+static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets;
+static int mon_refcount;
static mon_cmd_t mon_cmds[];
static mon_cmd_t info_cmds[];
@@ -299,8 +289,6 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
if (!mon)
return;
- mon_print_count_inc(mon);
-
if (monitor_ctrl_mode(mon)) {
return;
}
@@ -385,16 +373,26 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
QDECREF(json);
}
+static QDict *build_qmp_error_dict(const QError *err)
+{
+ QObject *obj;
+
+ obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }",
+ ErrorClass_lookup[err->err_class],
+ qerror_human(err));
+
+ return qobject_to_qdict(obj);
+}
+
static void monitor_protocol_emitter(Monitor *mon, QObject *data)
{
QDict *qmp;
trace_monitor_protocol_emitter(mon);
- qmp = qdict_new();
-
if (!monitor_has_error(mon)) {
/* success response */
+ qmp = qdict_new();
if (data) {
qobject_incref(data);
qdict_put_obj(qmp, "return", data);
@@ -404,9 +402,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
}
} else {
/* error response */
- qdict_put(mon->error->error, "desc", qerror_human(mon->error));
- qdict_put(qmp, "error", mon->error->error);
- QINCREF(mon->error->error);
+ qmp = build_qmp_error_dict(mon->error);
QDECREF(mon->error);
mon->error = NULL;
}
@@ -456,6 +452,7 @@ static const char *monitor_event_names[] = {
[QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
[QEVENT_SUSPEND] = "SUSPEND",
+ [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
[QEVENT_WAKEUP] = "WAKEUP",
[QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
};
@@ -2389,6 +2386,271 @@ int monitor_get_fd(Monitor *mon, const char *fdname)
return -1;
}
+static void monitor_fdset_cleanup(MonFdset *mon_fdset)
+{
+ MonFdsetFd *mon_fdset_fd;
+ MonFdsetFd *mon_fdset_fd_next;
+
+ QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) {
+ if (mon_fdset_fd->removed ||
+ (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) {
+ close(mon_fdset_fd->fd);
+ g_free(mon_fdset_fd->opaque);
+ QLIST_REMOVE(mon_fdset_fd, next);
+ g_free(mon_fdset_fd);
+ }
+ }
+
+ if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
+ QLIST_REMOVE(mon_fdset, next);
+ g_free(mon_fdset);
+ }
+}
+
+static void monitor_fdsets_cleanup(void)
+{
+ MonFdset *mon_fdset;
+ MonFdset *mon_fdset_next;
+
+ QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
+ monitor_fdset_cleanup(mon_fdset);
+ }
+}
+
+AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque,
+ const char *opaque, Error **errp)
+{
+ int fd;
+ Monitor *mon = cur_mon;
+ MonFdset *mon_fdset;
+ MonFdsetFd *mon_fdset_fd;
+ AddfdInfo *fdinfo;
+
+ fd = qemu_chr_fe_get_msgfd(mon->chr);
+ if (fd == -1) {
+ error_set(errp, QERR_FD_NOT_SUPPLIED);
+ goto error;
+ }
+
+ if (has_fdset_id) {
+ QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+ if (mon_fdset->id == fdset_id) {
+ break;
+ }
+ }
+ if (mon_fdset == NULL) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
+ "an existing fdset-id");
+ goto error;
+ }
+ } else {
+ int64_t fdset_id_prev = -1;
+ MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets);
+
+ /* Use first available fdset ID */
+ QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+ mon_fdset_cur = mon_fdset;
+ if (fdset_id_prev == mon_fdset_cur->id - 1) {
+ fdset_id_prev = mon_fdset_cur->id;
+ continue;
+ }
+ break;
+ }
+
+ mon_fdset = g_malloc0(sizeof(*mon_fdset));
+ mon_fdset->id = fdset_id_prev + 1;
+
+ /* The fdset list is ordered by fdset ID */
+ if (mon_fdset->id == 0) {
+ QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next);
+ } else if (mon_fdset->id < mon_fdset_cur->id) {
+ QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next);
+ } else {
+ QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next);
+ }
+ }
+
+ mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd));
+ mon_fdset_fd->fd = fd;
+ mon_fdset_fd->removed = false;
+ if (has_opaque) {
+ mon_fdset_fd->opaque = g_strdup(opaque);
+ }
+ QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next);
+
+ fdinfo = g_malloc0(sizeof(*fdinfo));
+ fdinfo->fdset_id = mon_fdset->id;
+ fdinfo->fd = mon_fdset_fd->fd;
+
+ return fdinfo;
+
+error:
+ if (fd != -1) {
+ close(fd);
+ }
+ return NULL;
+}
+
+void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
+{
+ MonFdset *mon_fdset;
+ MonFdsetFd *mon_fdset_fd;
+ char fd_str[60];
+
+ QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+ if (mon_fdset->id != fdset_id) {
+ continue;
+ }
+ QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
+ if (has_fd) {
+ if (mon_fdset_fd->fd != fd) {
+ continue;
+ }
+ mon_fdset_fd->removed = true;
+ break;
+ } else {
+ mon_fdset_fd->removed = true;
+ }
+ }
+ if (has_fd && !mon_fdset_fd) {
+ goto error;
+ }
+ monitor_fdset_cleanup(mon_fdset);
+ return;
+ }
+
+error:
+ if (has_fd) {
+ snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
+ fdset_id, fd);
+ } else {
+ snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id);
+ }
+ error_set(errp, QERR_FD_NOT_FOUND, fd_str);
+}
+
+FdsetInfoList *qmp_query_fdsets(Error **errp)
+{
+ MonFdset *mon_fdset;
+ MonFdsetFd *mon_fdset_fd;
+ FdsetInfoList *fdset_list = NULL;
+
+ QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+ FdsetInfoList *fdset_info = g_malloc0(sizeof(*fdset_info));
+ FdsetFdInfoList *fdsetfd_list = NULL;
+
+ fdset_info->value = g_malloc0(sizeof(*fdset_info->value));
+ fdset_info->value->fdset_id = mon_fdset->id;
+
+ QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
+ FdsetFdInfoList *fdsetfd_info;
+
+ fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info));
+ fdsetfd_info->value = g_malloc0(sizeof(*fdsetfd_info->value));
+ fdsetfd_info->value->fd = mon_fdset_fd->fd;
+ if (mon_fdset_fd->opaque) {
+ fdsetfd_info->value->has_opaque = true;
+ fdsetfd_info->value->opaque = g_strdup(mon_fdset_fd->opaque);
+ } else {
+ fdsetfd_info->value->has_opaque = false;
+ }
+
+ fdsetfd_info->next = fdsetfd_list;
+ fdsetfd_list = fdsetfd_info;
+ }
+
+ fdset_info->value->fds = fdsetfd_list;
+
+ fdset_info->next = fdset_list;
+ fdset_list = fdset_info;
+ }
+
+ return fdset_list;
+}
+
+int monitor_fdset_get_fd(int64_t fdset_id, int flags)
+{
+#ifndef _WIN32
+ MonFdset *mon_fdset;
+ MonFdsetFd *mon_fdset_fd;
+ int mon_fd_flags;
+
+ QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+ if (mon_fdset->id != fdset_id) {
+ continue;
+ }
+ QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
+ mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
+ if (mon_fd_flags == -1) {
+ return -1;
+ }
+
+ if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
+ return mon_fdset_fd->fd;
+ }
+ }
+ errno = EACCES;
+ return -1;
+ }
+#endif
+
+ errno = ENOENT;
+ return -1;
+}
+
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+ MonFdset *mon_fdset;
+ MonFdsetFd *mon_fdset_fd_dup;
+
+ QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+ if (mon_fdset->id != fdset_id) {
+ continue;
+ }
+ QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
+ if (mon_fdset_fd_dup->fd == dup_fd) {
+ return -1;
+ }
+ }
+ mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
+ mon_fdset_fd_dup->fd = dup_fd;
+ QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
+ return 0;
+ }
+ return -1;
+}
+
+static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
+{
+ MonFdset *mon_fdset;
+ MonFdsetFd *mon_fdset_fd_dup;
+
+ QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
+ QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
+ if (mon_fdset_fd_dup->fd == dup_fd) {
+ if (remove) {
+ QLIST_REMOVE(mon_fdset_fd_dup, next);
+ if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
+ monitor_fdset_cleanup(mon_fdset);
+ }
+ }
+ return mon_fdset->id;
+ }
+ }
+ }
+ return -1;
+}
+
+int monitor_fdset_dup_fd_find(int dup_fd)
+{
+ return monitor_fdset_dup_fd_find_remove(dup_fd, false);
+}
+
+int monitor_fdset_dup_fd_remove(int dup_fd)
+{
+ return monitor_fdset_dup_fd_find_remove(dup_fd, true);
+}
+
/* mon_cmds and info_cmds would be sorted at runtime */
static mon_cmd_t mon_cmds[] = {
#include "hmp-commands.h"
@@ -2655,6 +2917,20 @@ static mon_cmd_t info_cmds[] = {
.mhandler.info = hmp_info_migrate,
},
{
+ .name = "migrate_capabilities",
+ .args_type = "",
+ .params = "",
+ .help = "show current migration capabilities",
+ .mhandler.info = hmp_info_migrate_capabilities,
+ },
+ {
+ .name = "migrate_cache_size",
+ .args_type = "",
+ .params = "",
+ .help = "show current migration xbzrle cache size",
+ .mhandler.info = hmp_info_migrate_cache_size,
+ },
+ {
.name = "balloon",
.args_type = "",
.params = "",
@@ -3860,8 +4136,6 @@ void monitor_set_error(Monitor *mon, QError *qerror)
if (!mon->error) {
mon->error = qerror;
} else {
- MON_DEBUG("Additional error report at %s:%d\n",
- qerror->file, qerror->linenr);
QDECREF(qerror);
}
}
@@ -3875,36 +4149,7 @@ static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
* Action: Report an internal error to the client if in QMP.
*/
qerror_report(QERR_UNDEFINED_ERROR);
- MON_DEBUG("command '%s' returned failure but did not pass an error\n",
- cmd->name);
- }
-
-#ifdef CONFIG_DEBUG_MONITOR
- if (!ret && monitor_has_error(mon)) {
- /*
- * If it returns success, it must not have passed an error.
- *
- * Action: Report the passed error to the client.
- */
- MON_DEBUG("command '%s' returned success but passed an error\n",
- cmd->name);
}
-
- if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
- /*
- * Handlers should not call Monitor print functions.
- *
- * Action: Ignore them in QMP.
- *
- * (XXX: we don't check any 'info' or 'query' command here
- * because the user print function _is_ called by do_info(), hence
- * we will trigger this check. This problem will go away when we
- * make 'query' commands real and kill do_info())
- */
- MON_DEBUG("command '%s' called print functions %d time(s)\n",
- cmd->name, mon_print_count_get(mon));
- }
-#endif
}
static void handle_user_command(Monitor *mon, const char *cmdline)
@@ -4433,8 +4678,6 @@ static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
int ret;
QObject *data = NULL;
- mon_print_count_init(mon);
-
ret = cmd->mhandler.cmd_new(mon, params, &data);
handler_audit(mon, cmd, ret);
monitor_protocol_emitter(mon, data);
@@ -4589,13 +4832,16 @@ static void monitor_control_event(void *opaque, int event)
switch (event) {
case CHR_EVENT_OPENED:
mon->mc->command_mode = 0;
- json_message_parser_init(&mon->mc->parser, handle_qmp_command);
data = get_qmp_greeting();
monitor_json_emitter(mon, data);
qobject_decref(data);
+ mon_refcount++;
break;
case CHR_EVENT_CLOSED:
json_message_parser_destroy(&mon->mc->parser);
+ json_message_parser_init(&mon->mc->parser, handle_qmp_command);
+ mon_refcount--;
+ monitor_fdsets_cleanup();
break;
}
}
@@ -4636,6 +4882,12 @@ static void monitor_event(void *opaque, int event)
readline_show_prompt(mon->rs);
}
mon->reset_seen = 1;
+ mon_refcount++;
+ break;
+
+ case CHR_EVENT_CLOSED:
+ mon_refcount--;
+ monitor_fdsets_cleanup();
break;
}
}
@@ -4694,6 +4946,8 @@ void monitor_init(CharDriverState *chr, int flags)
qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
monitor_control_event, mon);
qemu_chr_fe_set_echo(chr, true);
+
+ json_message_parser_init(&mon->mc->parser, handle_qmp_command);
} else {
qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
monitor_event, mon);
diff --git a/monitor.h b/monitor.h
index 5f4de1b..47d556b 100644
--- a/monitor.h
+++ b/monitor.h
@@ -40,6 +40,7 @@ typedef enum MonitorEvent {
QEVENT_BLOCK_JOB_CANCELLED,
QEVENT_DEVICE_TRAY_MOVED,
QEVENT_SUSPEND,
+ QEVENT_SUSPEND_DISK,
QEVENT_WAKEUP,
QEVENT_BALLOON_CHANGE,
@@ -86,4 +87,9 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret);
+int monitor_fdset_get_fd(int64_t fdset_id, int flags);
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
+int monitor_fdset_dup_fd_remove(int dup_fd);
+int monitor_fdset_dup_fd_find(int dup_fd);
+
#endif /* !MONITOR_H */
diff --git a/nbd.c b/nbd.c
index dc0adf9..0dd60c5 100644
--- a/nbd.c
+++ b/nbd.c
@@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port)
int tcp_socket_outgoing_spec(const char *address_and_port)
{
- return inet_connect(address_and_port, true, NULL);
+ return inet_connect(address_and_port, true, NULL, NULL);
}
int tcp_socket_incoming(const char *address, uint16_t port)
diff --git a/osdep.c b/osdep.c
index c07faf5..3b25297 100644
--- a/osdep.c
+++ b/osdep.c
@@ -48,6 +48,7 @@ extern int madvise(caddr_t, size_t, int);
#include "qemu-common.h"
#include "trace.h"
#include "qemu_socket.h"
+#include "monitor.h"
static bool fips_enabled = false;
@@ -78,6 +79,72 @@ int qemu_madvise(void *addr, size_t len, int advice)
#endif
}
+#ifndef _WIN32
+/*
+ * Dups an fd and sets the flags
+ */
+static int qemu_dup_flags(int fd, int flags)
+{
+ int ret;
+ int serrno;
+ int dup_flags;
+ int setfl_flags;
+
+#ifdef F_DUPFD_CLOEXEC
+ ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+#else
+ ret = dup(fd);
+ if (ret != -1) {
+ qemu_set_cloexec(ret);
+ }
+#endif
+ if (ret == -1) {
+ goto fail;
+ }
+
+ dup_flags = fcntl(ret, F_GETFL);
+ if (dup_flags == -1) {
+ goto fail;
+ }
+
+ if ((flags & O_SYNC) != (dup_flags & O_SYNC)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ /* Set/unset flags that we can with fcntl */
+ setfl_flags = O_APPEND | O_ASYNC | O_NONBLOCK;
+#ifdef O_NOATIME
+ setfl_flags |= O_NOATIME;
+#endif
+#ifdef O_DIRECT
+ setfl_flags |= O_DIRECT;
+#endif
+ dup_flags &= ~setfl_flags;
+ dup_flags |= (flags & setfl_flags);
+ if (fcntl(ret, F_SETFL, dup_flags) == -1) {
+ goto fail;
+ }
+
+ /* Truncate the file in the cases that open() would truncate it */
+ if (flags & O_TRUNC ||
+ ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
+ if (ftruncate(ret, 0) == -1) {
+ goto fail;
+ }
+ }
+
+ return ret;
+
+fail:
+ serrno = errno;
+ if (ret != -1) {
+ close(ret);
+ }
+ errno = serrno;
+ return -1;
+}
+#endif
/*
* Opens a file with FD_CLOEXEC set
@@ -87,6 +154,41 @@ int qemu_open(const char *name, int flags, ...)
int ret;
int mode = 0;
+#ifndef _WIN32
+ const char *fdset_id_str;
+
+ /* Attempt dup of fd from fd set */
+ if (strstart(name, "/dev/fdset/", &fdset_id_str)) {
+ int64_t fdset_id;
+ int fd, dupfd;
+
+ fdset_id = qemu_parse_fdset(fdset_id_str);
+ if (fdset_id == -1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = monitor_fdset_get_fd(fdset_id, flags);
+ if (fd == -1) {
+ return -1;
+ }
+
+ dupfd = qemu_dup_flags(fd, flags);
+ if (dupfd == -1) {
+ return -1;
+ }
+
+ ret = monitor_fdset_dup_fd_add(fdset_id, dupfd);
+ if (ret == -1) {
+ close(dupfd);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return dupfd;
+ }
+#endif
+
if (flags & O_CREAT) {
va_list ap;
@@ -107,6 +209,26 @@ int qemu_open(const char *name, int flags, ...)
return ret;
}
+int qemu_close(int fd)
+{
+ int64_t fdset_id;
+
+ /* Close fd that was dup'd from an fdset */
+ fdset_id = monitor_fdset_dup_fd_find(fd);
+ if (fdset_id != -1) {
+ int ret;
+
+ ret = close(fd);
+ if (ret == 0) {
+ monitor_fdset_dup_fd_remove(fd);
+ }
+
+ return ret;
+ }
+
+ return close(fd);
+}
+
/*
* A variant of write(2) which handles partial write.
*
diff --git a/osdep.h b/osdep.h
index d4b887d..cb213e0 100644
--- a/osdep.h
+++ b/osdep.h
@@ -103,6 +103,11 @@ void qemu_vfree(void *ptr);
#else
#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID
#endif
+#ifdef MADV_DONTDUMP
+#define QEMU_MADV_DONTDUMP MADV_DONTDUMP
+#else
+#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID
+#endif
#elif defined(CONFIG_POSIX_MADVISE)
@@ -110,6 +115,7 @@ void qemu_vfree(void *ptr);
#define QEMU_MADV_DONTNEED POSIX_MADV_DONTNEED
#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID
#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID
+#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID
#else /* no-op */
@@ -117,6 +123,7 @@ void qemu_vfree(void *ptr);
#define QEMU_MADV_DONTNEED QEMU_MADV_INVALID
#define QEMU_MADV_DONTFORK QEMU_MADV_INVALID
#define QEMU_MADV_MERGEABLE QEMU_MADV_INVALID
+#define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID
#endif
diff --git a/page_cache.c b/page_cache.c
new file mode 100644
index 0000000..0294f7e
--- /dev/null
+++ b/page_cache.c
@@ -0,0 +1,218 @@
+/*
+ * Page cache for QEMU
+ * The cache is base on a hash of the page address
+ *
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Orit Wasserman <owasserm@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <strings.h>
+
+#include "qemu-common.h"
+#include "qemu/page_cache.h"
+
+#ifdef DEBUG_CACHE
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stdout, "cache: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+ do { } while (0)
+#endif
+
+typedef struct CacheItem CacheItem;
+
+struct CacheItem {
+ uint64_t it_addr;
+ uint64_t it_age;
+ uint8_t *it_data;
+};
+
+struct PageCache {
+ CacheItem *page_cache;
+ unsigned int page_size;
+ int64_t max_num_items;
+ uint64_t max_item_age;
+ int64_t num_items;
+};
+
+PageCache *cache_init(int64_t num_pages, unsigned int page_size)
+{
+ int64_t i;
+
+ PageCache *cache;
+
+ if (num_pages <= 0) {
+ DPRINTF("invalid number of pages\n");
+ return NULL;
+ }
+
+ cache = g_malloc(sizeof(*cache));
+
+ /* round down to the nearest power of 2 */
+ if (!is_power_of_2(num_pages)) {
+ num_pages = pow2floor(num_pages);
+ DPRINTF("rounding down to %" PRId64 "\n", num_pages);
+ }
+ cache->page_size = page_size;
+ cache->num_items = 0;
+ cache->max_item_age = 0;
+ cache->max_num_items = num_pages;
+
+ DPRINTF("Setting cache buckets to %" PRId64 "\n", cache->max_num_items);
+
+ cache->page_cache = g_malloc((cache->max_num_items) *
+ sizeof(*cache->page_cache));
+
+ for (i = 0; i < cache->max_num_items; i++) {
+ cache->page_cache[i].it_data = NULL;
+ cache->page_cache[i].it_age = 0;
+ cache->page_cache[i].it_addr = -1;
+ }
+
+ return cache;
+}
+
+void cache_fini(PageCache *cache)
+{
+ int64_t i;
+
+ g_assert(cache);
+ g_assert(cache->page_cache);
+
+ for (i = 0; i < cache->max_num_items; i++) {
+ g_free(cache->page_cache[i].it_data);
+ }
+
+ g_free(cache->page_cache);
+ cache->page_cache = NULL;
+}
+
+static size_t cache_get_cache_pos(const PageCache *cache,
+ uint64_t address)
+{
+ size_t pos;
+
+ g_assert(cache->max_num_items);
+ pos = (address / cache->page_size) & (cache->max_num_items - 1);
+ return pos;
+}
+
+bool cache_is_cached(const PageCache *cache, uint64_t addr)
+{
+ size_t pos;
+
+ g_assert(cache);
+ g_assert(cache->page_cache);
+
+ pos = cache_get_cache_pos(cache, addr);
+
+ return (cache->page_cache[pos].it_addr == addr);
+}
+
+static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr)
+{
+ size_t pos;
+
+ g_assert(cache);
+ g_assert(cache->page_cache);
+
+ pos = cache_get_cache_pos(cache, addr);
+
+ return &cache->page_cache[pos];
+}
+
+uint8_t *get_cached_data(const PageCache *cache, uint64_t addr)
+{
+ return cache_get_by_addr(cache, addr)->it_data;
+}
+
+void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata)
+{
+
+ CacheItem *it = NULL;
+
+ g_assert(cache);
+ g_assert(cache->page_cache);
+
+ /* actual update of entry */
+ it = cache_get_by_addr(cache, addr);
+
+ if (!it->it_data) {
+ cache->num_items++;
+ }
+
+ it->it_data = pdata;
+ it->it_age = ++cache->max_item_age;
+ it->it_addr = addr;
+}
+
+int64_t cache_resize(PageCache *cache, int64_t new_num_pages)
+{
+ PageCache *new_cache;
+ int64_t i;
+
+ CacheItem *old_it, *new_it;
+
+ g_assert(cache);
+
+ /* cache was not inited */
+ if (cache->page_cache == NULL) {
+ return -1;
+ }
+
+ /* same size */
+ if (pow2floor(new_num_pages) == cache->max_num_items) {
+ return cache->max_num_items;
+ }
+
+ new_cache = cache_init(new_num_pages, cache->page_size);
+ if (!(new_cache)) {
+ DPRINTF("Error creating new cache\n");
+ return -1;
+ }
+
+ /* move all data from old cache */
+ for (i = 0; i < cache->max_num_items; i++) {
+ old_it = &cache->page_cache[i];
+ if (old_it->it_addr != -1) {
+ /* check for collision, if there is, keep MRU page */
+ new_it = cache_get_by_addr(new_cache, old_it->it_addr);
+ if (new_it->it_data) {
+ /* keep the MRU page */
+ if (new_it->it_age >= old_it->it_age) {
+ g_free(old_it->it_data);
+ } else {
+ g_free(new_it->it_data);
+ new_it->it_data = old_it->it_data;
+ new_it->it_age = old_it->it_age;
+ new_it->it_addr = old_it->it_addr;
+ }
+ } else {
+ cache_insert(new_cache, old_it->it_addr, old_it->it_data);
+ }
+ }
+ }
+
+ cache->page_cache = new_cache->page_cache;
+ cache->max_num_items = new_cache->max_num_items;
+ cache->num_items = new_cache->num_items;
+
+ g_free(new_cache);
+
+ return cache->max_num_items;
+}
diff --git a/pc-bios/README b/pc-bios/README
index e56e9e5..3037130 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -12,12 +12,12 @@
1275-1994 (referred to as Open Firmware) compliant firmware.
The included images for PowerPC (for 32 and 64 bit PPC CPUs),
Sparc32 and Sparc64 are built from OpenBIOS SVN revision
- 1060.
+ 1063.
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/dgibson/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20120217.
+ built from git tag qemu-slof-20120731.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/qapi-schema.json b/qapi-schema.json
index bd9c450..bd8ad74 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3,6 +3,36 @@
# QAPI Schema
##
+# @ErrorClass
+#
+# QEMU error classes
+#
+# @GenericError: this is used for errors that don't require a specific error
+# class. This should be the default case for most errors
+#
+# @CommandNotFound: the requested command has not been found
+#
+# @DeviceEncrypted: the requested operation can't be fulfilled because the
+# selected device is encrypted
+#
+# @DeviceNotActive: a device has failed to be become active
+#
+# @DeviceNotFound: the requested device has not been found
+#
+# @KVMMissingCap: the requested operation can't be fulfilled because a
+# required KVM capability is missing
+#
+# @MigrationExpected: the requested operation can't be fulfilled because a
+# migration process is expected
+#
+# Since: 1.2
+##
+{ 'enum': 'ErrorClass',
+ 'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted',
+ 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap',
+ 'MigrationExpected' ] }
+
+##
# @NameInfo:
#
# Guest name information.
@@ -260,15 +290,38 @@
#
# @total: total amount of bytes involved in the migration process
#
-# @total_time: tota0l amount of ms since migration started. If
-# migration has ended, it returns the total migration
-# time. (since 1.2)
+# @duplicate: number of duplicate pages (since 1.2)
#
-# Since: 0.14.0.
+# @normal : number of normal pages (since 1.2)
+#
+# @normal-bytes : number of normal bytes sent (since 1.2)
+#
+# Since: 0.14.0
##
{ 'type': 'MigrationStats',
'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
- 'total_time': 'int' } }
+ 'duplicate': 'int', 'normal': 'int', 'normal-bytes': 'int' } }
+
+##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache-size: XBZRLE cache size
+#
+# @bytes: amount of bytes already transferred to the target VM
+#
+# @pages: amount of pages transferred to the target VM
+#
+# @cache-miss: number of cache miss
+#
+# @overflow: number of overflows
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+ 'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int',
+ 'cache-miss': 'int', 'overflow': 'int' } }
##
# @MigrationInfo
@@ -288,11 +341,21 @@
# status, only returned if status is 'active' and it is a block
# migration
#
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# migration statistics, only returned if XBZRLE feature is on and
+# status is 'active' or 'completed' (since 1.2)
+#
+# @total-time: #optional total amount of milliseconds since migration started.
+# If migration has ended, it returns the total migration
+# time. (since 1.2)
+#
# Since: 0.14.0
##
{ 'type': 'MigrationInfo',
'data': {'*status': 'str', '*ram': 'MigrationStats',
- '*disk': 'MigrationStats'} }
+ '*disk': 'MigrationStats',
+ '*xbzrle-cache': 'XBZRLECacheStats',
+ '*total-time': 'int'} }
##
# @query-migrate
@@ -306,6 +369,57 @@
{ 'command': 'query-migrate', 'returns': 'MigrationInfo' }
##
+# @MigrationCapability
+#
+# Migration capabilities enumeration
+#
+# @xbzrle: Migration supports xbzrle (Xor Based Zero Run Length Encoding).
+# This feature allows us to minimize migration traffic for certain work
+# loads, by sending compressed difference of the pages
+#
+# Since: 1.2
+##
+{ 'enum': 'MigrationCapability',
+ 'data': ['xbzrle'] }
+
+##
+# @MigrationCapabilityStatus
+#
+# Migration capability information
+#
+# @capability: capability enum
+#
+# @state: capability state bool
+#
+# Since: 1.2
+##
+{ 'type': 'MigrationCapabilityStatus',
+ 'data': { 'capability' : 'MigrationCapability', 'state' : 'bool' } }
+
+##
+# @migrate-set-capabilities
+#
+# Enable/Disable the following migration capabilities (like xbzrle)
+#
+# @capabilities: json array of capability modifications to make
+#
+# Since: 1.2
+##
+{ 'command': 'migrate-set-capabilities',
+ 'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
+
+##
+# @query-migrate-capabilities
+#
+# Returns information about the current migration capabilities status
+#
+# Returns: @MigrationCapabilitiesStatus
+#
+# Since: 1.2
+##
+{ 'command': 'query-migrate-capabilities', 'returns': ['MigrationCapabilityStatus']}
+
+##
# @MouseInfo:
#
# Information about a mouse device.
@@ -402,6 +516,9 @@
#
# @encrypted: true if the backing device is encrypted
#
+# @encryption_key_missing: true if the backing device is encrypted but an
+# valid encryption key is missing
+#
# @bps: total throughput limit in bytes per second is specified
#
# @bps_rd: read throughput limit in bytes per second is specified
@@ -421,9 +538,9 @@
{ 'type': 'BlockDeviceInfo',
'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
'*backing_file': 'str', 'backing_file_depth': 'int',
- 'encrypted': 'bool', 'bps': 'int', 'bps_rd': 'int',
- 'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int',
- 'iops_wr': 'int'} }
+ 'encrypted': 'bool', 'encryption_key_missing': 'bool',
+ 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
+ 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
##
# @BlockDeviceIoStatus:
@@ -625,7 +742,6 @@
# Returns information about the current VNC server
#
# Returns: @VncInfo
-# If VNC support is not compiled in, FeatureDisabled
#
# Since: 0.14.0
##
@@ -1009,9 +1125,6 @@
# virtual address (defaults to CPU 0)
#
# Returns: Nothing on success
-# If @cpu is not a valid VCPU, InvalidParameterValue
-# If @filename cannot be opened, OpenFileFailed
-# If an I/O error occurs while writing the file, IOError
#
# Since: 0.14.0
#
@@ -1032,8 +1145,6 @@
# @filename: the file to save the memory to as binary data
#
# Returns: Nothing on success
-# If @filename cannot be opened, OpenFileFailed
-# If an I/O error occurs while writing the file, IOError
#
# Since: 0.14.0
#
@@ -1075,7 +1186,6 @@
# Injects an Non-Maskable Interrupt into all guest's VCPUs.
#
# Returns: If successful, nothing
-# If the Virtual Machine doesn't support NMI injection, Unsupported
#
# Since: 0.14.0
#
@@ -1126,7 +1236,6 @@
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
# If @device is not encrypted, DeviceNotEncrypted
-# If @password is not valid for this device, InvalidPassword
#
# Notes: Not all block formats support encryption and some that do are not
# able to validate that a password is correct. Disk corruption may
@@ -1167,11 +1276,6 @@
#
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
-# If @size is negative, InvalidParameterValue
-# If the block device has no medium inserted, DeviceHasNoMedium
-# If the block device does not support resize, Unsupported
-# If the block device is read-only, DeviceIsReadOnly
-# If a long-running operation is using the device, DeviceInUse
#
# Since: 0.14.0
##
@@ -1233,10 +1337,6 @@
#
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
-# If @device is busy, DeviceInUse will be returned
-# If @snapshot-file can't be created, OpenFileFailed
-# If @snapshot-file can't be opened, OpenFileFailed
-# If @format is invalid, InvalidBlockFormat
#
# Note: The transaction aborts on the first failure. Therefore, there will
# be only one device or snapshot file returned in an error condition, and
@@ -1265,8 +1365,6 @@
#
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
-# If @snapshot-file can't be opened, OpenFileFailed
-# If @format is invalid, InvalidBlockFormat
#
# Since 0.14.0
##
@@ -1344,6 +1442,33 @@
{ 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
##
+# @migrate-set-cache-size
+#
+# Set XBZRLE cache size
+#
+# @value: cache size in bytes
+#
+# The size will be rounded down to the nearest power of 2.
+# The cache size can be modified before and during ongoing migration
+#
+# Returns: nothing on success
+#
+# Since: 1.2
+##
+{ 'command': 'migrate-set-cache-size', 'data': {'value': 'int'} }
+
+##
+# @query-migrate-cache-size
+#
+# query XBZRLE cache size
+#
+# Returns: XBZRLE cache size in bytes
+#
+# Since: 1.2
+##
+{ 'command': 'query-migrate-cache-size', 'returns': 'int' }
+
+##
# @ObjectPropertyInfo:
#
# @name: the name of the property
@@ -1363,9 +1488,7 @@
# 4) A link type in the form 'link<subtype>' where subtype is a qdev
# device type name. Link properties form the device model graph.
#
-# Since: 1.1
-#
-# Notes: This type is experimental. Its syntax may change in future releases.
+# Since: 1.2
##
{ 'type': 'ObjectPropertyInfo',
'data': { 'name': 'str', 'type': 'str' } }
@@ -1382,10 +1505,7 @@
# Returns: a list of @ObjectPropertyInfo that describe the properties of the
# object.
#
-# Since: 1.1
-#
-# Notes: This command is experimental. It's syntax may change in future
-# releases.
+# Since: 1.2
##
{ 'command': 'qom-list',
'data': { 'path': 'str' },
@@ -1421,9 +1541,7 @@
# returns as #str pathnames. All integer property types (u8, u16, etc)
# are returned as #int.
#
-# Since: 1.1
-#
-# Notes: This command is experimental and may change syntax in future releases.
+# Since: 1.2
##
{ 'command': 'qom-get',
'data': { 'path': 'str', 'property': 'str' },
@@ -1442,9 +1560,7 @@
# @value: a value who's type is appropriate for the property type. See @qom-get
# for a description of type mapping.
#
-# Since: 1.1
-#
-# Notes: This command is experimental and may change syntax in future releases.
+# Since: 1.2
##
{ 'command': 'qom-set',
'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
@@ -1468,11 +1584,6 @@
#
# Returns: Nothing on success
# If Spice is not enabled, DeviceNotFound
-# If @protocol does not support connected, InvalidParameter
-# If @protocol is invalid, InvalidParameter
-# If any other error occurs, SetPasswdFailed
-#
-# Notes: If VNC is not enabled, SetPasswdFailed is returned.
#
# Since: 0.14.0
##
@@ -1494,8 +1605,6 @@
#
# Returns: Nothing on success
# If @protocol is `spice' and Spice is not active, DeviceNotFound
-# If an error occurs setting password expiration, SetPasswdFailed
-# If @protocol is not `spice' or 'vnc', InvalidParameter
#
# Since: 0.14.0
#
@@ -1518,8 +1627,6 @@
#
# Returns: Nothing on success
# If @device is not a valid block device, DeviceNotFound
-# If @device is not removable and @force is false, DeviceNotRemovable
-# If @force is false and @device is locked, DeviceLocked
#
# Notes: Ejecting a device will no media results in success
#
@@ -1562,7 +1669,6 @@
#
# Returns: Nothing on success.
# If @device is not a valid block device, DeviceNotFound
-# If @format is not a valid block format, InvalidBlockFormat
# If the new block device is encrypted, DeviceEncrypted. Note that
# if this error is returned, the device has been opened successfully
# and an additional call to @block_passwd is required to set the
@@ -1598,7 +1704,6 @@
#
# Returns: Nothing on success
# If @device is not a valid block device, DeviceNotFound
-# If the argument combination is invalid, InvalidParameterCombination
#
# Since: 1.1
##
@@ -1632,11 +1737,7 @@
# @speed: #optional the maximum speed, in bytes per second
#
# Returns: Nothing on success
-# If streaming is already active on this device, DeviceInUse
# If @device does not exist, DeviceNotFound
-# If image streaming is not supported by this device, NotSupported
-# If @base does not exist, BaseNotFound
-# If @speed is invalid, InvalidParameter
#
# Since: 1.1
##
@@ -1658,8 +1759,6 @@
# Defaults to 0.
#
# Returns: Nothing on success
-# If the job type does not support throttling, NotSupported
-# If the speed value is invalid, InvalidParameter
# If no background operation is active on this device, DeviceNotActive
#
# Since: 1.1
@@ -1689,7 +1788,6 @@
#
# Returns: Nothing on success
# If no background operation is active on this device, DeviceNotActive
-# If cancellation already in progress, DeviceInUse
#
# Since: 1.1
##
@@ -1721,14 +1819,40 @@
# Returns: a list of @ObjectTypeInfo or an empty list if no results are found
#
# Since: 1.1
-#
-# Notes: This command is experimental and may change syntax in future releases.
##
{ 'command': 'qom-list-types',
'data': { '*implements': 'str', '*abstract': 'bool' },
'returns': [ 'ObjectTypeInfo' ] }
##
+# @DevicePropertyInfo:
+#
+# Information about device properties.
+#
+# @name: the name of the property
+# @type: the typename of the property
+#
+# Since: 1.2
+##
+{ 'type': 'DevicePropertyInfo',
+ 'data': { 'name': 'str', 'type': 'str' } }
+
+##
+# @device-list-properties:
+#
+# List properties associated with a device.
+#
+# @typename: the type name of a device
+#
+# Returns: a list of DevicePropertyInfo describing a devices properties
+#
+# Since: 1.2
+##
+{ 'command': 'device-list-properties',
+ 'data': { 'typename': 'str'},
+ 'returns': [ 'DevicePropertyInfo' ] }
+
+##
# @migrate
#
# Migrates the current running guest to another Virtual Machine.
@@ -1759,8 +1883,6 @@
# format.
#
# Returns: Nothing on success
-# If @filename cannot be opened, OpenFileFailed
-# If an I/O error occurs while writing the file, IOError
#
# Since: 1.1
##
@@ -1775,7 +1897,6 @@
#
# Returns: Nothing on success
# If @id is not a valid device, DeviceNotFound
-# If the device does not support unplug, BusNoHotplug
#
# Notes: When this command completes, the device may not be removed from the
# guest. Hot removal is an operation that requires guest cooperation.
@@ -1816,14 +1937,6 @@
# want to dump all guest's memory, please specify the start @begin and @length
#
# Returns: nothing on success
-# If @begin contains an invalid address, InvalidParameter
-# If only one of @begin and @length is specified, MissingParameter
-# If @protocol stats with "fd:", and the fd cannot be found, FdNotFound
-# If @protocol starts with "file:", and the file cannot be
-# opened, OpenFileFailed
-# If @protocol does not start with "fd:" or "file:", InvalidParameter
-# If an I/O error occurs while writing the file, IOError
-# If the target does not support this command, Unsupported
#
# Since: 1.2
##
@@ -1850,10 +1963,6 @@
#
# Returns: Nothing on success
# If @type is not a valid network backend, DeviceNotFound
-# If @id is not a valid identifier, InvalidParameterValue
-# if @id already exists, DuplicateId
-# If @props contains an invalid parameter for this backend,
-# InvalidParameter
##
{ 'command': 'netdev_add',
'data': {'type': 'str', 'id': 'str', '*props': '**'},
@@ -2173,8 +2282,6 @@
# @fdname: file descriptor name
#
# Returns: Nothing on success
-# If file descriptor was not received, FdNotSupplied
-# If @fdname is not valid, InvalidParameterType
#
# Since: 0.14.0
#
@@ -2194,8 +2301,195 @@
# @fdname: file descriptor name
#
# Returns: Nothing on success
-# If @fdname is not found, FdNotFound
#
# Since: 0.14.0
##
{ 'command': 'closefd', 'data': {'fdname': 'str'} }
+
+##
+# @MachineInfo:
+#
+# Information describing a machine.
+#
+# @name: the name of the machine
+#
+# @alias: #optional an alias for the machine name
+#
+# @default: #optional whether the machine is default
+#
+# Since: 1.2.0
+##
+{ 'type': 'MachineInfo',
+ 'data': { 'name': 'str', '*alias': 'str',
+ '*is-default': 'bool' } }
+
+##
+# @query-machines:
+#
+# Return a list of supported machines
+#
+# Returns: a list of MachineInfo
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-machines', 'returns': ['MachineInfo'] }
+
+##
+# @CpuDefinitionInfo:
+#
+# Virtual CPU definition.
+#
+# @name: the name of the CPU definition
+#
+# Since: 1.2.0
+##
+{ 'type': 'CpuDefinitionInfo',
+ 'data': { 'name': 'str' } }
+
+##
+# @query-cpu-definitions:
+#
+# Return a list of supported virtual CPU definitions
+#
+# Returns: a list of CpuDefInfo
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
+
+# @AddfdInfo:
+#
+# Information about a file descriptor that was added to an fd set.
+#
+# @fdset-id: The ID of the fd set that @fd was added to.
+#
+# @fd: The file descriptor that was received via SCM rights and
+# added to the fd set.
+#
+# Since: 1.2.0
+##
+{ 'type': 'AddfdInfo', 'data': {'fdset-id': 'int', 'fd': 'int'} }
+
+##
+# @add-fd:
+#
+# Add a file descriptor, that was passed via SCM rights, to an fd set.
+#
+# @fdset-id: #optional The ID of the fd set to add the file descriptor to.
+#
+# @opaque: #optional A free-form string that can be used to describe the fd.
+#
+# Returns: @AddfdInfo on success
+# If file descriptor was not received, FdNotSupplied
+# If @fdset-id does not exist, InvalidParameterValue
+#
+# Notes: The list of fd sets is shared by all monitor connections.
+#
+# If @fdset-id is not specified, a new fd set will be created.
+#
+# Since: 1.2.0
+##
+{ 'command': 'add-fd', 'data': {'*fdset-id': 'int', '*opaque': 'str'},
+ 'returns': 'AddfdInfo' }
+
+##
+# @remove-fd:
+#
+# Remove a file descriptor from an fd set.
+#
+# @fdset-id: The ID of the fd set that the file descriptor belongs to.
+#
+# @fd: #optional The file descriptor that is to be removed.
+#
+# Returns: Nothing on success
+# If @fdset-id or @fd is not found, FdNotFound
+#
+# Since: 1.2.0
+#
+# Notes: The list of fd sets is shared by all monitor connections.
+#
+# If @fd is not specified, all file descriptors in @fdset-id
+# will be removed.
+##
+{ 'command': 'remove-fd', 'data': {'fdset-id': 'int', '*fd': 'int'} }
+
+##
+# @FdsetFdInfo:
+#
+# Information about a file descriptor that belongs to an fd set.
+#
+# @fd: The file descriptor value.
+#
+# @opaque: #optional A free-form string that can be used to describe the fd.
+#
+# Since: 1.2.0
+##
+{ 'type': 'FdsetFdInfo',
+ 'data': {'fd': 'int', '*opaque': 'str'} }
+
+##
+# @FdsetInfo:
+#
+# Information about an fd set.
+#
+# @fdset-id: The ID of the fd set.
+#
+# @fds: A list of file descriptors that belong to this fd set.
+#
+# Since: 1.2.0
+##
+{ 'type': 'FdsetInfo',
+ 'data': {'fdset-id': 'int', 'fds': ['FdsetFdInfo']} }
+
+##
+# @query-fdsets:
+#
+# Return information describing all fd sets.
+#
+# Returns: A list of @FdsetInfo
+#
+# Since: 1.2.0
+#
+# Note: The list of fd sets is shared by all monitor connections.
+#
+##
+{ 'command': 'query-fdsets', 'returns': ['FdsetInfo'] }
+
+##
+# @TargetType
+#
+# Target CPU emulation type
+#
+# These parameters correspond to the softmmu binary CPU name that is currently
+# running.
+#
+# Since: 1.2.0
+##
+{ 'enum': 'TargetType',
+ 'data': [ 'alpha', 'arm', 'cris', 'i386', 'lm32', 'm68k', 'microblazeel',
+ 'microblaze', 'mips64el', 'mips64', 'mipsel', 'mips', 'or32',
+ 'ppc64', 'ppcemb', 'ppc', 's390x', 'sh4eb', 'sh4', 'sparc64',
+ 'sparc', 'unicore32', 'x86_64', 'xtensaeb', 'xtensa' ] }
+
+##
+# @TargetInfo:
+#
+# Information describing the QEMU target.
+#
+# @arch: the target architecture (eg "x86_64", "i386", etc)
+#
+# Since: 1.2.0
+##
+{ 'type': 'TargetInfo',
+ 'data': { 'arch': 'TargetType' } }
+
+##
+# @query-target:
+#
+# Return information about the target for this QEMU
+#
+# Returns: TargetInfo
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-target', 'returns': 'TargetInfo' }
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index a59d306..e048b6c 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -416,7 +416,7 @@ opts_visitor_cleanup(OptsVisitor *ov)
g_hash_table_destroy(ov->unprocessed_opts);
}
g_free(ov->fake_id_opt);
- memset(ov, '\0', sizeof *ov);
+ g_free(ov);
}
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
index b0f64ba..00446cf 100644
--- a/qapi/qmp-core.h
+++ b/qapi/qmp-core.h
@@ -49,6 +49,7 @@ void qmp_disable_command(const char *name);
void qmp_enable_command(const char *name);
bool qmp_command_is_enabled(const char *name);
char **qmp_get_command_list(void);
+QObject *qmp_build_error_object(Error *errp);
#endif
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 122c1a2..4085994 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -14,8 +14,8 @@
#include "qemu-objects.h"
#include "qapi/qmp-core.h"
#include "json-parser.h"
+#include "qapi-types.h"
#include "error.h"
-#include "error_int.h"
#include "qerror.h"
static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
@@ -109,6 +109,13 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
return ret;
}
+QObject *qmp_build_error_object(Error *errp)
+{
+ return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
+ ErrorClass_lookup[error_get_class(errp)],
+ error_get_pretty(errp));
+}
+
QObject *qmp_dispatch(QObject *request)
{
Error *err = NULL;
@@ -119,7 +126,7 @@ QObject *qmp_dispatch(QObject *request)
rsp = qdict_new();
if (err) {
- qdict_put_obj(rsp, "error", error_get_qobject(err));
+ qdict_put_obj(rsp, "error", qmp_build_error_object(err));
error_free(err);
} else if (ret) {
qdict_put_obj(rsp, "return", ret);
diff --git a/qemu-char.c b/qemu-char.c
index c2aaaee..398baf1 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2141,14 +2141,17 @@ typedef struct {
static void tcp_chr_accept(void *opaque);
+static void tcp_chr_connect(void *opaque);
+
static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
TCPCharDriver *s = chr->opaque;
if (s->connected) {
return send_all(s->fd, buf, len);
} else {
- /* XXX: indicate an error ? */
- return len;
+ /* (Re-)connect for unconnected writing */
+ tcp_chr_connect(chr);
+ return 0;
}
}
@@ -2238,6 +2241,9 @@ static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)
if (fd < 0)
continue;
+#ifndef MSG_CMSG_CLOEXEC
+ qemu_set_cloexec(fd);
+#endif
if (s->msgfd != -1)
close(s->msgfd);
s->msgfd = fd;
@@ -2253,6 +2259,7 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
struct cmsghdr cmsg;
char control[CMSG_SPACE(sizeof(int))];
} msg_control;
+ int flags = 0;
ssize_t ret;
iov[0].iov_base = buf;
@@ -2263,9 +2270,13 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
msg.msg_control = &msg_control;
msg.msg_controllen = sizeof(msg_control);
- ret = recvmsg(s->fd, &msg, 0);
- if (ret > 0 && s->is_unix)
+#ifdef MSG_CMSG_CLOEXEC
+ flags |= MSG_CMSG_CLOEXEC;
+#endif
+ ret = recvmsg(s->fd, &msg, flags);
+ if (ret > 0 && s->is_unix) {
unix_process_msgfd(chr, &msg);
+ }
return ret;
}
@@ -2446,7 +2457,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
if (is_listen) {
fd = inet_listen_opts(opts, 0, NULL);
} else {
- fd = inet_connect_opts(opts, NULL);
+ fd = inet_connect_opts(opts, NULL, NULL);
}
}
if (fd < 0) {
diff --git a/qemu-common.h b/qemu-common.h
index f16079f..e5c2bcd 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -1,3 +1,4 @@
+
/* Common header file that is included by all of qemu. */
#ifndef QEMU_COMMON_H
#define QEMU_COMMON_H
@@ -166,6 +167,7 @@ int qemu_fls(int i);
int qemu_fdatasync(int fd);
int fcntl_setfl(int fd, int flag);
int qemu_parse_fd(const char *param);
+int qemu_parse_fdset(const char *param);
/*
* strtosz() suffixes used to specify the default treatment of an
@@ -207,6 +209,7 @@ const char *path(const char *pathname);
void *qemu_oom_check(void *ptr);
int qemu_open(const char *name, int flags, ...);
+int qemu_close(int fd);
ssize_t qemu_write_full(int fd, const void *buf, size_t count)
QEMU_WARN_UNUSED_RESULT;
ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags)
@@ -376,6 +379,7 @@ bool buffer_is_zero(const void *buf, size_t len);
void qemu_progress_init(int enabled, float min_skip);
void qemu_progress_end(void);
void qemu_progress_print(float delta, int max);
+const char *qemu_get_vm_name(void);
#define QEMU_FILE_TYPE_BIOS 0
#define QEMU_FILE_TYPE_KEYMAP 1
@@ -428,6 +432,26 @@ static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
/* Round number up to multiple */
#define QEMU_ALIGN_UP(n, m) QEMU_ALIGN_DOWN((n) + (m) - 1, (m))
+static inline bool is_power_of_2(uint64_t value)
+{
+ if (!value) {
+ return 0;
+ }
+
+ return !(value & (value - 1));
+}
+
+/* round down to the nearest power of 2*/
+int64_t pow2floor(int64_t value);
+
#include "module.h"
+/*
+ * Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+ * Input is limited to 14-bit numbers
+ */
+
+int uleb128_encode_small(uint8_t *out, uint32_t n);
+int uleb128_decode_small(const uint8_t *in, uint32_t *n);
+
#endif
diff --git a/qemu-config.c b/qemu-config.c
index 5c3296b..c05ffbc 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -362,6 +362,19 @@ static QemuOptsList qemu_global_opts = {
},
};
+QemuOptsList qemu_sandbox_opts = {
+ .name = "sandbox",
+ .implied_opt_name = "enable",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head),
+ .desc = {
+ {
+ .name = "enable",
+ .type = QEMU_OPT_BOOL,
+ },
+ { /* end of list */ }
+ },
+};
+
static QemuOptsList qemu_mon_opts = {
.name = "mon",
.implied_opt_name = "chardev",
@@ -595,6 +608,10 @@ static QemuOptsList qemu_machine_opts = {
.name = "dt_compatible",
.type = QEMU_OPT_STRING,
.help = "Overrides the \"compatible\" property of the dt root node",
+ }, {
+ .name = "dump-guest-core",
+ .type = QEMU_OPT_BOOL,
+ .help = "Include guest memory in a core dump",
},
{ /* End of list */ }
},
@@ -641,6 +658,7 @@ static QemuOptsList *vm_config_groups[32] = {
&qemu_machine_opts,
&qemu_boot_opts,
&qemu_iscsi_opts,
+ &qemu_sandbox_opts,
NULL,
};
diff --git a/qemu-config.h b/qemu-config.h
index 12ddf3e..5557562 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -6,6 +6,7 @@
extern QemuOptsList qemu_fsdev_opts;
extern QemuOptsList qemu_virtfs_opts;
extern QemuOptsList qemu_spice_opts;
+extern QemuOptsList qemu_sandbox_opts;
QemuOptsList *qemu_find_opts(const char *group);
QemuOptsList *qemu_find_opts_err(const char *group, Error **errp);
diff --git a/qemu-doc.texi b/qemu-doc.texi
index f32e9e2..35cabbc 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -734,6 +734,11 @@ Various session related parameters can be set via special options, either
in a configuration file provided via '-readconfig' or directly on the
command line.
+If the initiator-name is not specified qemu will use a default name
+of 'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the
+virtual machine.
+
+
@example
Setting a specific initiator name to use when logging in to the target
-iscsi initiator-name=iqn.qemu.test:my-initiator
diff --git a/qemu-ga.c b/qemu-ga.c
index f1a39ec..7623079 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -28,7 +28,6 @@
#include "module.h"
#include "signal.h"
#include "qerror.h"
-#include "error_int.h"
#include "qapi/qmp-core.h"
#include "qga/channel.h"
#ifdef _WIN32
@@ -248,6 +247,9 @@ static bool ga_open_pidfile(const char *pidfile)
pidfd = open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
if (pidfd == -1 || lockf(pidfd, F_TLOCK, 0)) {
g_critical("Cannot lock pid file, %s", strerror(errno));
+ if (pidfd != -1) {
+ close(pidfd);
+ }
return false;
}
@@ -436,7 +438,9 @@ static void become_daemon(const char *pidfile)
return;
fail:
- unlink(pidfile);
+ if (pidfile) {
+ unlink(pidfile);
+ }
g_critical("failed to daemonize");
exit(EXIT_FAILURE);
#endif
@@ -515,7 +519,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
} else {
g_warning("failed to parse event: %s", error_get_pretty(err));
}
- qdict_put_obj(qdict, "error", error_get_qobject(err));
+ qdict_put_obj(qdict, "error", qmp_build_error_object(err));
error_free(err);
} else {
qdict = qobject_to_qdict(obj);
@@ -532,7 +536,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
qdict = qdict_new();
g_warning("unrecognized payload format");
error_set(&err, QERR_UNSUPPORTED);
- qdict_put_obj(qdict, "error", error_get_qobject(err));
+ qdict_put_obj(qdict, "error", qmp_build_error_object(err));
error_free(err);
}
ret = send_response(s, QOBJECT(qdict));
diff --git a/qemu-img.c b/qemu-img.c
index 94a31ad..b41e670 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -379,7 +379,7 @@ static int img_check(int argc, char **argv)
BlockDriverState *bs;
BdrvCheckResult result;
int fix = 0;
- int flags = BDRV_O_FLAGS;
+ int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
fmt = NULL;
for(;;) {
diff --git a/qemu-img.texi b/qemu-img.texi
index 77c6d0b..6b42e35 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -4,6 +4,16 @@ usage: qemu-img command [command options]
@c man end
@end example
+@c man begin DESCRIPTION
+qemu-img allows you to create, convert and modify images offline. It can handle
+all image formats supported by QEMU.
+
+@b{Warning:} Never use qemu-img to modify images in use by a running virtual
+machine or any other process; this may destroy the image. Also, be aware that
+querying an image that is being modified by another process may encounter
+inconsistent state.
+@c man end
+
@c man begin OPTIONS
The following commands are supported:
diff --git a/qemu-options.hx b/qemu-options.hx
index 5e7d0dc..3c411c4 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -37,7 +37,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
" property accel=accel1[:accel2[:...]] selects accelerator\n"
" supported accelerators are kvm, xen, tcg (default: tcg)\n"
" kernel_irqchip=on|off controls accelerated irqchip support\n"
- " kvm_shadow_mem=size of KVM shadow MMU\n",
+ " kvm_shadow_mem=size of KVM shadow MMU\n"
+ " dump-guest-core=on|off include guest memory in a core dump (default=on)\n",
QEMU_ARCH_ALL)
STEXI
@item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -54,6 +55,8 @@ to initialize.
Enables in-kernel irqchip support for the chosen accelerator when available.
@item kvm_shadow_mem=size
Defines the size of the KVM shadow MMU.
+@item dump-guest-core=on|off
+Include guest memory in a core dump. The default is on.
@end table
ETEXI
@@ -1897,6 +1900,11 @@ images for the guest storage. Both disk and cdrom images are supported.
Syntax for specifying iSCSI LUNs is
``iscsi://<target-ip>[:<port>]/<target-iqn>/<lun>''
+By default qemu will use the iSCSI initiator-name
+'iqn.2008-11.org.linux-kvm[:<name>]' but this can also be set from the command
+line or a configuration file.
+
+
Example (without authentication):
@example
qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
@@ -1926,6 +1934,9 @@ DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi,
" iSCSI session parameters\n", QEMU_ARCH_ALL)
STEXI
+iSCSI parameters such as username and password can also be specified via
+a configuration file. See qemu-doc for more information and examples.
+
@item NBD
QEMU supports NBD (Network Block Devices) both using TCP protocol as well
as Unix Domain Sockets.
@@ -2712,6 +2723,16 @@ STEXI
Old param mode (ARM only).
ETEXI
+DEF("sandbox", HAS_ARG, QEMU_OPTION_sandbox, \
+ "-sandbox <arg> Enable seccomp mode 2 system call filter (default 'off').\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -sandbox
+@findex -sandbox
+Enable Seccomp mode 2 system call filter. 'on' will enable syscall filtering and 'off' will
+disable it. The default is 'off'.
+ETEXI
+
DEF("readconfig", HAS_ARG, QEMU_OPTION_readconfig,
"-readconfig <file>\n", QEMU_ARCH_ALL)
STEXI
diff --git a/qemu-seccomp.c b/qemu-seccomp.c
new file mode 100644
index 0000000..64329a3
--- /dev/null
+++ b/qemu-seccomp.c
@@ -0,0 +1,141 @@
+/*
+ * QEMU seccomp mode 2 support with libseccomp
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Eduardo Otubo <eotubo@br.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+#include <stdio.h>
+#include <seccomp.h>
+#include "qemu-seccomp.h"
+
+struct QemuSeccompSyscall {
+ int32_t num;
+ uint8_t priority;
+};
+
+static const struct QemuSeccompSyscall seccomp_whitelist[] = {
+ { SCMP_SYS(timer_settime), 255 },
+ { SCMP_SYS(timer_gettime), 254 },
+ { SCMP_SYS(futex), 253 },
+ { SCMP_SYS(select), 252 },
+ { SCMP_SYS(recvfrom), 251 },
+ { SCMP_SYS(sendto), 250 },
+ { SCMP_SYS(read), 249 },
+ { SCMP_SYS(brk), 248 },
+ { SCMP_SYS(clone), 247 },
+ { SCMP_SYS(mmap), 247 },
+ { SCMP_SYS(mprotect), 246 },
+ { SCMP_SYS(execve), 245 },
+ { SCMP_SYS(open), 245 },
+ { SCMP_SYS(ioctl), 245 },
+ { SCMP_SYS(recvmsg), 245 },
+ { SCMP_SYS(sendmsg), 245 },
+ { SCMP_SYS(accept), 245 },
+ { SCMP_SYS(connect), 245 },
+ { SCMP_SYS(gettimeofday), 245 },
+ { SCMP_SYS(readlink), 245 },
+ { SCMP_SYS(access), 245 },
+ { SCMP_SYS(prctl), 245 },
+ { SCMP_SYS(signalfd), 245 },
+#if defined(__i386__)
+ { SCMP_SYS(fcntl64), 245 },
+ { SCMP_SYS(fstat64), 245 },
+ { SCMP_SYS(stat64), 245 },
+ { SCMP_SYS(getgid32), 245 },
+ { SCMP_SYS(getegid32), 245 },
+ { SCMP_SYS(getuid32), 245 },
+ { SCMP_SYS(geteuid32), 245 },
+ { SCMP_SYS(sigreturn), 245 },
+ { SCMP_SYS(_newselect), 245 },
+ { SCMP_SYS(_llseek), 245 },
+ { SCMP_SYS(mmap2), 245},
+ { SCMP_SYS(sigprocmask), 245 },
+#elif defined(__x86_64__)
+ { SCMP_SYS(sched_getparam), 245},
+ { SCMP_SYS(sched_getscheduler), 245},
+ { SCMP_SYS(fstat), 245},
+ { SCMP_SYS(clock_getres), 245},
+ { SCMP_SYS(sched_get_priority_min), 245},
+ { SCMP_SYS(sched_get_priority_max), 245},
+ { SCMP_SYS(stat), 245},
+ { SCMP_SYS(socket), 245},
+ { SCMP_SYS(setsockopt), 245},
+ { SCMP_SYS(uname), 245},
+ { SCMP_SYS(semget), 245},
+#endif
+ { SCMP_SYS(eventfd2), 245 },
+ { SCMP_SYS(dup), 245 },
+ { SCMP_SYS(gettid), 245 },
+ { SCMP_SYS(timer_create), 245 },
+ { SCMP_SYS(exit), 245 },
+ { SCMP_SYS(clock_gettime), 245 },
+ { SCMP_SYS(time), 245 },
+ { SCMP_SYS(restart_syscall), 245 },
+ { SCMP_SYS(pwrite64), 245 },
+ { SCMP_SYS(chown), 245 },
+ { SCMP_SYS(openat), 245 },
+ { SCMP_SYS(getdents), 245 },
+ { SCMP_SYS(timer_delete), 245 },
+ { SCMP_SYS(exit_group), 245 },
+ { SCMP_SYS(rt_sigreturn), 245 },
+ { SCMP_SYS(sync), 245 },
+ { SCMP_SYS(pread64), 245 },
+ { SCMP_SYS(madvise), 245 },
+ { SCMP_SYS(set_robust_list), 245 },
+ { SCMP_SYS(lseek), 245 },
+ { SCMP_SYS(pselect6), 245 },
+ { SCMP_SYS(fork), 245 },
+ { SCMP_SYS(bind), 245 },
+ { SCMP_SYS(listen), 245 },
+ { SCMP_SYS(eventfd), 245 },
+ { SCMP_SYS(rt_sigprocmask), 245 },
+ { SCMP_SYS(write), 244 },
+ { SCMP_SYS(fcntl), 243 },
+ { SCMP_SYS(tgkill), 242 },
+ { SCMP_SYS(rt_sigaction), 242 },
+ { SCMP_SYS(pipe2), 242 },
+ { SCMP_SYS(munmap), 242 },
+ { SCMP_SYS(mremap), 242 },
+ { SCMP_SYS(getsockname), 242 },
+ { SCMP_SYS(getpeername), 242 },
+ { SCMP_SYS(fdatasync), 242 },
+ { SCMP_SYS(close), 242 }
+};
+
+int seccomp_start(void)
+{
+ int rc = 0;
+ unsigned int i = 0;
+ scmp_filter_ctx ctx;
+
+ ctx = seccomp_init(SCMP_ACT_KILL);
+ if (ctx == NULL) {
+ goto seccomp_return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(seccomp_whitelist); i++) {
+ rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, seccomp_whitelist[i].num, 0);
+ if (rc < 0) {
+ goto seccomp_return;
+ }
+ rc = seccomp_syscall_priority(ctx, seccomp_whitelist[i].num,
+ seccomp_whitelist[i].priority);
+ if (rc < 0) {
+ goto seccomp_return;
+ }
+ }
+
+ rc = seccomp_load(ctx);
+
+ seccomp_return:
+ seccomp_release(ctx);
+ return rc;
+}
diff --git a/qemu-seccomp.h b/qemu-seccomp.h
new file mode 100644
index 0000000..b2fc3f8
--- /dev/null
+++ b/qemu-seccomp.h
@@ -0,0 +1,22 @@
+/*
+ * QEMU seccomp mode 2 support with libseccomp
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Eduardo Otubo <eotubo@br.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+#ifndef QEMU_SECCOMP_H
+#define QEMU_SECCOMP_H
+
+#include <seccomp.h>
+#include "osdep.h"
+
+int seccomp_start(void);
+#endif
diff --git a/qemu-sockets.c b/qemu-sockets.c
index beb2bb6..361d890 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -209,7 +209,7 @@ listen:
return slisten;
}
-int inet_connect_opts(QemuOpts *opts, Error **errp)
+int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
{
struct addrinfo ai,*res,*e;
const char *addr;
@@ -224,6 +224,10 @@ int inet_connect_opts(QemuOpts *opts, Error **errp)
ai.ai_family = PF_UNSPEC;
ai.ai_socktype = SOCK_STREAM;
+ if (in_progress) {
+ *in_progress = false;
+ }
+
addr = qemu_opt_get(opts, "host");
port = qemu_opt_get(opts, "port");
block = qemu_opt_get_bool(opts, "block", 0);
@@ -277,7 +281,9 @@ int inet_connect_opts(QemuOpts *opts, Error **errp)
#else
if (!block && (rc == -EINPROGRESS)) {
#endif
- error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS);
+ if (in_progress) {
+ *in_progress = true;
+ }
} else if (rc < 0) {
if (NULL == e->ai_next)
fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
@@ -487,7 +493,7 @@ int inet_listen(const char *str, char *ostr, int olen,
return sock;
}
-int inet_connect(const char *str, bool block, Error **errp)
+int inet_connect(const char *str, bool block, bool *in_progress, Error **errp)
{
QemuOpts *opts;
int sock = -1;
@@ -497,7 +503,7 @@ int inet_connect(const char *str, bool block, Error **errp)
if (block) {
qemu_opt_set(opts, "block", "on");
}
- sock = inet_connect_opts(opts, errp);
+ sock = inet_connect_opts(opts, in_progress, errp);
} else {
error_set(errp, QERR_SOCKET_CREATE_FAILED);
}
diff --git a/qemu-timer.c b/qemu-timer.c
index 5aea94e..c7a1551 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -759,11 +759,8 @@ int init_timer_alarm(void)
goto fail;
}
- /* first event is at time 0 */
atexit(quit_timers);
- t->pending = true;
alarm_timer = t;
-
return 0;
fail:
diff --git a/qemu-tool.c b/qemu-tool.c
index 318c5fc..18205ba 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -30,6 +30,11 @@ struct QEMUBH
void *opaque;
};
+const char *qemu_get_vm_name(void)
+{
+ return NULL;
+}
+
Monitor *cur_mon;
int monitor_cur_is_qmp(void)
@@ -57,6 +62,26 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
{
}
+int monitor_fdset_get_fd(int64_t fdset_id, int flags)
+{
+ return -1;
+}
+
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+ return -1;
+}
+
+int monitor_fdset_dup_fd_remove(int dup_fd)
+{
+ return -1;
+}
+
+int monitor_fdset_dup_fd_find(int dup_fd)
+{
+ return -1;
+}
+
int64_t cpu_get_clock(void)
{
return qemu_get_clock_ns(rt_clock);
diff --git a/qemu-user.c b/qemu-user.c
index 08ccb0f..13fb9ae 100644
--- a/qemu-user.c
+++ b/qemu-user.c
@@ -35,3 +35,23 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
void monitor_set_error(Monitor *mon, QError *qerror)
{
}
+
+int monitor_fdset_get_fd(int64_t fdset_id, int flags)
+{
+ return -1;
+}
+
+int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
+{
+ return -1;
+}
+
+int monitor_fdset_dup_fd_remove(int dup_fd)
+{
+ return -1;
+}
+
+int monitor_fdset_dup_fd_find(int dup_fd)
+{
+ return -1;
+}
diff --git a/qemu_socket.h b/qemu_socket.h
index 4689ff3..30ae6af 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -42,8 +42,8 @@ int send_all(int fd, const void *buf, int len1);
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp);
int inet_listen(const char *str, char *ostr, int olen,
int socktype, int port_offset, Error **errp);
-int inet_connect_opts(QemuOpts *opts, Error **errp);
-int inet_connect(const char *str, bool block, Error **errp);
+int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp);
+int inet_connect(const char *str, bool block, bool *in_progress, Error **errp);
int inet_dgram_opts(QemuOpts *opts);
const char *inet_strfamily(int family);
diff --git a/qerror.c b/qerror.c
index 92c4eff..0818504 100644
--- a/qerror.c
+++ b/qerror.c
@@ -23,320 +23,11 @@ static const QType qerror_type = {
};
/**
- * The 'desc' parameter is a printf-like string, the format of the format
- * string is:
- *
- * %(KEY)
- *
- * Where KEY is a QDict key, which has to be passed to qerror_from_info().
- *
- * Example:
- *
- * "foo error on device: %(device) slot: %(slot_nr)"
- *
- * A single percent sign can be printed if followed by a second one,
- * for example:
- *
- * "running out of foo: %(foo)%%"
- *
- * Please keep the entries in alphabetical order.
- * Use scripts/check-qerror.sh to check.
- */
-static const QErrorStringTable qerror_table[] = {
- {
- .error_fmt = QERR_ADD_CLIENT_FAILED,
- .desc = "Could not add client",
- },
- {
- .error_fmt = QERR_AMBIGUOUS_PATH,
- .desc = "Path '%(path)' does not uniquely identify a %(object)"
- },
- {
- .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
- .desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
- },
- {
- .error_fmt = QERR_BASE_NOT_FOUND,
- .desc = "Base '%(base)' not found",
- },
- {
- .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
- .desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
- },
- {
- .error_fmt = QERR_BUS_NO_HOTPLUG,
- .desc = "Bus '%(bus)' does not support hotplugging",
- },
- {
- .error_fmt = QERR_BUS_NOT_FOUND,
- .desc = "Bus '%(bus)' not found",
- },
- {
- .error_fmt = QERR_COMMAND_DISABLED,
- .desc = "The command %(name) has been disabled for this instance",
- },
- {
- .error_fmt = QERR_COMMAND_NOT_FOUND,
- .desc = "The command %(name) has not been found",
- },
- {
- .error_fmt = QERR_DEVICE_ENCRYPTED,
- .desc = "Device '%(device)' is encrypted",
- },
- {
- .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
- .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
- },
- {
- .error_fmt = QERR_DEVICE_HAS_NO_MEDIUM,
- .desc = "Device '%(device)' has no medium",
- },
- {
- .error_fmt = QERR_DEVICE_INIT_FAILED,
- .desc = "Device '%(device)' could not be initialized",
- },
- {
- .error_fmt = QERR_DEVICE_IN_USE,
- .desc = "Device '%(device)' is in use",
- },
- {
- .error_fmt = QERR_DEVICE_IS_READ_ONLY,
- .desc = "Device '%(device)' is read only",
- },
- {
- .error_fmt = QERR_DEVICE_LOCKED,
- .desc = "Device '%(device)' is locked",
- },
- {
- .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES,
- .desc = "Device '%(device)' has multiple child busses",
- },
- {
- .error_fmt = QERR_DEVICE_NO_BUS,
- .desc = "Device '%(device)' has no child bus",
- },
- {
- .error_fmt = QERR_DEVICE_NO_HOTPLUG,
- .desc = "Device '%(device)' does not support hotplugging",
- },
- {
- .error_fmt = QERR_DEVICE_NOT_ACTIVE,
- .desc = "Device '%(device)' has not been activated",
- },
- {
- .error_fmt = QERR_DEVICE_NOT_ENCRYPTED,
- .desc = "Device '%(device)' is not encrypted",
- },
- {
- .error_fmt = QERR_DEVICE_NOT_FOUND,
- .desc = "Device '%(device)' not found",
- },
- {
- .error_fmt = QERR_DEVICE_NOT_REMOVABLE,
- .desc = "Device '%(device)' is not removable",
- },
- {
- .error_fmt = QERR_DUPLICATE_ID,
- .desc = "Duplicate ID '%(id)' for %(object)",
- },
- {
- .error_fmt = QERR_FD_NOT_FOUND,
- .desc = "File descriptor named '%(name)' not found",
- },
- {
- .error_fmt = QERR_FD_NOT_SUPPLIED,
- .desc = "No file descriptor supplied via SCM_RIGHTS",
- },
- {
- .error_fmt = QERR_FEATURE_DISABLED,
- .desc = "The feature '%(name)' is not enabled",
- },
- {
- .error_fmt = QERR_INVALID_BLOCK_FORMAT,
- .desc = "Invalid block format '%(name)'",
- },
- {
- .error_fmt = QERR_INVALID_OPTION_GROUP,
- .desc = "There is no option group '%(group)'",
- },
- {
- .error_fmt = QERR_INVALID_PARAMETER,
- .desc = "Invalid parameter '%(name)'",
- },
- {
- .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
- .desc = "Invalid parameter combination",
- },
- {
- .error_fmt = QERR_INVALID_PARAMETER_TYPE,
- .desc = "Invalid parameter type for '%(name)', expected: %(expected)",
- },
- {
- .error_fmt = QERR_INVALID_PARAMETER_VALUE,
- .desc = "Parameter '%(name)' expects %(expected)",
- },
- {
- .error_fmt = QERR_INVALID_PASSWORD,
- .desc = "Password incorrect",
- },
- {
- .error_fmt = QERR_IO_ERROR,
- .desc = "An IO error has occurred",
- },
- {
- .error_fmt = QERR_JSON_PARSE_ERROR,
- .desc = "JSON parse error, %(message)",
-
- },
- {
- .error_fmt = QERR_JSON_PARSING,
- .desc = "Invalid JSON syntax",
- },
- {
- .error_fmt = QERR_KVM_MISSING_CAP,
- .desc = "Using KVM without %(capability), %(feature) unavailable",
- },
- {
- .error_fmt = QERR_MIGRATION_ACTIVE,
- .desc = "There's a migration process in progress",
- },
- {
- .error_fmt = QERR_MIGRATION_NOT_SUPPORTED,
- .desc = "State blocked by non-migratable device '%(device)'",
- },
- {
- .error_fmt = QERR_MIGRATION_EXPECTED,
- .desc = "An incoming migration is expected before this command can be executed",
- },
- {
- .error_fmt = QERR_MISSING_PARAMETER,
- .desc = "Parameter '%(name)' is missing",
- },
- {
- .error_fmt = QERR_NO_BUS_FOR_DEVICE,
- .desc = "No '%(bus)' bus found for device '%(device)'",
- },
- {
- .error_fmt = QERR_NOT_SUPPORTED,
- .desc = "Not supported",
- },
- {
- .error_fmt = QERR_OPEN_FILE_FAILED,
- .desc = "Could not open '%(filename)'",
- },
- {
- .error_fmt = QERR_PERMISSION_DENIED,
- .desc = "Insufficient permission to perform this operation",
- },
- {
- .error_fmt = QERR_PROPERTY_NOT_FOUND,
- .desc = "Property '%(device).%(property)' not found",
- },
- {
- .error_fmt = QERR_PROPERTY_VALUE_BAD,
- .desc = "Property '%(device).%(property)' doesn't take value '%(value)'",
- },
- {
- .error_fmt = QERR_PROPERTY_VALUE_IN_USE,
- .desc = "Property '%(device).%(property)' can't take value '%(value)', it's in use",
- },
- {
- .error_fmt = QERR_PROPERTY_VALUE_NOT_FOUND,
- .desc = "Property '%(device).%(property)' can't find value '%(value)'",
- },
- {
- .error_fmt = QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
- .desc = "Property '%(device).%(property)' doesn't take "
- "value '%(value)', it's not a power of 2",
- },
- {
- .error_fmt = QERR_PROPERTY_VALUE_OUT_OF_RANGE,
- .desc = "Property '%(device).%(property)' doesn't take "
- "value %(value) (minimum: %(min), maximum: %(max))",
- },
- {
- .error_fmt = QERR_QGA_COMMAND_FAILED,
- .desc = "Guest agent command failed, error was '%(message)'",
- },
- {
- .error_fmt = QERR_QGA_LOGGING_FAILED,
- .desc = "Guest agent failed to log non-optional log statement",
- },
- {
- .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
- .desc = "Expected '%(expected)' in QMP input",
- },
- {
- .error_fmt = QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
- .desc = "QMP input object member '%(member)' expects '%(expected)'",
- },
- {
- .error_fmt = QERR_QMP_EXTRA_MEMBER,
- .desc = "QMP input object member '%(member)' is unexpected",
- },
- {
- .error_fmt = QERR_RESET_REQUIRED,
- .desc = "Resetting the Virtual Machine is required",
- },
- {
- .error_fmt = QERR_SET_PASSWD_FAILED,
- .desc = "Could not set password",
- },
- {
- .error_fmt = QERR_TOO_MANY_FILES,
- .desc = "Too many open files",
- },
- {
- .error_fmt = QERR_UNDEFINED_ERROR,
- .desc = "An undefined error has occurred",
- },
- {
- .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
- .desc = "'%(device)' uses a %(format) feature which is not "
- "supported by this qemu version: %(feature)",
- },
- {
- .error_fmt = QERR_UNSUPPORTED,
- .desc = "this feature or command is not currently supported",
- },
- {
- .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
- .desc = "Migration is disabled when VirtFS export path '%(path)' "
- "is mounted in the guest using mount_tag '%(tag)'",
- },
- {
- .error_fmt = QERR_VNC_SERVER_FAILED,
- .desc = "Could not start VNC server on %(target)",
- },
- {
- .error_fmt = QERR_SOCKET_CONNECT_IN_PROGRESS,
- .desc = "Connection can not be completed immediately",
- },
- {
- .error_fmt = QERR_SOCKET_CONNECT_FAILED,
- .desc = "Failed to connect to socket",
- },
- {
- .error_fmt = QERR_SOCKET_LISTEN_FAILED,
- .desc = "Failed to set socket to listening mode",
- },
- {
- .error_fmt = QERR_SOCKET_BIND_FAILED,
- .desc = "Failed to bind socket",
- },
- {
- .error_fmt = QERR_SOCKET_CREATE_FAILED,
- .desc = "Failed to create socket",
- },
- {}
-};
-
-/**
* qerror_new(): Create a new QError
*
* Return strong reference.
*/
-QError *qerror_new(void)
+static QError *qerror_new(void)
{
QError *qerr;
@@ -346,200 +37,31 @@ QError *qerror_new(void)
return qerr;
}
-static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr,
- const char *fmt, ...)
-{
- va_list ap;
-
- fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
- fprintf(stderr, "qerror: -> ");
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
- abort();
-}
-
-static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
- const char *fmt, va_list *va)
-{
- QObject *obj;
-
- obj = qobject_from_jsonv(fmt, va);
- if (!obj) {
- qerror_abort(qerr, "invalid format '%s'", fmt);
- }
- if (qobject_type(obj) != QTYPE_QDICT) {
- qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
- }
-
- qerr->error = qobject_to_qdict(obj);
-
- obj = qdict_get(qerr->error, "class");
- if (!obj) {
- qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
- }
- if (qobject_type(obj) != QTYPE_QSTRING) {
- qerror_abort(qerr, "'class' key value should be a QString");
- }
-
- obj = qdict_get(qerr->error, "data");
- if (!obj) {
- qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
- }
- if (qobject_type(obj) != QTYPE_QDICT) {
- qerror_abort(qerr, "'data' key value should be a QDICT");
- }
-}
-
-static void qerror_set_desc(QError *qerr, const char *fmt)
-{
- int i;
-
- // FIXME: inefficient loop
-
- for (i = 0; qerror_table[i].error_fmt; i++) {
- if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
- qerr->entry = &qerror_table[i];
- return;
- }
- }
-
- qerror_abort(qerr, "error format '%s' not found", fmt);
-}
-
/**
* qerror_from_info(): Create a new QError from error information
*
- * The information consists of:
- *
- * - file the file name of where the error occurred
- * - linenr the line number of where the error occurred
- * - func the function name of where the error occurred
- * - fmt JSON printf-like dictionary, there must exist keys 'class' and
- * 'data'
- * - va va_list of all arguments specified by fmt
- *
* Return strong reference.
*/
-QError *qerror_from_info(const char *file, int linenr, const char *func,
- const char *fmt, va_list *va)
+static QError *qerror_from_info(ErrorClass err_class, const char *fmt,
+ va_list *va)
{
QError *qerr;
qerr = qerror_new();
loc_save(&qerr->loc);
- qerr->linenr = linenr;
- qerr->file = file;
- qerr->func = func;
-
- if (!fmt) {
- qerror_abort(qerr, "QDict not specified");
- }
- qerror_set_data(qerr, fmt, va);
- qerror_set_desc(qerr, fmt);
+ qerr->err_msg = g_strdup_vprintf(fmt, *va);
+ qerr->err_class = err_class;
return qerr;
}
-static void parse_error(const QErrorStringTable *entry, int c)
-{
- fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
- abort();
-}
-
-static const char *append_field(QDict *error, QString *outstr,
- const QErrorStringTable *entry,
- const char *start)
-{
- QObject *obj;
- QDict *qdict;
- QString *key_qs;
- const char *end, *key;
-
- if (*start != '%')
- parse_error(entry, '%');
- start++;
- if (*start != '(')
- parse_error(entry, '(');
- start++;
-
- end = strchr(start, ')');
- if (!end)
- parse_error(entry, ')');
-
- key_qs = qstring_from_substr(start, 0, end - start - 1);
- key = qstring_get_str(key_qs);
-
- qdict = qobject_to_qdict(qdict_get(error, "data"));
- obj = qdict_get(qdict, key);
- if (!obj) {
- abort();
- }
-
- switch (qobject_type(obj)) {
- case QTYPE_QSTRING:
- qstring_append(outstr, qdict_get_str(qdict, key));
- break;
- case QTYPE_QINT:
- qstring_append_int(outstr, qdict_get_int(qdict, key));
- break;
- default:
- abort();
- }
-
- QDECREF(key_qs);
- return ++end;
-}
-
-static QString *qerror_format_desc(QDict *error,
- const QErrorStringTable *entry)
-{
- QString *qstring;
- const char *p;
-
- assert(entry != NULL);
-
- qstring = qstring_new();
-
- for (p = entry->desc; *p != '\0';) {
- if (*p != '%') {
- qstring_append_chr(qstring, *p++);
- } else if (*(p + 1) == '%') {
- qstring_append_chr(qstring, '%');
- p += 2;
- } else {
- p = append_field(error, qstring, entry, p);
- }
- }
-
- return qstring;
-}
-
-QString *qerror_format(const char *fmt, QDict *error)
-{
- const QErrorStringTable *entry = NULL;
- int i;
-
- for (i = 0; qerror_table[i].error_fmt; i++) {
- if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
- entry = &qerror_table[i];
- break;
- }
- }
-
- return qerror_format_desc(error, entry);
-}
-
/**
* qerror_human(): Format QError data into human-readable string.
*/
QString *qerror_human(const QError *qerror)
{
- return qerror_format_desc(qerror->error, qerror->entry);
+ return qstring_from_str(qerror->err_msg);
}
/**
@@ -549,7 +71,7 @@ QString *qerror_human(const QError *qerror)
* it uses error_report() for this, so that the output is routed to the right
* place (ie. stderr or Monitor's device).
*/
-void qerror_print(QError *qerror)
+static void qerror_print(QError *qerror)
{
QString *qstring = qerror_human(qerror);
loc_push_restore(&qerror->loc);
@@ -558,14 +80,13 @@ void qerror_print(QError *qerror)
QDECREF(qstring);
}
-void qerror_report_internal(const char *file, int linenr, const char *func,
- const char *fmt, ...)
+void qerror_report(ErrorClass eclass, const char *fmt, ...)
{
va_list va;
QError *qerror;
va_start(va, fmt);
- qerror = qerror_from_info(file, linenr, func, fmt, &va);
+ qerror = qerror_from_info(eclass, fmt, &va);
va_end(va);
if (monitor_cur_is_qmp()) {
@@ -579,27 +100,18 @@ void qerror_report_internal(const char *file, int linenr, const char *func,
/* Evil... */
struct Error
{
- QDict *obj;
- const char *fmt;
char *msg;
+ ErrorClass err_class;
};
void qerror_report_err(Error *err)
{
QError *qerr;
- int i;
qerr = qerror_new();
loc_save(&qerr->loc);
- QINCREF(err->obj);
- qerr->error = err->obj;
-
- for (i = 0; qerror_table[i].error_fmt; i++) {
- if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) {
- qerr->entry = &qerror_table[i];
- break;
- }
- }
+ qerr->err_msg = g_strdup(err->msg);
+ qerr->err_class = err->err_class;
if (monitor_cur_is_qmp()) {
monitor_set_error(cur_mon, qerr);
@@ -620,7 +132,7 @@ void assert_no_error(Error *err)
/**
* qobject_to_qerror(): Convert a QObject into a QError
*/
-QError *qobject_to_qerror(const QObject *obj)
+static QError *qobject_to_qerror(const QObject *obj)
{
if (qobject_type(obj) != QTYPE_QERROR) {
return NULL;
@@ -639,6 +151,6 @@ static void qerror_destroy_obj(QObject *obj)
assert(obj != NULL);
qerr = qobject_to_qerror(obj);
- QDECREF(qerr->error);
+ g_free(qerr->err_msg);
g_free(qerr);
}
diff --git a/qerror.h b/qerror.h
index b4c8758..d0a76a4 100644
--- a/qerror.h
+++ b/qerror.h
@@ -16,36 +16,20 @@
#include "qstring.h"
#include "qemu-error.h"
#include "error.h"
+#include "qapi-types.h"
#include <stdarg.h>
-typedef struct QErrorStringTable {
- const char *desc;
- const char *error_fmt;
-} QErrorStringTable;
-
typedef struct QError {
QObject_HEAD;
- QDict *error;
Location loc;
- int linenr;
- const char *file;
- const char *func;
- const QErrorStringTable *entry;
+ char *err_msg;
+ ErrorClass err_class;
} QError;
-QError *qerror_new(void);
-QError *qerror_from_info(const char *file, int linenr, const char *func,
- const char *fmt, va_list *va) GCC_FMT_ATTR(4, 0);
QString *qerror_human(const QError *qerror);
-void qerror_print(QError *qerror);
-void qerror_report_internal(const char *file, int linenr, const char *func,
- const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+void qerror_report(ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
void qerror_report_err(Error *err);
void assert_no_error(Error *err);
-QString *qerror_format(const char *fmt, QDict *error);
-#define qerror_report(fmt, ...) \
- qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
-QError *qobject_to_qerror(const QObject *obj);
/*
* QError class list
@@ -53,217 +37,213 @@ QError *qobject_to_qerror(const QObject *obj);
* Use scripts/check-qerror.sh to check.
*/
#define QERR_ADD_CLIENT_FAILED \
- "{ 'class': 'AddClientFailed', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Could not add client"
#define QERR_AMBIGUOUS_PATH \
- "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Path '%s' does not uniquely identify an object"
#define QERR_BAD_BUS_FOR_DEVICE \
- "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' can't go on a %s bus"
#define QERR_BASE_NOT_FOUND \
- "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Base '%s' not found"
#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
- "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by device '%s' does not support feature '%s'"
#define QERR_BUFFER_OVERRUN \
- "{ 'class': 'BufferOverrun', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "An internal buffer overran"
#define QERR_BUS_NO_HOTPLUG \
- "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Bus '%s' does not support hotplugging"
#define QERR_BUS_NOT_FOUND \
- "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Bus '%s' not found"
#define QERR_COMMAND_DISABLED \
- "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "The command %s has been disabled for this instance"
#define QERR_COMMAND_NOT_FOUND \
- "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+ ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has not been found"
#define QERR_DEVICE_ENCRYPTED \
- "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
+ ERROR_CLASS_DEVICE_ENCRYPTED, "'%s' (%s) is encrypted"
#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
- "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when using feature '%s' in device '%s'"
#define QERR_DEVICE_HAS_NO_MEDIUM \
- "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' has no medium"
#define QERR_DEVICE_INIT_FAILED \
- "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' could not be initialized"
#define QERR_DEVICE_IN_USE \
- "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' is in use"
#define QERR_DEVICE_IS_READ_ONLY \
- "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' is read only"
#define QERR_DEVICE_LOCKED \
- "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' is locked"
#define QERR_DEVICE_MULTIPLE_BUSSES \
- "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' has multiple child busses"
#define QERR_DEVICE_NO_BUS \
- "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' has no child bus"
#define QERR_DEVICE_NO_HOTPLUG \
- "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' does not support hotplugging"
#define QERR_DEVICE_NOT_ACTIVE \
- "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
+ ERROR_CLASS_DEVICE_NOT_ACTIVE, "Device '%s' has not been activated"
#define QERR_DEVICE_NOT_ENCRYPTED \
- "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not encrypted"
#define QERR_DEVICE_NOT_FOUND \
- "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }"
+ ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found"
#define QERR_DEVICE_NOT_REMOVABLE \
- "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not removable"
#define QERR_DUPLICATE_ID \
- "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Duplicate ID '%s' for %s"
#define QERR_FD_NOT_FOUND \
- "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "File descriptor named '%s' not found"
#define QERR_FD_NOT_SUPPLIED \
- "{ 'class': 'FdNotSupplied', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "No file descriptor supplied via SCM_RIGHTS"
#define QERR_FEATURE_DISABLED \
- "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "The feature '%s' is not enabled"
#define QERR_INVALID_BLOCK_FORMAT \
- "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Invalid block format '%s'"
#define QERR_INVALID_OPTION_GROUP \
- "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "There is no option group '%s'"
#define QERR_INVALID_PARAMETER \
- "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Invalid parameter '%s'"
#define QERR_INVALID_PARAMETER_COMBINATION \
- "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Invalid parameter combination"
#define QERR_INVALID_PARAMETER_TYPE \
- "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Invalid parameter type for '%s', expected: %s"
#define QERR_INVALID_PARAMETER_VALUE \
- "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s"
#define QERR_INVALID_PASSWORD \
- "{ 'class': 'InvalidPassword', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Password incorrect"
#define QERR_IO_ERROR \
- "{ 'class': 'IOError', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "An IO error has occurred"
#define QERR_JSON_PARSE_ERROR \
- "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "JSON parse error, %s"
#define QERR_JSON_PARSING \
- "{ 'class': 'JSONParsing', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Invalid JSON syntax"
#define QERR_KVM_MISSING_CAP \
- "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
+ ERROR_CLASS_K_V_M_MISSING_CAP, "Using KVM without %s, %s unavailable"
#define QERR_MIGRATION_ACTIVE \
- "{ 'class': 'MigrationActive', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "There's a migration process in progress"
#define QERR_MIGRATION_NOT_SUPPORTED \
- "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }"
+ ERROR_CLASS_GENERIC_ERROR, "State blocked by non-migratable device '%s'"
#define QERR_MIGRATION_EXPECTED \
- "{ 'class': 'MigrationExpected', 'data': {} }"
+ ERROR_CLASS_MIGRATION_EXPECTED, "An incoming migration is expected before this command can be executed"
#define QERR_MISSING_PARAMETER \
- "{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' is missing"
#define QERR_NO_BUS_FOR_DEVICE \
- "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "No '%s' bus found for device '%s'"
#define QERR_NOT_SUPPORTED \
- "{ 'class': 'NotSupported', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Not supported"
#define QERR_OPEN_FILE_FAILED \
- "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Could not open '%s'"
#define QERR_PERMISSION_DENIED \
- "{ 'class': 'PermissionDenied', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Insufficient permission to perform this operation"
#define QERR_PROPERTY_NOT_FOUND \
- "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' not found"
#define QERR_PROPERTY_VALUE_BAD \
- "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' doesn't take value '%s'"
#define QERR_PROPERTY_VALUE_IN_USE \
- "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' can't take value '%s', it's in use"
#define QERR_PROPERTY_VALUE_NOT_FOUND \
- "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' can't find value '%s'"
#define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \
- "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
- "'device': %s, 'property': %s, 'value': %"PRId64" } }"
+ ERROR_CLASS_GENERIC_ERROR, "Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2"
#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
- "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
+ ERROR_CLASS_GENERIC_ERROR, "Property %s.%s doesn't take value %" PRId64 " (minimum: %" PRId64 ", maximum: %" PRId64 ")"
#define QERR_QGA_COMMAND_FAILED \
- "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Guest agent command failed, error was '%s'"
#define QERR_QGA_LOGGING_FAILED \
- "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Guest agent failed to log non-optional log statement"
#define QERR_QMP_BAD_INPUT_OBJECT \
- "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Expected '%s' in QMP input"
#define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \
- "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "QMP input object member '%s' expects '%s'"
#define QERR_QMP_EXTRA_MEMBER \
- "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "QMP input object member '%s' is unexpected"
#define QERR_RESET_REQUIRED \
- "{ 'class': 'ResetRequired', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Resetting the Virtual Machine is required"
#define QERR_SET_PASSWD_FAILED \
- "{ 'class': 'SetPasswdFailed', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Could not set password"
#define QERR_TOO_MANY_FILES \
- "{ 'class': 'TooManyFiles', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Too many open files"
#define QERR_UNDEFINED_ERROR \
- "{ 'class': 'UndefinedError', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "An undefined error has occurred"
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
- "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "'%s' uses a %s feature which is not supported by this qemu version: %s"
#define QERR_UNSUPPORTED \
- "{ 'class': 'Unsupported', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "this feature or command is not currently supported"
#define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
- "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
+ ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'"
#define QERR_VNC_SERVER_FAILED \
- "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
-
-#define QERR_SOCKET_CONNECT_IN_PROGRESS \
- "{ 'class': 'SockConnectInprogress', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Could not start VNC server on %s"
#define QERR_SOCKET_CONNECT_FAILED \
- "{ 'class': 'SockConnectFailed', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Failed to connect to socket"
#define QERR_SOCKET_LISTEN_FAILED \
- "{ 'class': 'SockListenFailed', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Failed to set socket to listening mode"
#define QERR_SOCKET_BIND_FAILED \
- "{ 'class': 'SockBindFailed', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Failed to bind socket"
#define QERR_SOCKET_CREATE_FAILED \
- "{ 'class': 'SockCreateFailed', 'data': {} }"
+ ERROR_CLASS_GENERIC_ERROR, "Failed to create socket"
#endif /* QERROR_H */
diff --git a/qlist.c b/qlist.c
index 88498b1..b48ec5b 100644
--- a/qlist.c
+++ b/qlist.c
@@ -124,6 +124,19 @@ int qlist_empty(const QList *qlist)
return QTAILQ_EMPTY(&qlist->head);
}
+static void qlist_size_iter(QObject *obj, void *opaque)
+{
+ size_t *count = opaque;
+ (*count)++;
+}
+
+size_t qlist_size(const QList *qlist)
+{
+ size_t count = 0;
+ qlist_iter(qlist, qlist_size_iter, &count);
+ return count;
+}
+
/**
* qobject_to_qlist(): Convert a QObject into a QList
*/
diff --git a/qlist.h b/qlist.h
index d426bd4..ae776f9 100644
--- a/qlist.h
+++ b/qlist.h
@@ -49,6 +49,7 @@ void qlist_iter(const QList *qlist,
QObject *qlist_pop(QList *qlist);
QObject *qlist_peek(QList *qlist);
int qlist_empty(const QList *qlist);
+size_t qlist_size(const QList *qlist);
QList *qobject_to_qlist(const QObject *obj);
static inline const QListEntry *qlist_first(const QList *qlist)
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ac46638..3745a21 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -435,8 +435,8 @@ Example:
-> { "execute": "inject-nmi" }
<- { "return": {} }
-Note: inject-nmi is only supported for x86 guest currently, it will
- returns "Unsupported" error for non-x86 guest.
+Note: inject-nmi fails when the guest doesn't support injecting.
+ Currently, only x86 guests do.
EQMP
@@ -520,6 +520,50 @@ Example:
<- { "return": {} }
EQMP
+{
+ .name = "migrate-set-cache-size",
+ .args_type = "value:o",
+ .mhandler.cmd_new = qmp_marshal_input_migrate_set_cache_size,
+ },
+
+SQMP
+migrate-set-cache-size
+---------------------
+
+Set cache size to be used by XBZRLE migration, the cache size will be rounded
+down to the nearest power of 2
+
+Arguments:
+
+- "value": cache size in bytes (json-int)
+
+Example:
+
+-> { "execute": "migrate-set-cache-size", "arguments": { "value": 536870912 } }
+<- { "return": {} }
+
+EQMP
+ {
+ .name = "query-migrate-cache-size",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_migrate_cache_size,
+ },
+
+SQMP
+query-migrate-cache-size
+---------------------
+
+Show cache size to be used by XBZRLE migration
+
+returns a json-object with the following information:
+- "size" : json-int
+
+Example:
+
+-> { "execute": "query-migrate-cache-size" }
+<- { "return": 67108864 }
+
+EQMP
{
.name = "migrate_set_speed",
@@ -926,6 +970,128 @@ Example:
EQMP
+ {
+ .name = "add-fd",
+ .args_type = "fdset-id:i?,opaque:s?",
+ .params = "add-fd fdset-id opaque",
+ .help = "Add a file descriptor, that was passed via SCM rights, to an fd set",
+ .mhandler.cmd_new = qmp_marshal_input_add_fd,
+ },
+
+SQMP
+add-fd
+-------
+
+Add a file descriptor, that was passed via SCM rights, to an fd set.
+
+Arguments:
+
+- "fdset-id": The ID of the fd set to add the file descriptor to.
+ (json-int, optional)
+- "opaque": A free-form string that can be used to describe the fd.
+ (json-string, optional)
+
+Return a json-object with the following information:
+
+- "fdset-id": The ID of the fd set that the fd was added to. (json-int)
+- "fd": The file descriptor that was received via SCM rights and added to the
+ fd set. (json-int)
+
+Example:
+
+-> { "execute": "add-fd", "arguments": { "fdset-id": 1 } }
+<- { "return": { "fdset-id": 1, "fd": 3 } }
+
+Notes:
+
+(1) The list of fd sets is shared by all monitor connections.
+(2) If "fdset-id" is not specified, a new fd set will be created.
+
+EQMP
+
+ {
+ .name = "remove-fd",
+ .args_type = "fdset-id:i,fd:i?",
+ .params = "remove-fd fdset-id fd",
+ .help = "Remove a file descriptor from an fd set",
+ .mhandler.cmd_new = qmp_marshal_input_remove_fd,
+ },
+
+SQMP
+remove-fd
+---------
+
+Remove a file descriptor from an fd set.
+
+Arguments:
+
+- "fdset-id": The ID of the fd set that the file descriptor belongs to.
+ (json-int)
+- "fd": The file descriptor that is to be removed. (json-int, optional)
+
+Example:
+
+-> { "execute": "remove-fd", "arguments": { "fdset-id": 1, "fd": 3 } }
+<- { "return": {} }
+
+Notes:
+
+(1) The list of fd sets is shared by all monitor connections.
+(2) If "fd" is not specified, all file descriptors in "fdset-id" will be
+ removed.
+
+EQMP
+
+ {
+ .name = "query-fdsets",
+ .args_type = "",
+ .help = "Return information describing all fd sets",
+ .mhandler.cmd_new = qmp_marshal_input_query_fdsets,
+ },
+
+SQMP
+query-fdsets
+-------------
+
+Return information describing all fd sets.
+
+Arguments: None
+
+Example:
+
+-> { "execute": "query-fdsets" }
+<- { "return": [
+ {
+ "fds": [
+ {
+ "fd": 30,
+ "opaque": "rdonly:/path/to/file"
+ },
+ {
+ "fd": 24,
+ "opaque": "rdwr:/path/to/file"
+ }
+ ],
+ "fdset-id": 1
+ },
+ {
+ "fds": [
+ {
+ "fd": 28
+ },
+ {
+ "fd": 29
+ }
+ ],
+ "fdset-id": 0
+ }
+ ]
+ }
+
+Note: The list of fd sets is shared by all monitor connections.
+
+EQMP
+
{
.name = "block_passwd",
.args_type = "device:B,password:s",
@@ -2073,17 +2239,29 @@ The main json-object contains the following:
- "status": migration status (json-string)
- Possible values: "active", "completed", "failed", "cancelled"
+- "total-time": total amount of ms since migration started. If
+ migration has ended, it returns the total migration
+ time (json-int)
- "ram": only present if "status" is "active", it is a json-object with the
following RAM information (in bytes):
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
+ - "duplicate": number of duplicated pages (json-int)
+ - "normal" : number of normal pages transferred (json-int)
+ - "normal-bytes" : number of normal bytes transferred (json-int)
- "disk": only present if "status" is "active" and it is a block migration,
it is a json-object with the following disk information (in bytes):
- "transferred": amount transferred (json-int)
- "remaining": amount remaining (json-int)
- "total": total (json-int)
-
+- "xbzrle-cache": only present if XBZRLE is active.
+ It is a json-object with the following XBZRLE information:
+ - "cache-size": XBZRLE cache size
+ - "bytes": total XBZRLE bytes transferred
+ - "pages": number of XBZRLE compressed pages
+ - "cache-miss": number of cache misses
+ - "overflow": number of XBZRLE overflows
Examples:
1. Before the first migration
@@ -2094,7 +2272,19 @@ Examples:
2. Migration is done and has succeeded
-> { "execute": "query-migrate" }
-<- { "return": { "status": "completed" } }
+<- { "return": {
+ "status": "completed",
+ "ram":{
+ "transferred":123,
+ "remaining":123,
+ "total":246,
+ "total-time":12345,
+ "duplicate":123,
+ "normal":123,
+ "normal-bytes":123456
+ }
+ }
+ }
3. Migration is done and has failed
@@ -2110,7 +2300,11 @@ Examples:
"ram":{
"transferred":123,
"remaining":123,
- "total":246
+ "total":246,
+ "total-time":12345,
+ "duplicate":123,
+ "normal":123,
+ "normal-bytes":123456
}
}
}
@@ -2124,7 +2318,11 @@ Examples:
"ram":{
"total":1057024,
"remaining":1053304,
- "transferred":3720
+ "transferred":3720,
+ "total-time":12345,
+ "duplicate":123,
+ "normal":123,
+ "normal-bytes":123456
},
"disk":{
"total":20971520,
@@ -2134,6 +2332,32 @@ Examples:
}
}
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+ "return":{
+ "status":"active",
+ "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+ "ram":{
+ "total":1057024,
+ "remaining":1053304,
+ "transferred":3720,
+ "total-time":12345,
+ "duplicate":10,
+ "normal":3333,
+ "normal-bytes":3412992
+ },
+ "xbzrle-cache":{
+ "cache-size":67108864,
+ "bytes":20971520,
+ "pages":2444343,
+ "cache-miss":2244,
+ "overflow":34434
+ }
+ }
+ }
+
EQMP
{
@@ -2143,6 +2367,55 @@ EQMP
},
SQMP
+migrate-set-capabilities
+-------
+
+Enable/Disable migration capabilities
+
+- "xbzrle": xbzrle support
+
+Arguments:
+
+Example:
+
+-> { "execute": "migrate-set-capabilities" , "arguments":
+ { "capabilities": [ { "capability": "xbzrle", "state": true } ] } }
+
+EQMP
+
+ {
+ .name = "migrate-set-capabilities",
+ .args_type = "capabilities:O",
+ .params = "capability:s,state:b",
+ .mhandler.cmd_new = qmp_marshal_input_migrate_set_capabilities,
+ },
+SQMP
+query-migrate-capabilities
+-------
+
+Query current migration capabilities
+
+- "capabilities": migration capabilities state
+ - "xbzrle" : XBZRLE state (json-bool)
+
+Arguments:
+
+Example:
+
+-> { "execute": "query-migrate-capabilities" }
+<- { "return": {
+ "capabilities" : [ { "capability" : "xbzrle", "state" : false } ]
+ }
+ }
+EQMP
+
+ {
+ .name = "query-migrate-capabilities",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_migrate_capabilities,
+ },
+
+SQMP
query-balloon
-------------
@@ -2217,3 +2490,27 @@ EQMP
.args_type = "implements:s?,abstract:b?",
.mhandler.cmd_new = qmp_marshal_input_qom_list_types,
},
+
+ {
+ .name = "device-list-properties",
+ .args_type = "typename:s",
+ .mhandler.cmd_new = qmp_marshal_input_device_list_properties,
+ },
+
+ {
+ .name = "query-machines",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_machines,
+ },
+
+ {
+ .name = "query-cpu-definitions",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_cpu_definitions,
+ },
+
+ {
+ .name = "query-target",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_target,
+ },
diff --git a/qmp.c b/qmp.c
index fee9fb2..8463922 100644
--- a/qmp.c
+++ b/qmp.c
@@ -417,3 +417,65 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
return ret;
}
+
+DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
+ Error **errp)
+{
+ ObjectClass *klass;
+ Property *prop;
+ DevicePropertyInfoList *prop_list = NULL;
+
+ klass = object_class_by_name(typename);
+ if (klass == NULL) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, typename);
+ return NULL;
+ }
+
+ klass = object_class_dynamic_cast(klass, TYPE_DEVICE);
+ if (klass == NULL) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE,
+ "name", TYPE_DEVICE);
+ return NULL;
+ }
+
+ do {
+ for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
+ DevicePropertyInfoList *entry;
+ DevicePropertyInfo *info;
+
+ /*
+ * TODO Properties without a parser are just for dirty hacks.
+ * qdev_prop_ptr is the only such PropertyInfo. It's marked
+ * for removal. This conditional should be removed along with
+ * it.
+ */
+ if (!prop->info->set) {
+ continue; /* no way to set it, don't show */
+ }
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(prop->name);
+ info->type = g_strdup(prop->info->legacy_name ?: prop->info->name);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = prop_list;
+ prop_list = entry;
+ }
+ klass = object_class_get_parent(klass);
+ } while (klass != object_class_by_name(TYPE_DEVICE));
+
+ return prop_list;
+}
+
+CpuDefinitionInfoList GCC_WEAK *arch_query_cpu_definitions(Error **errp)
+{
+ error_set(errp, QERR_NOT_SUPPORTED);
+ return NULL;
+}
+
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+{
+ return arch_query_cpu_definitions(errp);
+}
+
diff --git a/qom/object.c b/qom/object.c
index 00bb3b0..e3e9242 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -31,9 +31,7 @@ typedef struct TypeImpl TypeImpl;
struct InterfaceImpl
{
- const char *parent;
- void (*interface_initfn)(ObjectClass *class, void *data);
- TypeImpl *type;
+ const char *typename;
};
struct TypeImpl
@@ -64,14 +62,6 @@ struct TypeImpl
InterfaceImpl interfaces[MAX_INTERFACES];
};
-typedef struct Interface
-{
- Object parent;
- Object *obj;
-} Interface;
-
-#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
-
static Type type_interface;
static GHashTable *type_table_get(void)
@@ -98,6 +88,7 @@ static TypeImpl *type_table_lookup(const char *name)
static TypeImpl *type_register_internal(const TypeInfo *info)
{
TypeImpl *ti = g_malloc0(sizeof(*ti));
+ int i;
g_assert(info->name != NULL);
@@ -122,15 +113,10 @@ static TypeImpl *type_register_internal(const TypeInfo *info)
ti->abstract = info->abstract;
- if (info->interfaces) {
- int i;
-
- for (i = 0; info->interfaces[i].type; i++) {
- ti->interfaces[i].parent = info->interfaces[i].type;
- ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
- ti->num_interfaces++;
- }
+ for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
+ ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
}
+ ti->num_interfaces = i;
type_table_add(ti);
@@ -198,26 +184,48 @@ static size_t type_object_get_size(TypeImpl *ti)
return 0;
}
-static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
+static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
{
- TypeInfo info = {
- .instance_size = sizeof(Interface),
- .parent = iface->parent,
- .class_size = sizeof(InterfaceClass),
- .class_init = iface->interface_initfn,
- .abstract = true,
- };
- char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
+ assert(target_type);
- info.name = name;
- iface->type = type_register_internal(&info);
- g_free(name);
+ /* Check if typename is a direct ancestor of type */
+ while (type) {
+ if (type == target_type) {
+ return true;
+ }
+
+ type = type_get_parent(type);
+ }
+
+ return false;
+}
+
+static void type_initialize(TypeImpl *ti);
+
+static void type_initialize_interface(TypeImpl *ti, const char *parent)
+{
+ InterfaceClass *new_iface;
+ TypeInfo info = { };
+ TypeImpl *iface_impl;
+
+ info.parent = parent;
+ info.name = g_strdup_printf("%s::%s", ti->name, info.parent);
+ info.abstract = true;
+
+ iface_impl = type_register(&info);
+ type_initialize(iface_impl);
+ g_free((char *)info.name);
+
+ new_iface = (InterfaceClass *)iface_impl->class;
+ new_iface->concrete_class = ti->class;
+
+ ti->class->interfaces = g_slist_append(ti->class->interfaces,
+ iface_impl->class);
}
static void type_initialize(TypeImpl *ti)
{
TypeImpl *parent;
- int i;
if (ti->class) {
return;
@@ -231,9 +239,33 @@ static void type_initialize(TypeImpl *ti)
parent = type_get_parent(ti);
if (parent) {
type_initialize(parent);
+ GSList *e;
+ int i;
g_assert(parent->class_size <= ti->class_size);
memcpy(ti->class, parent->class, parent->class_size);
+
+ for (e = parent->class->interfaces; e; e = e->next) {
+ ObjectClass *iface = e->data;
+ type_initialize_interface(ti, object_class_get_name(iface));
+ }
+
+ for (i = 0; i < ti->num_interfaces; i++) {
+ TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
+ for (e = ti->class->interfaces; e; e = e->next) {
+ TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
+
+ if (type_is_ancestor(target_type, t)) {
+ break;
+ }
+ }
+
+ if (e) {
+ continue;
+ }
+
+ type_initialize_interface(ti, ti->interfaces[i].typename);
+ }
}
ti->class->type = ti;
@@ -245,38 +277,19 @@ static void type_initialize(TypeImpl *ti)
parent = type_get_parent(parent);
}
- for (i = 0; i < ti->num_interfaces; i++) {
- type_class_interface_init(ti, &ti->interfaces[i]);
- }
-
if (ti->class_init) {
ti->class_init(ti->class, ti->class_data);
}
-}
-
-static void object_interface_init(Object *obj, InterfaceImpl *iface)
-{
- TypeImpl *ti = iface->type;
- Interface *iface_obj;
- iface_obj = INTERFACE(object_new(ti->name));
- iface_obj->obj = obj;
- obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
}
static void object_init_with_type(Object *obj, TypeImpl *ti)
{
- int i;
-
if (type_has_parent(ti)) {
object_init_with_type(obj, type_get_parent(ti));
}
- for (i = 0; i < ti->num_interfaces; i++) {
- object_interface_init(obj, &ti->interfaces[i]);
- }
-
if (ti->instance_init) {
ti->instance_init(obj);
}
@@ -357,17 +370,9 @@ static void object_deinit(Object *obj, TypeImpl *type)
type->instance_finalize(obj);
}
- while (obj->interfaces) {
- Interface *iface_obj = obj->interfaces->data;
- obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
- object_delete(OBJECT(iface_obj));
- }
-
if (type_has_parent(type)) {
object_deinit(obj, type_get_parent(type));
}
-
- object_unparent(obj);
}
void object_finalize(void *data)
@@ -404,79 +409,21 @@ Object *object_new(const char *typename)
void object_delete(Object *obj)
{
+ object_unparent(obj);
+ g_assert(obj->ref == 1);
object_unref(obj);
- g_assert(obj->ref == 0);
g_free(obj);
}
-static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
-{
- assert(target_type);
-
- /* Check if typename is a direct ancestor of type */
- while (type) {
- if (type == target_type) {
- return true;
- }
-
- type = type_get_parent(type);
- }
-
- return false;
-}
-
-static bool object_is_type(Object *obj, TypeImpl *target_type)
-{
- return !target_type || type_is_ancestor(obj->class->type, target_type);
-}
-
Object *object_dynamic_cast(Object *obj, const char *typename)
{
- TypeImpl *target_type = type_get_by_name(typename);
- GSList *i;
-
- /* Check if typename is a direct ancestor. Special-case TYPE_OBJECT,
- * we want to go back from interfaces to the parent.
- */
- if (target_type && object_is_type(obj, target_type)) {
- return obj;
- }
-
- /* Check if obj is an interface and its containing object is a direct
- * ancestor of typename. In principle we could do this test at the very
- * beginning of object_dynamic_cast, avoiding a second call to
- * object_is_type. However, casting between interfaces is relatively
- * rare, and object_is_type(obj, type_interface) would fail almost always.
- *
- * Perhaps we could add a magic value to the object header for increased
- * (run-time) type safety and to speed up tests like this one. If we ever
- * do that we can revisit the order here.
- */
- if (object_is_type(obj, type_interface)) {
- assert(!obj->interfaces);
- obj = INTERFACE(obj)->obj;
- if (object_is_type(obj, target_type)) {
- return obj;
- }
- }
-
- if (!target_type) {
+ if (object_class_dynamic_cast(object_get_class(obj), typename)) {
return obj;
}
- /* Check if obj has an interface of typename */
- for (i = obj->interfaces; i; i = i->next) {
- Interface *iface = i->data;
-
- if (object_is_type(OBJECT(iface), target_type)) {
- return OBJECT(iface);
- }
- }
-
return NULL;
}
-
Object *object_dynamic_cast_assert(Object *obj, const char *typename)
{
Object *inst;
@@ -497,16 +444,30 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
{
TypeImpl *target_type = type_get_by_name(typename);
TypeImpl *type = class->type;
+ ObjectClass *ret = NULL;
- while (type) {
- if (type == target_type) {
- return class;
- }
+ if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) {
+ int found = 0;
+ GSList *i;
- type = type_get_parent(type);
+ for (i = class->interfaces; i; i = i->next) {
+ ObjectClass *target_class = i->data;
+
+ if (type_is_ancestor(target_class->type, target_type)) {
+ ret = target_class;
+ found++;
+ }
+ }
+
+ /* The match was ambiguous, don't allow a cast */
+ if (found > 1) {
+ ret = NULL;
+ }
+ } else if (type_is_ancestor(type, target_type)) {
+ ret = class;
}
- return NULL;
+ return ret;
}
ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
@@ -920,12 +881,6 @@ void object_property_add_child(Object *obj, const char *name,
{
gchar *type;
- /* Registering an interface object in the composition tree will mightily
- * confuse object_get_canonical_path (which, on the other hand, knows how
- * to get the canonical path of an interface object).
- */
- assert(!object_is_type(obj, type_interface));
-
type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
object_property_add(obj, name, type, object_get_child_property,
@@ -1022,10 +977,6 @@ gchar *object_get_canonical_path(Object *obj)
Object *root = object_get_root();
char *newpath = NULL, *path = NULL;
- if (object_is_type(obj, type_interface)) {
- obj = INTERFACE(obj)->obj;
- }
-
while (obj != root) {
ObjectProperty *prop = NULL;
@@ -1246,7 +1197,7 @@ static void register_types(void)
{
static TypeInfo interface_info = {
.name = TYPE_INTERFACE,
- .instance_size = sizeof(Interface),
+ .class_size = sizeof(InterfaceClass),
.abstract = true,
};
diff --git a/rules.mak b/rules.mak
index a284946..1b173aa 100644
--- a/rules.mak
+++ b/rules.mak
@@ -29,7 +29,7 @@ endif
$(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@")
%.o: %.m
- $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@")
+ $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@")
LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(sort $(1)) $(LIBS)," LINK $(TARGET_DIR)$@")
diff --git a/savevm.c b/savevm.c
index 6e82b2d..c7fe283 100644
--- a/savevm.c
+++ b/savevm.c
@@ -513,7 +513,7 @@ static void qemu_fill_buffer(QEMUFile *f)
*
* Returns f->close() return value, or 0 if close function is not set.
*/
-static int qemu_close(QEMUFile *f)
+static int qemu_fclose_internal(QEMUFile *f)
{
int ret = 0;
if (f->close) {
@@ -535,7 +535,7 @@ int qemu_fclose(QEMUFile *f)
{
int ret;
qemu_fflush(f);
- ret = qemu_close(f);
+ ret = qemu_fclose_internal(f);
/* If any error was spotted before closing, we should report it
* instead of the close() return value.
*/
@@ -2392,3 +2392,162 @@ void vmstate_register_ram_global(MemoryRegion *mr)
{
vmstate_register_ram(mr, NULL);
}
+
+/*
+ page = zrun nzrun
+ | zrun nzrun page
+
+ zrun = length
+
+ nzrun = length byte...
+
+ length = uleb128 encoded integer
+ */
+int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
+ uint8_t *dst, int dlen)
+{
+ uint32_t zrun_len = 0, nzrun_len = 0;
+ int d = 0, i = 0;
+ long res, xor;
+ uint8_t *nzrun_start = NULL;
+
+ g_assert(!(((uintptr_t)old_buf | (uintptr_t)new_buf | slen) %
+ sizeof(long)));
+
+ while (i < slen) {
+ /* overflow */
+ if (d + 2 > dlen) {
+ return -1;
+ }
+
+ /* not aligned to sizeof(long) */
+ res = (slen - i) % sizeof(long);
+ while (res && old_buf[i] == new_buf[i]) {
+ zrun_len++;
+ i++;
+ res--;
+ }
+
+ /* word at a time for speed */
+ if (!res) {
+ while (i < slen &&
+ (*(long *)(old_buf + i)) == (*(long *)(new_buf + i))) {
+ i += sizeof(long);
+ zrun_len += sizeof(long);
+ }
+
+ /* go over the rest */
+ while (i < slen && old_buf[i] == new_buf[i]) {
+ zrun_len++;
+ i++;
+ }
+ }
+
+ /* buffer unchanged */
+ if (zrun_len == slen) {
+ return 0;
+ }
+
+ /* skip last zero run */
+ if (i == slen) {
+ return d;
+ }
+
+ d += uleb128_encode_small(dst + d, zrun_len);
+
+ zrun_len = 0;
+ nzrun_start = new_buf + i;
+
+ /* overflow */
+ if (d + 2 > dlen) {
+ return -1;
+ }
+ /* not aligned to sizeof(long) */
+ res = (slen - i) % sizeof(long);
+ while (res && old_buf[i] != new_buf[i]) {
+ i++;
+ nzrun_len++;
+ res--;
+ }
+
+ /* word at a time for speed, use of 32-bit long okay */
+ if (!res) {
+ /* truncation to 32-bit long okay */
+ long mask = (long)0x0101010101010101ULL;
+ while (i < slen) {
+ xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i);
+ if ((xor - mask) & ~xor & (mask << 7)) {
+ /* found the end of an nzrun within the current long */
+ while (old_buf[i] != new_buf[i]) {
+ nzrun_len++;
+ i++;
+ }
+ break;
+ } else {
+ i += sizeof(long);
+ nzrun_len += sizeof(long);
+ }
+ }
+ }
+
+ d += uleb128_encode_small(dst + d, nzrun_len);
+ /* overflow */
+ if (d + nzrun_len > dlen) {
+ return -1;
+ }
+ memcpy(dst + d, nzrun_start, nzrun_len);
+ d += nzrun_len;
+ nzrun_len = 0;
+ }
+
+ return d;
+}
+
+int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen)
+{
+ int i = 0, d = 0;
+ int ret;
+ uint32_t count = 0;
+
+ while (i < slen) {
+
+ /* zrun */
+ if ((slen - i) < 2) {
+ return -1;
+ }
+
+ ret = uleb128_decode_small(src + i, &count);
+ if (ret < 0 || (i && !count)) {
+ return -1;
+ }
+ i += ret;
+ d += count;
+
+ /* overflow */
+ if (d > dlen) {
+ return -1;
+ }
+
+ /* nzrun */
+ if ((slen - i) < 2) {
+ return -1;
+ }
+
+ ret = uleb128_decode_small(src + i, &count);
+ if (ret < 0 || !count) {
+ return -1;
+ }
+ i += ret;
+
+ /* overflow */
+ if (d + count > dlen || i + count > slen) {
+ return -1;
+ }
+
+ memcpy(dst + d, src + i, count);
+ d += count;
+ i += count;
+ }
+
+ return d;
+}
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 9eed40e..3c4678d 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -342,6 +342,7 @@ def gen_command_decl_prologue(header, guard, prefix=""):
#define %(guard)s
#include "%(prefix)sqapi-types.h"
+#include "qdict.h"
#include "error.h"
''',
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 4a734f5..cf601ae 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -70,7 +70,7 @@ const char *%(name)s_lookup[] = {
ret += mcgen('''
"%(value)s",
''',
- value=value.lower())
+ value=value)
ret += mcgen('''
NULL,
@@ -79,6 +79,16 @@ const char *%(name)s_lookup[] = {
''')
return ret
+def generate_enum_name(name):
+ if name.isupper():
+ return c_fun(name)
+ new_name = ''
+ for c in c_fun(name):
+ if c.isupper():
+ new_name += '_'
+ new_name += c
+ return new_name.lstrip('_').upper()
+
def generate_enum(name, values):
lookup_decl = mcgen('''
extern const char *%(name)s_lookup[];
@@ -100,7 +110,7 @@ typedef enum %(name)s
%(abbrev)s_%(value)s = %(i)d,
''',
abbrev=de_camel_case(name).upper(),
- value=c_fun(value).upper(),
+ value=generate_enum_name(value),
i=i)
i += 1
@@ -253,7 +263,8 @@ fdecl.write(mcgen('''
#ifndef %(guard)s
#define %(guard)s
-#include "qapi/qapi-types-core.h"
+#include "qemu-common.h"
+
''',
guard=guardname(h_file)))
diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py
index 9b4419f..8bbcb42 100755
--- a/scripts/simpletrace.py
+++ b/scripts/simpletrace.py
@@ -71,7 +71,7 @@ def read_trace_file(edict, fobj):
log_version = header[2]
if log_version == 0:
- raise ValueError('Older log format, not supported with this Qemu release!')
+ raise ValueError('Older log format, not supported with this QEMU release!')
while True:
rec = read_record(edict, fobj)
diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py
index c7e47d6..e4b4a7f 100644
--- a/scripts/tracetool/backend/simple.py
+++ b/scripts/tracetool/backend/simple.py
@@ -79,7 +79,7 @@ def c(events):
)
# pointer var (not string)
elif type_.endswith('*'):
- out(' trace_record_write_u64(&rec, (uint64_t)(uint64_t *)%(name)s);',
+ out(' trace_record_write_u64(&rec, (uintptr_t)(uint64_t *)%(name)s);',
name = name,
)
# primitive data type
diff --git a/softmmu-semi.h b/softmmu-semi.h
index 648cb95..bcb979a 100644
--- a/softmmu-semi.h
+++ b/softmmu-semi.h
@@ -40,7 +40,7 @@ static void *softmmu_lock_user(CPUArchState *env, uint32_t addr, uint32_t len,
uint8_t *p;
/* TODO: Make this something that isn't fixed size. */
p = malloc(len);
- if (copy)
+ if (p && copy)
cpu_memory_rw_debug(env, addr, p, len, 0);
return p;
}
@@ -52,6 +52,9 @@ static char *softmmu_lock_user_string(CPUArchState *env, uint32_t addr)
uint8_t c;
/* TODO: Make this something that isn't fixed size. */
s = p = malloc(1024);
+ if (!s) {
+ return NULL;
+ }
do {
cpu_memory_rw_debug(env, addr, &c, 1, 0);
addr++;
diff --git a/sysemu.h b/sysemu.h
index 4669348..65552ac 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -62,6 +62,7 @@ int qemu_powerdown_requested(void);
void qemu_system_killed(int signal, pid_t pid);
void qemu_kill_report(void);
extern qemu_irq qemu_system_powerdown;
+void qemu_devices_reset(void);
void qemu_system_reset(bool report);
void qemu_add_exit_notifier(Notifier *notify);
diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c
index 88ca9bb..73bde58 100644
--- a/target-arm/arm-semi.c
+++ b/target-arm/arm-semi.c
@@ -194,18 +194,19 @@ uint32_t do_arm_semihosting(CPUARMState *env)
if (!(s = lock_user_string(ARG(0))))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
- if (ARG(1) >= 12)
+ if (ARG(1) >= 12) {
+ unlock_user(s, ARG(0), 0);
return (uint32_t)-1;
+ }
if (strcmp(s, ":tt") == 0) {
- if (ARG(1) < 4)
- return STDIN_FILENO;
- else
- return STDOUT_FILENO;
+ int result_fileno = ARG(1) < 4 ? STDIN_FILENO : STDOUT_FILENO;
+ unlock_user(s, ARG(0), 0);
+ return result_fileno;
}
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
(int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
- return env->regs[0];
+ ret = env->regs[0];
} else {
ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
}
@@ -281,7 +282,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
return len - ret;
}
case TARGET_SYS_READC:
- /* XXX: Read from debug cosole. Not implemented. */
+ /* XXX: Read from debug console. Not implemented. */
return 0;
case TARGET_SYS_ISTTY:
if (use_gdb_syscalls()) {
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 2825700..4364f7e 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -80,7 +80,7 @@ struct arm_boot_info;
typedef struct CPUARMState {
/* Regs for current mode. */
uint32_t regs[16];
- /* Frequently accessed CPSR bits are stored separately for efficiently.
+ /* Frequently accessed CPSR bits are stored separately for efficiency.
This contains all the other bits. Use cpsr_{read,write} to access
the whole CPSR. */
uint32_t uncached_cpsr;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index aa93b96..c24c248 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -985,7 +985,7 @@ static void ttbr164_reset(CPUARMState *env, const ARMCPRegInfo *ri)
}
static const ARMCPRegInfo lpae_cp_reginfo[] = {
- /* NOP AMAIR0/1: the override is because these clash with tha rather
+ /* NOP AMAIR0/1: the override is because these clash with the rather
* broadly specified TLB_LOCKDOWN entry in the generic cp_reginfo.
*/
{ .name = "AMAIR0", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
@@ -2956,8 +2956,8 @@ uint32_t HELPER(logicq_cc)(uint64_t val)
return (val >> 32) | (val != 0);
}
-/* VFP support. We follow the convention used for VFP instrunctions:
- Single precition routines have a "s" suffix, double precision a
+/* VFP support. We follow the convention used for VFP instructions:
+ Single precision routines have a "s" suffix, double precision a
"d" suffix. */
/* Convert host exception flags to vfp form. */
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index e0b9dbf..8bb5129 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -530,7 +530,7 @@ NEON_VOP(rshl_s16, neon_s16, 2)
#undef NEON_FN
/* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator. */
+ * intermediate 64 bit accumulator. */
uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
{
int32_t dest;
@@ -547,8 +547,8 @@ uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
return dest;
}
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values. */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values. */
uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
{
int8_t shift = (int8_t)shiftop;
@@ -590,7 +590,7 @@ NEON_VOP(rshl_u16, neon_u16, 2)
#undef NEON_FN
/* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator. */
+ * intermediate 64 bit accumulator. */
uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
{
uint32_t dest;
@@ -608,8 +608,8 @@ uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
return dest;
}
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values. */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values. */
uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
{
int8_t shift = (uint8_t)shiftop;
@@ -817,7 +817,7 @@ NEON_VOP_ENV(qrshl_u16, neon_u16, 2)
#undef NEON_FN
/* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator. */
+ * intermediate 64 bit accumulator. */
uint32_t HELPER(neon_qrshl_u32)(CPUARMState *env, uint32_t val, uint32_t shiftop)
{
uint32_t dest;
@@ -846,8 +846,8 @@ uint32_t HELPER(neon_qrshl_u32)(CPUARMState *env, uint32_t val, uint32_t shiftop
return dest;
}
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values. */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values. */
uint64_t HELPER(neon_qrshl_u64)(CPUARMState *env, uint64_t val, uint64_t shiftop)
{
int8_t shift = (int8_t)shiftop;
@@ -914,7 +914,7 @@ NEON_VOP_ENV(qrshl_s16, neon_s16, 2)
#undef NEON_FN
/* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator. */
+ * intermediate 64 bit accumulator. */
uint32_t HELPER(neon_qrshl_s32)(CPUARMState *env, uint32_t valop, uint32_t shiftop)
{
int32_t dest;
@@ -942,8 +942,8 @@ uint32_t HELPER(neon_qrshl_s32)(CPUARMState *env, uint32_t valop, uint32_t shift
return dest;
}
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values. */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values. */
uint64_t HELPER(neon_qrshl_s64)(CPUARMState *env, uint64_t valop, uint64_t shiftop)
{
int8_t shift = (uint8_t)shiftop;
@@ -1671,7 +1671,7 @@ uint64_t HELPER(neon_negl_u64)(uint64_t x)
return -x;
}
-/* Saturnating sign manuipulation. */
+/* Saturating sign manipulation. */
/* ??? Make these use NEON_VOP1 */
#define DO_QABS8(x) do { \
if (x == (int8_t)0x80) { \
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 490111c..d77bfab 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -99,7 +99,7 @@ void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx,
}
#endif
-/* FIXME: Pass an axplicit pointer to QF to CPUARMState, and move saturating
+/* FIXME: Pass an explicit pointer to QF to CPUARMState, and move saturating
instructions into helper.c */
uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
{
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 839f237..369f710 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -53,7 +53,7 @@ typedef struct DisasContext {
int condjmp;
/* The label that will be jumped to when the instruction is skipped. */
int condlabel;
- /* Thumb-2 condtional execution bits. */
+ /* Thumb-2 conditional execution bits. */
int condexec_mask;
int condexec_cond;
struct TranslationBlock *tb;
@@ -77,7 +77,7 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
#endif
/* These instructions trap after executing, so defer them until after the
- conditional executions state has been updated. */
+ conditional execution state has been updated. */
#define DISAS_WFI 4
#define DISAS_SWI 5
#define DISAS_SMC 6
@@ -156,7 +156,7 @@ static void load_reg_var(DisasContext *s, TCGv var, int reg)
{
if (reg == 15) {
uint32_t addr;
- /* normaly, since we updated PC, we need only to add one insn */
+ /* normally, since we updated PC, we need only to add one insn */
if (s->thumb)
addr = (long)s->pc + 2;
else
@@ -4904,7 +4904,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
size--;
}
shift = (insn >> 16) & ((1 << (3 + size)) - 1);
- /* To avoid excessive dumplication of ops we implement shift
+ /* To avoid excessive duplication of ops we implement shift
by immediate using the variable shift operations. */
if (op < 8) {
/* Shift by immediate:
@@ -6409,7 +6409,7 @@ static void gen_logicq_cc(TCGv_i64 val)
/* Load/Store exclusive instructions are implemented by remembering
the value/address loaded, and seeing if these are the same
- when the store is performed. This should be is sufficient to implement
+ when the store is performed. This should be sufficient to implement
the architecturally mandated semantics, and avoids having to monitor
regular stores.
@@ -9916,7 +9916,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
} else {
/* While branches must always occur at the end of an IT block,
there are a few other things that can cause us to terminate
- the TB in the middel of an IT block:
+ the TB in the middle of an IT block:
- Exception generating instructions (bkpt, swi, undefined).
- Page boundaries.
- Hardware watchpoints.
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index 0715f58..c1d4f05 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -6,12 +6,3 @@ obj-$(CONFIG_KVM) += kvm.o hyperv.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-$(CONFIG_LINUX_USER) += ioport-user.o
obj-$(CONFIG_BSD_USER) += ioport-user.o
-
-$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
-$(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
-$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
-$(obj)/svm_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
-$(obj)/smm_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
-$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
-$(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
-$(obj)/seg_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c
index ff654bc..07892f9 100644
--- a/target-i386/cc_helper.c
+++ b/target-i386/cc_helper.c
@@ -18,7 +18,6 @@
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
const uint8_t parity_table[256] = {
@@ -76,184 +75,177 @@ const uint8_t parity_table[256] = {
#endif
-static int compute_all_eflags(void)
+static int compute_all_eflags(CPUX86State *env)
{
return CC_SRC;
}
-static int compute_c_eflags(void)
+static int compute_c_eflags(CPUX86State *env)
{
return CC_SRC & CC_C;
}
-uint32_t helper_cc_compute_all(int op)
+uint32_t helper_cc_compute_all(CPUX86State *env, int op)
{
switch (op) {
default: /* should never happen */
return 0;
case CC_OP_EFLAGS:
- return compute_all_eflags();
+ return compute_all_eflags(env);
case CC_OP_MULB:
- return compute_all_mulb();
+ return compute_all_mulb(env);
case CC_OP_MULW:
- return compute_all_mulw();
+ return compute_all_mulw(env);
case CC_OP_MULL:
- return compute_all_mull();
+ return compute_all_mull(env);
case CC_OP_ADDB:
- return compute_all_addb();
+ return compute_all_addb(env);
case CC_OP_ADDW:
- return compute_all_addw();
+ return compute_all_addw(env);
case CC_OP_ADDL:
- return compute_all_addl();
+ return compute_all_addl(env);
case CC_OP_ADCB:
- return compute_all_adcb();
+ return compute_all_adcb(env);
case CC_OP_ADCW:
- return compute_all_adcw();
+ return compute_all_adcw(env);
case CC_OP_ADCL:
- return compute_all_adcl();
+ return compute_all_adcl(env);
case CC_OP_SUBB:
- return compute_all_subb();
+ return compute_all_subb(env);
case CC_OP_SUBW:
- return compute_all_subw();
+ return compute_all_subw(env);
case CC_OP_SUBL:
- return compute_all_subl();
+ return compute_all_subl(env);
case CC_OP_SBBB:
- return compute_all_sbbb();
+ return compute_all_sbbb(env);
case CC_OP_SBBW:
- return compute_all_sbbw();
+ return compute_all_sbbw(env);
case CC_OP_SBBL:
- return compute_all_sbbl();
+ return compute_all_sbbl(env);
case CC_OP_LOGICB:
- return compute_all_logicb();
+ return compute_all_logicb(env);
case CC_OP_LOGICW:
- return compute_all_logicw();
+ return compute_all_logicw(env);
case CC_OP_LOGICL:
- return compute_all_logicl();
+ return compute_all_logicl(env);
case CC_OP_INCB:
- return compute_all_incb();
+ return compute_all_incb(env);
case CC_OP_INCW:
- return compute_all_incw();
+ return compute_all_incw(env);
case CC_OP_INCL:
- return compute_all_incl();
+ return compute_all_incl(env);
case CC_OP_DECB:
- return compute_all_decb();
+ return compute_all_decb(env);
case CC_OP_DECW:
- return compute_all_decw();
+ return compute_all_decw(env);
case CC_OP_DECL:
- return compute_all_decl();
+ return compute_all_decl(env);
case CC_OP_SHLB:
- return compute_all_shlb();
+ return compute_all_shlb(env);
case CC_OP_SHLW:
- return compute_all_shlw();
+ return compute_all_shlw(env);
case CC_OP_SHLL:
- return compute_all_shll();
+ return compute_all_shll(env);
case CC_OP_SARB:
- return compute_all_sarb();
+ return compute_all_sarb(env);
case CC_OP_SARW:
- return compute_all_sarw();
+ return compute_all_sarw(env);
case CC_OP_SARL:
- return compute_all_sarl();
+ return compute_all_sarl(env);
#ifdef TARGET_X86_64
case CC_OP_MULQ:
- return compute_all_mulq();
+ return compute_all_mulq(env);
case CC_OP_ADDQ:
- return compute_all_addq();
+ return compute_all_addq(env);
case CC_OP_ADCQ:
- return compute_all_adcq();
+ return compute_all_adcq(env);
case CC_OP_SUBQ:
- return compute_all_subq();
+ return compute_all_subq(env);
case CC_OP_SBBQ:
- return compute_all_sbbq();
+ return compute_all_sbbq(env);
case CC_OP_LOGICQ:
- return compute_all_logicq();
+ return compute_all_logicq(env);
case CC_OP_INCQ:
- return compute_all_incq();
+ return compute_all_incq(env);
case CC_OP_DECQ:
- return compute_all_decq();
+ return compute_all_decq(env);
case CC_OP_SHLQ:
- return compute_all_shlq();
+ return compute_all_shlq(env);
case CC_OP_SARQ:
- return compute_all_sarq();
+ return compute_all_sarq(env);
#endif
}
}
-uint32_t cpu_cc_compute_all(CPUX86State *env1, int op)
+uint32_t cpu_cc_compute_all(CPUX86State *env, int op)
{
- CPUX86State *saved_env;
- uint32_t ret;
-
- saved_env = env;
- env = env1;
- ret = helper_cc_compute_all(op);
- env = saved_env;
- return ret;
+ return helper_cc_compute_all(env, op);
}
-uint32_t helper_cc_compute_c(int op)
+uint32_t helper_cc_compute_c(CPUX86State *env, int op)
{
switch (op) {
default: /* should never happen */
return 0;
case CC_OP_EFLAGS:
- return compute_c_eflags();
+ return compute_c_eflags(env);
case CC_OP_MULB:
- return compute_c_mull();
+ return compute_c_mull(env);
case CC_OP_MULW:
- return compute_c_mull();
+ return compute_c_mull(env);
case CC_OP_MULL:
- return compute_c_mull();
+ return compute_c_mull(env);
case CC_OP_ADDB:
- return compute_c_addb();
+ return compute_c_addb(env);
case CC_OP_ADDW:
- return compute_c_addw();
+ return compute_c_addw(env);
case CC_OP_ADDL:
- return compute_c_addl();
+ return compute_c_addl(env);
case CC_OP_ADCB:
- return compute_c_adcb();
+ return compute_c_adcb(env);
case CC_OP_ADCW:
- return compute_c_adcw();
+ return compute_c_adcw(env);
case CC_OP_ADCL:
- return compute_c_adcl();
+ return compute_c_adcl(env);
case CC_OP_SUBB:
- return compute_c_subb();
+ return compute_c_subb(env);
case CC_OP_SUBW:
- return compute_c_subw();
+ return compute_c_subw(env);
case CC_OP_SUBL:
- return compute_c_subl();
+ return compute_c_subl(env);
case CC_OP_SBBB:
- return compute_c_sbbb();
+ return compute_c_sbbb(env);
case CC_OP_SBBW:
- return compute_c_sbbw();
+ return compute_c_sbbw(env);
case CC_OP_SBBL:
- return compute_c_sbbl();
+ return compute_c_sbbl(env);
case CC_OP_LOGICB:
return compute_c_logicb();
@@ -263,111 +255,112 @@ uint32_t helper_cc_compute_c(int op)
return compute_c_logicl();
case CC_OP_INCB:
- return compute_c_incl();
+ return compute_c_incl(env);
case CC_OP_INCW:
- return compute_c_incl();
+ return compute_c_incl(env);
case CC_OP_INCL:
- return compute_c_incl();
+ return compute_c_incl(env);
case CC_OP_DECB:
- return compute_c_incl();
+ return compute_c_incl(env);
case CC_OP_DECW:
- return compute_c_incl();
+ return compute_c_incl(env);
case CC_OP_DECL:
- return compute_c_incl();
+ return compute_c_incl(env);
case CC_OP_SHLB:
- return compute_c_shlb();
+ return compute_c_shlb(env);
case CC_OP_SHLW:
- return compute_c_shlw();
+ return compute_c_shlw(env);
case CC_OP_SHLL:
- return compute_c_shll();
+ return compute_c_shll(env);
case CC_OP_SARB:
- return compute_c_sarl();
+ return compute_c_sarl(env);
case CC_OP_SARW:
- return compute_c_sarl();
+ return compute_c_sarl(env);
case CC_OP_SARL:
- return compute_c_sarl();
+ return compute_c_sarl(env);
#ifdef TARGET_X86_64
case CC_OP_MULQ:
- return compute_c_mull();
+ return compute_c_mull(env);
case CC_OP_ADDQ:
- return compute_c_addq();
+ return compute_c_addq(env);
case CC_OP_ADCQ:
- return compute_c_adcq();
+ return compute_c_adcq(env);
case CC_OP_SUBQ:
- return compute_c_subq();
+ return compute_c_subq(env);
case CC_OP_SBBQ:
- return compute_c_sbbq();
+ return compute_c_sbbq(env);
case CC_OP_LOGICQ:
return compute_c_logicq();
case CC_OP_INCQ:
- return compute_c_incl();
+ return compute_c_incl(env);
case CC_OP_DECQ:
- return compute_c_incl();
+ return compute_c_incl(env);
case CC_OP_SHLQ:
- return compute_c_shlq();
+ return compute_c_shlq(env);
case CC_OP_SARQ:
- return compute_c_sarl();
+ return compute_c_sarl(env);
#endif
}
}
-void helper_write_eflags(target_ulong t0, uint32_t update_mask)
+void helper_write_eflags(CPUX86State *env, target_ulong t0,
+ uint32_t update_mask)
{
cpu_load_eflags(env, t0, update_mask);
}
-target_ulong helper_read_eflags(void)
+target_ulong helper_read_eflags(CPUX86State *env)
{
uint32_t eflags;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = helper_cc_compute_all(env, CC_OP);
eflags |= (DF & DF_MASK);
eflags |= env->eflags & ~(VM_MASK | RF_MASK);
return eflags;
}
-void helper_clts(void)
+void helper_clts(CPUX86State *env)
{
env->cr[0] &= ~CR0_TS_MASK;
env->hflags &= ~HF_TS_MASK;
}
-void helper_reset_rf(void)
+void helper_reset_rf(CPUX86State *env)
{
env->eflags &= ~RF_MASK;
}
-void helper_cli(void)
+void helper_cli(CPUX86State *env)
{
env->eflags &= ~IF_MASK;
}
-void helper_sti(void)
+void helper_sti(CPUX86State *env)
{
env->eflags |= IF_MASK;
}
#if 0
/* vm86plus instructions */
-void helper_cli_vm(void)
+void helper_cli_vm(CPUX86State *env)
{
env->eflags &= ~VIF_MASK;
}
-void helper_sti_vm(void)
+void helper_sti_vm(CPUX86State *env)
{
env->eflags |= VIF_MASK;
if (env->eflags & VIP_MASK) {
@@ -376,12 +369,12 @@ void helper_sti_vm(void)
}
#endif
-void helper_set_inhibit_irq(void)
+void helper_set_inhibit_irq(CPUX86State *env)
{
env->hflags |= HF_INHIBIT_IRQ_MASK;
}
-void helper_reset_inhibit_irq(void)
+void helper_reset_inhibit_irq(CPUX86State *env)
{
env->hflags &= ~HF_INHIBIT_IRQ_MASK;
}
diff --git a/target-i386/cc_helper_template.h b/target-i386/cc_helper_template.h
index ff22830..1f94e11 100644
--- a/target-i386/cc_helper_template.h
+++ b/target-i386/cc_helper_template.h
@@ -42,7 +42,7 @@
/* dynamic flags computation */
-static int glue(compute_all_add, SUFFIX)(void)
+static int glue(compute_all_add, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
target_long src1, src2;
@@ -58,7 +58,7 @@ static int glue(compute_all_add, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_add, SUFFIX)(void)
+static int glue(compute_c_add, SUFFIX)(CPUX86State *env)
{
int cf;
target_long src1;
@@ -68,7 +68,7 @@ static int glue(compute_c_add, SUFFIX)(void)
return cf;
}
-static int glue(compute_all_adc, SUFFIX)(void)
+static int glue(compute_all_adc, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
target_long src1, src2;
@@ -84,7 +84,7 @@ static int glue(compute_all_adc, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_adc, SUFFIX)(void)
+static int glue(compute_c_adc, SUFFIX)(CPUX86State *env)
{
int cf;
target_long src1;
@@ -94,7 +94,7 @@ static int glue(compute_c_adc, SUFFIX)(void)
return cf;
}
-static int glue(compute_all_sub, SUFFIX)(void)
+static int glue(compute_all_sub, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
target_long src1, src2;
@@ -110,7 +110,7 @@ static int glue(compute_all_sub, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_sub, SUFFIX)(void)
+static int glue(compute_c_sub, SUFFIX)(CPUX86State *env)
{
int cf;
target_long src1, src2;
@@ -121,7 +121,7 @@ static int glue(compute_c_sub, SUFFIX)(void)
return cf;
}
-static int glue(compute_all_sbb, SUFFIX)(void)
+static int glue(compute_all_sbb, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
target_long src1, src2;
@@ -137,7 +137,7 @@ static int glue(compute_all_sbb, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_sbb, SUFFIX)(void)
+static int glue(compute_c_sbb, SUFFIX)(CPUX86State *env)
{
int cf;
target_long src1, src2;
@@ -148,7 +148,7 @@ static int glue(compute_c_sbb, SUFFIX)(void)
return cf;
}
-static int glue(compute_all_logic, SUFFIX)(void)
+static int glue(compute_all_logic, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
@@ -166,7 +166,7 @@ static int glue(compute_c_logic, SUFFIX)(void)
return 0;
}
-static int glue(compute_all_inc, SUFFIX)(void)
+static int glue(compute_all_inc, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
target_long src1, src2;
@@ -183,13 +183,13 @@ static int glue(compute_all_inc, SUFFIX)(void)
}
#if DATA_BITS == 32
-static int glue(compute_c_inc, SUFFIX)(void)
+static int glue(compute_c_inc, SUFFIX)(CPUX86State *env)
{
return CC_SRC;
}
#endif
-static int glue(compute_all_dec, SUFFIX)(void)
+static int glue(compute_all_dec, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
target_long src1, src2;
@@ -205,7 +205,7 @@ static int glue(compute_all_dec, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_all_shl, SUFFIX)(void)
+static int glue(compute_all_shl, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
@@ -219,19 +219,19 @@ static int glue(compute_all_shl, SUFFIX)(void)
return cf | pf | af | zf | sf | of;
}
-static int glue(compute_c_shl, SUFFIX)(void)
+static int glue(compute_c_shl, SUFFIX)(CPUX86State *env)
{
return (CC_SRC >> (DATA_BITS - 1)) & CC_C;
}
#if DATA_BITS == 32
-static int glue(compute_c_sar, SUFFIX)(void)
+static int glue(compute_c_sar, SUFFIX)(CPUX86State *env)
{
return CC_SRC & 1;
}
#endif
-static int glue(compute_all_sar, SUFFIX)(void)
+static int glue(compute_all_sar, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
@@ -246,7 +246,7 @@ static int glue(compute_all_sar, SUFFIX)(void)
}
#if DATA_BITS == 32
-static int glue(compute_c_mul, SUFFIX)(void)
+static int glue(compute_c_mul, SUFFIX)(CPUX86State *env)
{
int cf;
@@ -257,7 +257,7 @@ static int glue(compute_c_mul, SUFFIX)(void)
/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
CF are modified and it is slower to do that. */
-static int glue(compute_all_mul, SUFFIX)(void)
+static int glue(compute_all_mul, SUFFIX)(CPUX86State *env)
{
int cf, pf, af, zf, sf, of;
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 880cfea..423e009 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -28,10 +28,14 @@
#include "qemu-config.h"
#include "qapi/qapi-visit-core.h"
+#include "arch_init.h"
#include "hyperv.h"
#include "hw/hw.h"
+#if defined(CONFIG_KVM)
+#include <linux/kvm_para.h>
+#endif
/* feature flags taken from "Intel Processor Identification and the CPUID
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
@@ -886,7 +890,17 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
memcpy(x86_cpu_def, def, sizeof(*def));
}
- plus_kvm_features = ~0; /* not supported bits will be filtered out later */
+#if defined(CONFIG_KVM)
+ plus_kvm_features = (1 << KVM_FEATURE_CLOCKSOURCE) |
+ (1 << KVM_FEATURE_NOP_IO_DELAY) |
+ (1 << KVM_FEATURE_MMU_OP) |
+ (1 << KVM_FEATURE_CLOCKSOURCE2) |
+ (1 << KVM_FEATURE_ASYNC_PF) |
+ (1 << KVM_FEATURE_STEAL_TIME) |
+ (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
+#else
+ plus_kvm_features = 0;
+#endif
add_flagname_to_bitmaps("hypervisor", &plus_features,
&plus_ext_features, &plus_ext2_features, &plus_ext3_features,
@@ -1125,6 +1139,27 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
}
}
+CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
+{
+ CpuDefinitionInfoList *cpu_list = NULL;
+ x86_def_t *def;
+
+ for (def = x86_defs; def; def = def->next) {
+ CpuDefinitionInfoList *entry;
+ CpuDefinitionInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(def->name);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = cpu_list;
+ cpu_list = entry;
+ }
+
+ return cpu_list;
+}
+
int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
{
CPUX86State *env = &cpu->env;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 60f9e97..0677502 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -699,6 +699,7 @@ typedef struct CPUX86State {
uint64_t system_time_msr;
uint64_t wall_clock_msr;
uint64_t async_pf_en_msr;
+ uint64_t pv_eoi_en_msr;
uint64_t tsc;
uint64_t tsc_deadline;
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index 6065c2e..dfc34a6 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -19,7 +19,6 @@
#include <math.h>
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
#if !defined(CONFIG_USER_ONLY)
@@ -58,39 +57,39 @@
#define floatx80_l2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcLL)
#define floatx80_l2t make_floatx80(0x4000, 0xd49a784bcd1b8afeLL)
-static inline void fpush(void)
+static inline void fpush(CPUX86State *env)
{
env->fpstt = (env->fpstt - 1) & 7;
env->fptags[env->fpstt] = 0; /* validate stack entry */
}
-static inline void fpop(void)
+static inline void fpop(CPUX86State *env)
{
env->fptags[env->fpstt] = 1; /* invalidate stack entry */
env->fpstt = (env->fpstt + 1) & 7;
}
-static inline floatx80 helper_fldt(target_ulong ptr)
+static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr)
{
CPU_LDoubleU temp;
- temp.l.lower = ldq(ptr);
- temp.l.upper = lduw(ptr + 8);
+ temp.l.lower = cpu_ldq_data(env, ptr);
+ temp.l.upper = cpu_lduw_data(env, ptr + 8);
return temp.d;
}
-static inline void helper_fstt(floatx80 f, target_ulong ptr)
+static inline void helper_fstt(CPUX86State *env, floatx80 f, target_ulong ptr)
{
CPU_LDoubleU temp;
temp.d = f;
- stq(ptr, temp.l.lower);
- stw(ptr + 8, temp.l.upper);
+ cpu_stq_data(env, ptr, temp.l.lower);
+ cpu_stw_data(env, ptr + 8, temp.l.upper);
}
/* x87 FPU helpers */
-static inline double floatx80_to_double(floatx80 a)
+static inline double floatx80_to_double(CPUX86State *env, floatx80 a)
{
union {
float64 f64;
@@ -101,7 +100,7 @@ static inline double floatx80_to_double(floatx80 a)
return u.d;
}
-static inline floatx80 double_to_floatx80(double a)
+static inline floatx80 double_to_floatx80(CPUX86State *env, double a)
{
union {
float64 f64;
@@ -112,7 +111,7 @@ static inline floatx80 double_to_floatx80(double a)
return float64_to_floatx80(u.f64, &env->fp_status);
}
-static void fpu_set_exception(int mask)
+static void fpu_set_exception(CPUX86State *env, int mask)
{
env->fpus |= mask;
if (env->fpus & (~env->fpuc & FPUC_EM)) {
@@ -120,15 +119,15 @@ static void fpu_set_exception(int mask)
}
}
-static inline floatx80 helper_fdiv(floatx80 a, floatx80 b)
+static inline floatx80 helper_fdiv(CPUX86State *env, floatx80 a, floatx80 b)
{
if (floatx80_is_zero(b)) {
- fpu_set_exception(FPUS_ZE);
+ fpu_set_exception(env, FPUS_ZE);
}
return floatx80_div(a, b, &env->fp_status);
}
-static void fpu_raise_exception(void)
+static void fpu_raise_exception(CPUX86State *env)
{
if (env->cr[0] & CR0_NE_MASK) {
raise_exception(env, EXCP10_COPR);
@@ -140,7 +139,7 @@ static void fpu_raise_exception(void)
#endif
}
-void helper_flds_FT0(uint32_t val)
+void helper_flds_FT0(CPUX86State *env, uint32_t val)
{
union {
float32 f;
@@ -151,7 +150,7 @@ void helper_flds_FT0(uint32_t val)
FT0 = float32_to_floatx80(u.f, &env->fp_status);
}
-void helper_fldl_FT0(uint64_t val)
+void helper_fldl_FT0(CPUX86State *env, uint64_t val)
{
union {
float64 f;
@@ -162,12 +161,12 @@ void helper_fldl_FT0(uint64_t val)
FT0 = float64_to_floatx80(u.f, &env->fp_status);
}
-void helper_fildl_FT0(int32_t val)
+void helper_fildl_FT0(CPUX86State *env, int32_t val)
{
FT0 = int32_to_floatx80(val, &env->fp_status);
}
-void helper_flds_ST0(uint32_t val)
+void helper_flds_ST0(CPUX86State *env, uint32_t val)
{
int new_fpstt;
union {
@@ -182,7 +181,7 @@ void helper_flds_ST0(uint32_t val)
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
-void helper_fldl_ST0(uint64_t val)
+void helper_fldl_ST0(CPUX86State *env, uint64_t val)
{
int new_fpstt;
union {
@@ -197,7 +196,7 @@ void helper_fldl_ST0(uint64_t val)
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
-void helper_fildl_ST0(int32_t val)
+void helper_fildl_ST0(CPUX86State *env, int32_t val)
{
int new_fpstt;
@@ -207,7 +206,7 @@ void helper_fildl_ST0(int32_t val)
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
-void helper_fildll_ST0(int64_t val)
+void helper_fildll_ST0(CPUX86State *env, int64_t val)
{
int new_fpstt;
@@ -217,7 +216,7 @@ void helper_fildll_ST0(int64_t val)
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
-uint32_t helper_fsts_ST0(void)
+uint32_t helper_fsts_ST0(CPUX86State *env)
{
union {
float32 f;
@@ -228,7 +227,7 @@ uint32_t helper_fsts_ST0(void)
return u.i;
}
-uint64_t helper_fstl_ST0(void)
+uint64_t helper_fstl_ST0(CPUX86State *env)
{
union {
float64 f;
@@ -239,7 +238,7 @@ uint64_t helper_fstl_ST0(void)
return u.i;
}
-int32_t helper_fist_ST0(void)
+int32_t helper_fist_ST0(CPUX86State *env)
{
int32_t val;
@@ -250,7 +249,7 @@ int32_t helper_fist_ST0(void)
return val;
}
-int32_t helper_fistl_ST0(void)
+int32_t helper_fistl_ST0(CPUX86State *env)
{
int32_t val;
@@ -258,7 +257,7 @@ int32_t helper_fistl_ST0(void)
return val;
}
-int64_t helper_fistll_ST0(void)
+int64_t helper_fistll_ST0(CPUX86State *env)
{
int64_t val;
@@ -266,7 +265,7 @@ int64_t helper_fistll_ST0(void)
return val;
}
-int32_t helper_fistt_ST0(void)
+int32_t helper_fistt_ST0(CPUX86State *env)
{
int32_t val;
@@ -277,7 +276,7 @@ int32_t helper_fistt_ST0(void)
return val;
}
-int32_t helper_fisttl_ST0(void)
+int32_t helper_fisttl_ST0(CPUX86State *env)
{
int32_t val;
@@ -285,7 +284,7 @@ int32_t helper_fisttl_ST0(void)
return val;
}
-int64_t helper_fisttll_ST0(void)
+int64_t helper_fisttll_ST0(CPUX86State *env)
{
int64_t val;
@@ -293,38 +292,38 @@ int64_t helper_fisttll_ST0(void)
return val;
}
-void helper_fldt_ST0(target_ulong ptr)
+void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = helper_fldt(ptr);
+ env->fpregs[new_fpstt].d = helper_fldt(env, ptr);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
-void helper_fstt_ST0(target_ulong ptr)
+void helper_fstt_ST0(CPUX86State *env, target_ulong ptr)
{
- helper_fstt(ST0, ptr);
+ helper_fstt(env, ST0, ptr);
}
-void helper_fpush(void)
+void helper_fpush(CPUX86State *env)
{
- fpush();
+ fpush(env);
}
-void helper_fpop(void)
+void helper_fpop(CPUX86State *env)
{
- fpop();
+ fpop(env);
}
-void helper_fdecstp(void)
+void helper_fdecstp(CPUX86State *env)
{
env->fpstt = (env->fpstt - 1) & 7;
env->fpus &= ~0x4700;
}
-void helper_fincstp(void)
+void helper_fincstp(CPUX86State *env)
{
env->fpstt = (env->fpstt + 1) & 7;
env->fpus &= ~0x4700;
@@ -332,32 +331,32 @@ void helper_fincstp(void)
/* FPU move */
-void helper_ffree_STN(int st_index)
+void helper_ffree_STN(CPUX86State *env, int st_index)
{
env->fptags[(env->fpstt + st_index) & 7] = 1;
}
-void helper_fmov_ST0_FT0(void)
+void helper_fmov_ST0_FT0(CPUX86State *env)
{
ST0 = FT0;
}
-void helper_fmov_FT0_STN(int st_index)
+void helper_fmov_FT0_STN(CPUX86State *env, int st_index)
{
FT0 = ST(st_index);
}
-void helper_fmov_ST0_STN(int st_index)
+void helper_fmov_ST0_STN(CPUX86State *env, int st_index)
{
ST0 = ST(st_index);
}
-void helper_fmov_STN_ST0(int st_index)
+void helper_fmov_STN_ST0(CPUX86State *env, int st_index)
{
ST(st_index) = ST0;
}
-void helper_fxchg_ST0_STN(int st_index)
+void helper_fxchg_ST0_STN(CPUX86State *env, int st_index)
{
floatx80 tmp;
@@ -370,7 +369,7 @@ void helper_fxchg_ST0_STN(int st_index)
static const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
-void helper_fcom_ST0_FT0(void)
+void helper_fcom_ST0_FT0(CPUX86State *env)
{
int ret;
@@ -378,7 +377,7 @@ void helper_fcom_ST0_FT0(void)
env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
}
-void helper_fucom_ST0_FT0(void)
+void helper_fucom_ST0_FT0(CPUX86State *env)
{
int ret;
@@ -388,158 +387,158 @@ void helper_fucom_ST0_FT0(void)
static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
-void helper_fcomi_ST0_FT0(void)
+void helper_fcomi_ST0_FT0(CPUX86State *env)
{
int eflags;
int ret;
ret = floatx80_compare(ST0, FT0, &env->fp_status);
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
CC_SRC = eflags;
}
-void helper_fucomi_ST0_FT0(void)
+void helper_fucomi_ST0_FT0(CPUX86State *env)
{
int eflags;
int ret;
ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
CC_SRC = eflags;
}
-void helper_fadd_ST0_FT0(void)
+void helper_fadd_ST0_FT0(CPUX86State *env)
{
ST0 = floatx80_add(ST0, FT0, &env->fp_status);
}
-void helper_fmul_ST0_FT0(void)
+void helper_fmul_ST0_FT0(CPUX86State *env)
{
ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
}
-void helper_fsub_ST0_FT0(void)
+void helper_fsub_ST0_FT0(CPUX86State *env)
{
ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
}
-void helper_fsubr_ST0_FT0(void)
+void helper_fsubr_ST0_FT0(CPUX86State *env)
{
ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
}
-void helper_fdiv_ST0_FT0(void)
+void helper_fdiv_ST0_FT0(CPUX86State *env)
{
- ST0 = helper_fdiv(ST0, FT0);
+ ST0 = helper_fdiv(env, ST0, FT0);
}
-void helper_fdivr_ST0_FT0(void)
+void helper_fdivr_ST0_FT0(CPUX86State *env)
{
- ST0 = helper_fdiv(FT0, ST0);
+ ST0 = helper_fdiv(env, FT0, ST0);
}
/* fp operations between STN and ST0 */
-void helper_fadd_STN_ST0(int st_index)
+void helper_fadd_STN_ST0(CPUX86State *env, int st_index)
{
ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
}
-void helper_fmul_STN_ST0(int st_index)
+void helper_fmul_STN_ST0(CPUX86State *env, int st_index)
{
ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
}
-void helper_fsub_STN_ST0(int st_index)
+void helper_fsub_STN_ST0(CPUX86State *env, int st_index)
{
ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
}
-void helper_fsubr_STN_ST0(int st_index)
+void helper_fsubr_STN_ST0(CPUX86State *env, int st_index)
{
ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
}
-void helper_fdiv_STN_ST0(int st_index)
+void helper_fdiv_STN_ST0(CPUX86State *env, int st_index)
{
floatx80 *p;
p = &ST(st_index);
- *p = helper_fdiv(*p, ST0);
+ *p = helper_fdiv(env, *p, ST0);
}
-void helper_fdivr_STN_ST0(int st_index)
+void helper_fdivr_STN_ST0(CPUX86State *env, int st_index)
{
floatx80 *p;
p = &ST(st_index);
- *p = helper_fdiv(ST0, *p);
+ *p = helper_fdiv(env, ST0, *p);
}
/* misc FPU operations */
-void helper_fchs_ST0(void)
+void helper_fchs_ST0(CPUX86State *env)
{
ST0 = floatx80_chs(ST0);
}
-void helper_fabs_ST0(void)
+void helper_fabs_ST0(CPUX86State *env)
{
ST0 = floatx80_abs(ST0);
}
-void helper_fld1_ST0(void)
+void helper_fld1_ST0(CPUX86State *env)
{
ST0 = floatx80_one;
}
-void helper_fldl2t_ST0(void)
+void helper_fldl2t_ST0(CPUX86State *env)
{
ST0 = floatx80_l2t;
}
-void helper_fldl2e_ST0(void)
+void helper_fldl2e_ST0(CPUX86State *env)
{
ST0 = floatx80_l2e;
}
-void helper_fldpi_ST0(void)
+void helper_fldpi_ST0(CPUX86State *env)
{
ST0 = floatx80_pi;
}
-void helper_fldlg2_ST0(void)
+void helper_fldlg2_ST0(CPUX86State *env)
{
ST0 = floatx80_lg2;
}
-void helper_fldln2_ST0(void)
+void helper_fldln2_ST0(CPUX86State *env)
{
ST0 = floatx80_ln2;
}
-void helper_fldz_ST0(void)
+void helper_fldz_ST0(CPUX86State *env)
{
ST0 = floatx80_zero;
}
-void helper_fldz_FT0(void)
+void helper_fldz_FT0(CPUX86State *env)
{
FT0 = floatx80_zero;
}
-uint32_t helper_fnstsw(void)
+uint32_t helper_fnstsw(CPUX86State *env)
{
return (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
}
-uint32_t helper_fnstcw(void)
+uint32_t helper_fnstcw(CPUX86State *env)
{
return env->fpuc;
}
-static void update_fp_status(void)
+static void update_fp_status(CPUX86State *env)
{
int rnd_type;
@@ -575,25 +574,25 @@ static void update_fp_status(void)
set_floatx80_rounding_precision(rnd_type, &env->fp_status);
}
-void helper_fldcw(uint32_t val)
+void helper_fldcw(CPUX86State *env, uint32_t val)
{
env->fpuc = val;
- update_fp_status();
+ update_fp_status(env);
}
-void helper_fclex(void)
+void helper_fclex(CPUX86State *env)
{
env->fpus &= 0x7f00;
}
-void helper_fwait(void)
+void helper_fwait(CPUX86State *env)
{
if (env->fpus & FPUS_SE) {
- fpu_raise_exception();
+ fpu_raise_exception(env);
}
}
-void helper_fninit(void)
+void helper_fninit(CPUX86State *env)
{
env->fpus = 0;
env->fpstt = 0;
@@ -610,7 +609,7 @@ void helper_fninit(void)
/* BCD ops */
-void helper_fbld_ST0(target_ulong ptr)
+void helper_fbld_ST0(CPUX86State *env, target_ulong ptr)
{
floatx80 tmp;
uint64_t val;
@@ -619,18 +618,18 @@ void helper_fbld_ST0(target_ulong ptr)
val = 0;
for (i = 8; i >= 0; i--) {
- v = ldub(ptr + i);
+ v = cpu_ldub_data(env, ptr + i);
val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
}
tmp = int64_to_floatx80(val, &env->fp_status);
- if (ldub(ptr + 9) & 0x80) {
+ if (cpu_ldub_data(env, ptr + 9) & 0x80) {
floatx80_chs(tmp);
}
- fpush();
+ fpush(env);
ST0 = tmp;
}
-void helper_fbst_ST0(target_ulong ptr)
+void helper_fbst_ST0(CPUX86State *env, target_ulong ptr)
{
int v;
target_ulong mem_ref, mem_end;
@@ -640,10 +639,10 @@ void helper_fbst_ST0(target_ulong ptr)
mem_ref = ptr;
mem_end = mem_ref + 9;
if (val < 0) {
- stb(mem_end, 0x80);
+ cpu_stb_data(env, mem_end, 0x80);
val = -val;
} else {
- stb(mem_end, 0x00);
+ cpu_stb_data(env, mem_end, 0x00);
}
while (mem_ref < mem_end) {
if (val == 0) {
@@ -652,63 +651,63 @@ void helper_fbst_ST0(target_ulong ptr)
v = val % 100;
val = val / 100;
v = ((v / 10) << 4) | (v % 10);
- stb(mem_ref++, v);
+ cpu_stb_data(env, mem_ref++, v);
}
while (mem_ref < mem_end) {
- stb(mem_ref++, 0);
+ cpu_stb_data(env, mem_ref++, 0);
}
}
-void helper_f2xm1(void)
+void helper_f2xm1(CPUX86State *env)
{
- double val = floatx80_to_double(ST0);
+ double val = floatx80_to_double(env, ST0);
val = pow(2.0, val) - 1.0;
- ST0 = double_to_floatx80(val);
+ ST0 = double_to_floatx80(env, val);
}
-void helper_fyl2x(void)
+void helper_fyl2x(CPUX86State *env)
{
- double fptemp = floatx80_to_double(ST0);
+ double fptemp = floatx80_to_double(env, ST0);
if (fptemp > 0.0) {
fptemp = log(fptemp) / log(2.0); /* log2(ST) */
- fptemp *= floatx80_to_double(ST1);
- ST1 = double_to_floatx80(fptemp);
- fpop();
+ fptemp *= floatx80_to_double(env, ST1);
+ ST1 = double_to_floatx80(env, fptemp);
+ fpop(env);
} else {
env->fpus &= ~0x4700;
env->fpus |= 0x400;
}
}
-void helper_fptan(void)
+void helper_fptan(CPUX86State *env)
{
- double fptemp = floatx80_to_double(ST0);
+ double fptemp = floatx80_to_double(env, ST0);
if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
env->fpus |= 0x400;
} else {
fptemp = tan(fptemp);
- ST0 = double_to_floatx80(fptemp);
- fpush();
+ ST0 = double_to_floatx80(env, fptemp);
+ fpush(env);
ST0 = floatx80_one;
env->fpus &= ~0x400; /* C2 <-- 0 */
/* the above code is for |arg| < 2**52 only */
}
}
-void helper_fpatan(void)
+void helper_fpatan(CPUX86State *env)
{
double fptemp, fpsrcop;
- fpsrcop = floatx80_to_double(ST1);
- fptemp = floatx80_to_double(ST0);
- ST1 = double_to_floatx80(atan2(fpsrcop, fptemp));
- fpop();
+ fpsrcop = floatx80_to_double(env, ST1);
+ fptemp = floatx80_to_double(env, ST0);
+ ST1 = double_to_floatx80(env, atan2(fpsrcop, fptemp));
+ fpop(env);
}
-void helper_fxtract(void)
+void helper_fxtract(CPUX86State *env)
{
CPU_LDoubleU temp;
@@ -718,7 +717,7 @@ void helper_fxtract(void)
/* Easy way to generate -inf and raising division by 0 exception */
ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero,
&env->fp_status);
- fpush();
+ fpush(env);
ST0 = temp.d;
} else {
int expdif;
@@ -726,24 +725,24 @@ void helper_fxtract(void)
expdif = EXPD(temp) - EXPBIAS;
/* DP exponent bias */
ST0 = int32_to_floatx80(expdif, &env->fp_status);
- fpush();
+ fpush(env);
BIASEXPONENT(temp);
ST0 = temp.d;
}
}
-void helper_fprem1(void)
+void helper_fprem1(CPUX86State *env)
{
double st0, st1, dblq, fpsrcop, fptemp;
CPU_LDoubleU fpsrcop1, fptemp1;
int expdif;
signed long long int q;
- st0 = floatx80_to_double(ST0);
- st1 = floatx80_to_double(ST1);
+ st0 = floatx80_to_double(env, ST0);
+ st1 = floatx80_to_double(env, ST1);
if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
- ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
+ ST0 = double_to_floatx80(env, 0.0 / 0.0); /* NaN */
env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
return;
}
@@ -788,21 +787,21 @@ void helper_fprem1(void)
-(floor(fabs(fpsrcop))) : floor(fpsrcop);
st0 -= (st1 * fpsrcop * fptemp);
}
- ST0 = double_to_floatx80(st0);
+ ST0 = double_to_floatx80(env, st0);
}
-void helper_fprem(void)
+void helper_fprem(CPUX86State *env)
{
double st0, st1, dblq, fpsrcop, fptemp;
CPU_LDoubleU fpsrcop1, fptemp1;
int expdif;
signed long long int q;
- st0 = floatx80_to_double(ST0);
- st1 = floatx80_to_double(ST1);
+ st0 = floatx80_to_double(env, ST0);
+ st1 = floatx80_to_double(env, ST1);
if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
- ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
+ ST0 = double_to_floatx80(env, 0.0 / 0.0); /* NaN */
env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
return;
}
@@ -849,25 +848,25 @@ void helper_fprem(void)
-(floor(fabs(fpsrcop))) : floor(fpsrcop);
st0 -= (st1 * fpsrcop * fptemp);
}
- ST0 = double_to_floatx80(st0);
+ ST0 = double_to_floatx80(env, st0);
}
-void helper_fyl2xp1(void)
+void helper_fyl2xp1(CPUX86State *env)
{
- double fptemp = floatx80_to_double(ST0);
+ double fptemp = floatx80_to_double(env, ST0);
if ((fptemp + 1.0) > 0.0) {
fptemp = log(fptemp + 1.0) / log(2.0); /* log2(ST + 1.0) */
- fptemp *= floatx80_to_double(ST1);
- ST1 = double_to_floatx80(fptemp);
- fpop();
+ fptemp *= floatx80_to_double(env, ST1);
+ ST1 = double_to_floatx80(env, fptemp);
+ fpop(env);
} else {
env->fpus &= ~0x4700;
env->fpus |= 0x400;
}
}
-void helper_fsqrt(void)
+void helper_fsqrt(CPUX86State *env)
{
if (floatx80_is_neg(ST0)) {
env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
@@ -876,27 +875,27 @@ void helper_fsqrt(void)
ST0 = floatx80_sqrt(ST0, &env->fp_status);
}
-void helper_fsincos(void)
+void helper_fsincos(CPUX86State *env)
{
- double fptemp = floatx80_to_double(ST0);
+ double fptemp = floatx80_to_double(env, ST0);
if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
env->fpus |= 0x400;
} else {
- ST0 = double_to_floatx80(sin(fptemp));
- fpush();
- ST0 = double_to_floatx80(cos(fptemp));
+ ST0 = double_to_floatx80(env, sin(fptemp));
+ fpush(env);
+ ST0 = double_to_floatx80(env, cos(fptemp));
env->fpus &= ~0x400; /* C2 <-- 0 */
/* the above code is for |arg| < 2**63 only */
}
}
-void helper_frndint(void)
+void helper_frndint(CPUX86State *env)
{
ST0 = floatx80_round_to_int(ST0, &env->fp_status);
}
-void helper_fscale(void)
+void helper_fscale(CPUX86State *env)
{
if (floatx80_is_any_nan(ST1)) {
ST0 = ST1;
@@ -906,33 +905,33 @@ void helper_fscale(void)
}
}
-void helper_fsin(void)
+void helper_fsin(CPUX86State *env)
{
- double fptemp = floatx80_to_double(ST0);
+ double fptemp = floatx80_to_double(env, ST0);
if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
env->fpus |= 0x400;
} else {
- ST0 = double_to_floatx80(sin(fptemp));
+ ST0 = double_to_floatx80(env, sin(fptemp));
env->fpus &= ~0x400; /* C2 <-- 0 */
/* the above code is for |arg| < 2**53 only */
}
}
-void helper_fcos(void)
+void helper_fcos(CPUX86State *env)
{
- double fptemp = floatx80_to_double(ST0);
+ double fptemp = floatx80_to_double(env, ST0);
if ((fptemp > MAXTAN) || (fptemp < -MAXTAN)) {
env->fpus |= 0x400;
} else {
- ST0 = double_to_floatx80(cos(fptemp));
+ ST0 = double_to_floatx80(env, cos(fptemp));
env->fpus &= ~0x400; /* C2 <-- 0 */
/* the above code is for |arg| < 2**63 only */
}
}
-void helper_fxam_ST0(void)
+void helper_fxam_ST0(CPUX86State *env)
{
CPU_LDoubleU temp;
int expdif;
@@ -963,7 +962,7 @@ void helper_fxam_ST0(void)
}
}
-void helper_fstenv(target_ulong ptr, int data32)
+void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
{
int fpus, fptag, exp, i;
uint64_t mant;
@@ -991,37 +990,37 @@ void helper_fstenv(target_ulong ptr, int data32)
}
if (data32) {
/* 32 bit */
- stl(ptr, env->fpuc);
- stl(ptr + 4, fpus);
- stl(ptr + 8, fptag);
- stl(ptr + 12, 0); /* fpip */
- stl(ptr + 16, 0); /* fpcs */
- stl(ptr + 20, 0); /* fpoo */
- stl(ptr + 24, 0); /* fpos */
+ cpu_stl_data(env, ptr, env->fpuc);
+ cpu_stl_data(env, ptr + 4, fpus);
+ cpu_stl_data(env, ptr + 8, fptag);
+ cpu_stl_data(env, ptr + 12, 0); /* fpip */
+ cpu_stl_data(env, ptr + 16, 0); /* fpcs */
+ cpu_stl_data(env, ptr + 20, 0); /* fpoo */
+ cpu_stl_data(env, ptr + 24, 0); /* fpos */
} else {
/* 16 bit */
- stw(ptr, env->fpuc);
- stw(ptr + 2, fpus);
- stw(ptr + 4, fptag);
- stw(ptr + 6, 0);
- stw(ptr + 8, 0);
- stw(ptr + 10, 0);
- stw(ptr + 12, 0);
+ cpu_stw_data(env, ptr, env->fpuc);
+ cpu_stw_data(env, ptr + 2, fpus);
+ cpu_stw_data(env, ptr + 4, fptag);
+ cpu_stw_data(env, ptr + 6, 0);
+ cpu_stw_data(env, ptr + 8, 0);
+ cpu_stw_data(env, ptr + 10, 0);
+ cpu_stw_data(env, ptr + 12, 0);
}
}
-void helper_fldenv(target_ulong ptr, int data32)
+void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32)
{
int i, fpus, fptag;
if (data32) {
- env->fpuc = lduw(ptr);
- fpus = lduw(ptr + 4);
- fptag = lduw(ptr + 8);
+ env->fpuc = cpu_lduw_data(env, ptr);
+ fpus = cpu_lduw_data(env, ptr + 4);
+ fptag = cpu_lduw_data(env, ptr + 8);
} else {
- env->fpuc = lduw(ptr);
- fpus = lduw(ptr + 2);
- fptag = lduw(ptr + 4);
+ env->fpuc = cpu_lduw_data(env, ptr);
+ fpus = cpu_lduw_data(env, ptr + 2);
+ fptag = cpu_lduw_data(env, ptr + 4);
}
env->fpstt = (fpus >> 11) & 7;
env->fpus = fpus & ~0x3800;
@@ -1031,17 +1030,17 @@ void helper_fldenv(target_ulong ptr, int data32)
}
}
-void helper_fsave(target_ulong ptr, int data32)
+void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
{
floatx80 tmp;
int i;
- helper_fstenv(ptr, data32);
+ helper_fstenv(env, ptr, data32);
ptr += (14 << data32);
for (i = 0; i < 8; i++) {
tmp = ST(i);
- helper_fstt(tmp, ptr);
+ helper_fstt(env, tmp, ptr);
ptr += 10;
}
@@ -1059,48 +1058,34 @@ void helper_fsave(target_ulong ptr, int data32)
env->fptags[7] = 1;
}
-void helper_frstor(target_ulong ptr, int data32)
+void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
{
floatx80 tmp;
int i;
- helper_fldenv(ptr, data32);
+ helper_fldenv(env, ptr, data32);
ptr += (14 << data32);
for (i = 0; i < 8; i++) {
- tmp = helper_fldt(ptr);
+ tmp = helper_fldt(env, ptr);
ST(i) = tmp;
ptr += 10;
}
}
#if defined(CONFIG_USER_ONLY)
-void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
+void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32)
{
- CPUX86State *saved_env;
-
- saved_env = env;
- env = s;
-
- helper_fsave(ptr, data32);
-
- env = saved_env;
+ helper_fsave(env, ptr, data32);
}
-void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
+void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
{
- CPUX86State *saved_env;
-
- saved_env = env;
- env = s;
-
- helper_frstor(ptr, data32);
-
- env = saved_env;
+ helper_frstor(env, ptr, data32);
}
#endif
-void helper_fxsave(target_ulong ptr, int data64)
+void helper_fxsave(CPUX86State *env, target_ulong ptr, int data64)
{
int fpus, fptag, i, nb_xmm_regs;
floatx80 tmp;
@@ -1116,33 +1101,33 @@ void helper_fxsave(target_ulong ptr, int data64)
for (i = 0; i < 8; i++) {
fptag |= (env->fptags[i] << i);
}
- stw(ptr, env->fpuc);
- stw(ptr + 2, fpus);
- stw(ptr + 4, fptag ^ 0xff);
+ cpu_stw_data(env, ptr, env->fpuc);
+ cpu_stw_data(env, ptr + 2, fpus);
+ cpu_stw_data(env, ptr + 4, fptag ^ 0xff);
#ifdef TARGET_X86_64
if (data64) {
- stq(ptr + 0x08, 0); /* rip */
- stq(ptr + 0x10, 0); /* rdp */
+ cpu_stq_data(env, ptr + 0x08, 0); /* rip */
+ cpu_stq_data(env, ptr + 0x10, 0); /* rdp */
} else
#endif
{
- stl(ptr + 0x08, 0); /* eip */
- stl(ptr + 0x0c, 0); /* sel */
- stl(ptr + 0x10, 0); /* dp */
- stl(ptr + 0x14, 0); /* sel */
+ cpu_stl_data(env, ptr + 0x08, 0); /* eip */
+ cpu_stl_data(env, ptr + 0x0c, 0); /* sel */
+ cpu_stl_data(env, ptr + 0x10, 0); /* dp */
+ cpu_stl_data(env, ptr + 0x14, 0); /* sel */
}
addr = ptr + 0x20;
for (i = 0; i < 8; i++) {
tmp = ST(i);
- helper_fstt(tmp, addr);
+ helper_fstt(env, tmp, addr);
addr += 16;
}
if (env->cr[4] & CR4_OSFXSR_MASK) {
/* XXX: finish it */
- stl(ptr + 0x18, env->mxcsr); /* mxcsr */
- stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
+ cpu_stl_data(env, ptr + 0x18, env->mxcsr); /* mxcsr */
+ cpu_stl_data(env, ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
} else {
@@ -1154,15 +1139,15 @@ void helper_fxsave(target_ulong ptr, int data64)
|| (env->hflags & HF_CPL_MASK)
|| !(env->hflags & HF_LMA_MASK)) {
for (i = 0; i < nb_xmm_regs; i++) {
- stq(addr, env->xmm_regs[i].XMM_Q(0));
- stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
+ cpu_stq_data(env, addr, env->xmm_regs[i].XMM_Q(0));
+ cpu_stq_data(env, addr + 8, env->xmm_regs[i].XMM_Q(1));
addr += 16;
}
}
}
}
-void helper_fxrstor(target_ulong ptr, int data64)
+void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64)
{
int i, fpus, fptag, nb_xmm_regs;
floatx80 tmp;
@@ -1173,9 +1158,9 @@ void helper_fxrstor(target_ulong ptr, int data64)
raise_exception(env, EXCP0D_GPF);
}
- env->fpuc = lduw(ptr);
- fpus = lduw(ptr + 2);
- fptag = lduw(ptr + 4);
+ env->fpuc = cpu_lduw_data(env, ptr);
+ fpus = cpu_lduw_data(env, ptr + 2);
+ fptag = cpu_lduw_data(env, ptr + 4);
env->fpstt = (fpus >> 11) & 7;
env->fpus = fpus & ~0x3800;
fptag ^= 0xff;
@@ -1185,15 +1170,15 @@ void helper_fxrstor(target_ulong ptr, int data64)
addr = ptr + 0x20;
for (i = 0; i < 8; i++) {
- tmp = helper_fldt(addr);
+ tmp = helper_fldt(env, addr);
ST(i) = tmp;
addr += 16;
}
if (env->cr[4] & CR4_OSFXSR_MASK) {
/* XXX: finish it */
- env->mxcsr = ldl(ptr + 0x18);
- /* ldl(ptr + 0x1c); */
+ env->mxcsr = cpu_ldl_data(env, ptr + 0x18);
+ /* cpu_ldl_data(env, ptr + 0x1c); */
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
} else {
@@ -1205,8 +1190,8 @@ void helper_fxrstor(target_ulong ptr, int data64)
|| (env->hflags & HF_CPL_MASK)
|| !(env->hflags & HF_LMA_MASK)) {
for (i = 0; i < nb_xmm_regs; i++) {
- env->xmm_regs[i].XMM_Q(0) = ldq(addr);
- env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
+ env->xmm_regs[i].XMM_Q(0) = cpu_ldq_data(env, addr);
+ env->xmm_regs[i].XMM_Q(1) = cpu_ldq_data(env, addr + 8);
addr += 16;
}
}
@@ -1242,7 +1227,7 @@ floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
#define SSE_RC_CHOP 0x6000
#define SSE_FZ 0x8000
-static void update_sse_status(void)
+static void update_sse_status(CPUX86State *env)
{
int rnd_type;
@@ -1271,20 +1256,20 @@ static void update_sse_status(void)
set_flush_to_zero((env->mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status);
}
-void helper_ldmxcsr(uint32_t val)
+void helper_ldmxcsr(CPUX86State *env, uint32_t val)
{
env->mxcsr = val;
- update_sse_status();
+ update_sse_status(env);
}
-void helper_enter_mmx(void)
+void helper_enter_mmx(CPUX86State *env)
{
env->fpstt = 0;
*(uint32_t *)(env->fptags) = 0;
*(uint32_t *)(env->fptags + 4) = 0;
}
-void helper_emms(void)
+void helper_emms(CPUX86State *env)
{
/* set to empty state */
*(uint32_t *)(env->fptags) = 0x01010101;
@@ -1292,7 +1277,7 @@ void helper_emms(void)
}
/* XXX: suppress */
-void helper_movq(void *d, void *s)
+void helper_movq(CPUX86State *env, void *d, void *s)
{
*(uint64_t *)d = *(uint64_t *)s;
}
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 99ca183..ab6af63 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -1,93 +1,93 @@
#include "def-helper.h"
-DEF_HELPER_FLAGS_1(cc_compute_all, TCG_CALL_PURE, i32, int)
-DEF_HELPER_FLAGS_1(cc_compute_c, TCG_CALL_PURE, i32, int)
+DEF_HELPER_FLAGS_2(cc_compute_all, TCG_CALL_PURE, i32, env, int)
+DEF_HELPER_FLAGS_2(cc_compute_c, TCG_CALL_PURE, i32, env, int)
DEF_HELPER_0(lock, void)
DEF_HELPER_0(unlock, void)
-DEF_HELPER_2(write_eflags, void, tl, i32)
-DEF_HELPER_0(read_eflags, tl)
-DEF_HELPER_1(divb_AL, void, tl)
-DEF_HELPER_1(idivb_AL, void, tl)
-DEF_HELPER_1(divw_AX, void, tl)
-DEF_HELPER_1(idivw_AX, void, tl)
-DEF_HELPER_1(divl_EAX, void, tl)
-DEF_HELPER_1(idivl_EAX, void, tl)
+DEF_HELPER_3(write_eflags, void, env, tl, i32)
+DEF_HELPER_1(read_eflags, tl, env)
+DEF_HELPER_2(divb_AL, void, env, tl)
+DEF_HELPER_2(idivb_AL, void, env, tl)
+DEF_HELPER_2(divw_AX, void, env, tl)
+DEF_HELPER_2(idivw_AX, void, env, tl)
+DEF_HELPER_2(divl_EAX, void, env, tl)
+DEF_HELPER_2(idivl_EAX, void, env, tl)
#ifdef TARGET_X86_64
-DEF_HELPER_1(mulq_EAX_T0, void, tl)
-DEF_HELPER_1(imulq_EAX_T0, void, tl)
-DEF_HELPER_2(imulq_T0_T1, tl, tl, tl)
-DEF_HELPER_1(divq_EAX, void, tl)
-DEF_HELPER_1(idivq_EAX, void, tl)
+DEF_HELPER_2(mulq_EAX_T0, void, env, tl)
+DEF_HELPER_2(imulq_EAX_T0, void, env, tl)
+DEF_HELPER_3(imulq_T0_T1, tl, env, tl, tl)
+DEF_HELPER_2(divq_EAX, void, env, tl)
+DEF_HELPER_2(idivq_EAX, void, env, tl)
#endif
-DEF_HELPER_1(aam, void, int)
-DEF_HELPER_1(aad, void, int)
-DEF_HELPER_0(aaa, void)
-DEF_HELPER_0(aas, void)
-DEF_HELPER_0(daa, void)
-DEF_HELPER_0(das, void)
+DEF_HELPER_2(aam, void, env, int)
+DEF_HELPER_2(aad, void, env, int)
+DEF_HELPER_1(aaa, void, env)
+DEF_HELPER_1(aas, void, env)
+DEF_HELPER_1(daa, void, env)
+DEF_HELPER_1(das, void, env)
-DEF_HELPER_1(lsl, tl, tl)
-DEF_HELPER_1(lar, tl, tl)
-DEF_HELPER_1(verr, void, tl)
-DEF_HELPER_1(verw, void, tl)
-DEF_HELPER_1(lldt, void, int)
-DEF_HELPER_1(ltr, void, int)
-DEF_HELPER_2(load_seg, void, int, int)
-DEF_HELPER_3(ljmp_protected, void, int, tl, int)
-DEF_HELPER_4(lcall_real, void, int, tl, int, int)
-DEF_HELPER_4(lcall_protected, void, int, tl, int, int)
-DEF_HELPER_1(iret_real, void, int)
-DEF_HELPER_2(iret_protected, void, int, int)
-DEF_HELPER_2(lret_protected, void, int, int)
-DEF_HELPER_1(read_crN, tl, int)
-DEF_HELPER_2(write_crN, void, int, tl)
-DEF_HELPER_1(lmsw, void, tl)
-DEF_HELPER_0(clts, void)
-DEF_HELPER_2(movl_drN_T0, void, int, tl)
-DEF_HELPER_1(invlpg, void, tl)
+DEF_HELPER_2(lsl, tl, env, tl)
+DEF_HELPER_2(lar, tl, env, tl)
+DEF_HELPER_2(verr, void, env, tl)
+DEF_HELPER_2(verw, void, env, tl)
+DEF_HELPER_2(lldt, void, env, int)
+DEF_HELPER_2(ltr, void, env, int)
+DEF_HELPER_3(load_seg, void, env, int, int)
+DEF_HELPER_4(ljmp_protected, void, env, int, tl, int)
+DEF_HELPER_5(lcall_real, void, env, int, tl, int, int)
+DEF_HELPER_5(lcall_protected, void, env, int, tl, int, int)
+DEF_HELPER_2(iret_real, void, env, int)
+DEF_HELPER_3(iret_protected, void, env, int, int)
+DEF_HELPER_3(lret_protected, void, env, int, int)
+DEF_HELPER_2(read_crN, tl, env, int)
+DEF_HELPER_3(write_crN, void, env, int, tl)
+DEF_HELPER_2(lmsw, void, env, tl)
+DEF_HELPER_1(clts, void, env)
+DEF_HELPER_3(movl_drN_T0, void, env, int, tl)
+DEF_HELPER_2(invlpg, void, env, tl)
-DEF_HELPER_3(enter_level, void, int, int, tl)
+DEF_HELPER_4(enter_level, void, env, int, int, tl)
#ifdef TARGET_X86_64
-DEF_HELPER_3(enter64_level, void, int, int, tl)
+DEF_HELPER_4(enter64_level, void, env, int, int, tl)
#endif
-DEF_HELPER_0(sysenter, void)
-DEF_HELPER_1(sysexit, void, int)
+DEF_HELPER_1(sysenter, void, env)
+DEF_HELPER_2(sysexit, void, env, int)
#ifdef TARGET_X86_64
-DEF_HELPER_1(syscall, void, int)
-DEF_HELPER_1(sysret, void, int)
+DEF_HELPER_2(syscall, void, env, int)
+DEF_HELPER_2(sysret, void, env, int)
#endif
-DEF_HELPER_1(hlt, void, int)
-DEF_HELPER_1(monitor, void, tl)
-DEF_HELPER_1(mwait, void, int)
-DEF_HELPER_0(debug, void)
-DEF_HELPER_0(reset_rf, void)
+DEF_HELPER_2(hlt, void, env, int)
+DEF_HELPER_2(monitor, void, env, tl)
+DEF_HELPER_2(mwait, void, env, int)
+DEF_HELPER_1(debug, void, env)
+DEF_HELPER_1(reset_rf, void, env)
DEF_HELPER_3(raise_interrupt, void, env, int, int)
DEF_HELPER_2(raise_exception, void, env, int)
-DEF_HELPER_0(cli, void)
-DEF_HELPER_0(sti, void)
-DEF_HELPER_0(set_inhibit_irq, void)
-DEF_HELPER_0(reset_inhibit_irq, void)
-DEF_HELPER_2(boundw, void, tl, int)
-DEF_HELPER_2(boundl, void, tl, int)
-DEF_HELPER_0(rsm, void)
-DEF_HELPER_1(into, void, int)
-DEF_HELPER_1(cmpxchg8b, void, tl)
+DEF_HELPER_1(cli, void, env)
+DEF_HELPER_1(sti, void, env)
+DEF_HELPER_1(set_inhibit_irq, void, env)
+DEF_HELPER_1(reset_inhibit_irq, void, env)
+DEF_HELPER_3(boundw, void, env, tl, int)
+DEF_HELPER_3(boundl, void, env, tl, int)
+DEF_HELPER_1(rsm, void, env)
+DEF_HELPER_2(into, void, env, int)
+DEF_HELPER_2(cmpxchg8b, void, env, tl)
#ifdef TARGET_X86_64
-DEF_HELPER_1(cmpxchg16b, void, tl)
+DEF_HELPER_2(cmpxchg16b, void, env, tl)
#endif
-DEF_HELPER_0(single_step, void)
-DEF_HELPER_0(cpuid, void)
-DEF_HELPER_0(rdtsc, void)
-DEF_HELPER_0(rdtscp, void)
-DEF_HELPER_0(rdpmc, void)
-DEF_HELPER_0(rdmsr, void)
-DEF_HELPER_0(wrmsr, void)
+DEF_HELPER_1(single_step, void, env)
+DEF_HELPER_1(cpuid, void, env)
+DEF_HELPER_1(rdtsc, void, env)
+DEF_HELPER_1(rdtscp, void, env)
+DEF_HELPER_1(rdpmc, void, env)
+DEF_HELPER_1(rdmsr, void, env)
+DEF_HELPER_1(wrmsr, void, env)
-DEF_HELPER_1(check_iob, void, i32)
-DEF_HELPER_1(check_iow, void, i32)
-DEF_HELPER_1(check_iol, void, i32)
+DEF_HELPER_2(check_iob, void, env, i32)
+DEF_HELPER_2(check_iow, void, env, i32)
+DEF_HELPER_2(check_iol, void, env, i32)
DEF_HELPER_2(outb, void, i32, i32)
DEF_HELPER_1(inb, tl, i32)
DEF_HELPER_2(outw, void, i32, i32)
@@ -95,127 +95,127 @@ DEF_HELPER_1(inw, tl, i32)
DEF_HELPER_2(outl, void, i32, i32)
DEF_HELPER_1(inl, tl, i32)
-DEF_HELPER_2(svm_check_intercept_param, void, i32, i64)
-DEF_HELPER_2(vmexit, void, i32, i64)
-DEF_HELPER_3(svm_check_io, void, i32, i32, i32)
-DEF_HELPER_2(vmrun, void, int, int)
-DEF_HELPER_0(vmmcall, void)
-DEF_HELPER_1(vmload, void, int)
-DEF_HELPER_1(vmsave, void, int)
-DEF_HELPER_0(stgi, void)
-DEF_HELPER_0(clgi, void)
-DEF_HELPER_0(skinit, void)
-DEF_HELPER_1(invlpga, void, int)
+DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64)
+DEF_HELPER_3(vmexit, void, env, i32, i64)
+DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32)
+DEF_HELPER_3(vmrun, void, env, int, int)
+DEF_HELPER_1(vmmcall, void, env)
+DEF_HELPER_2(vmload, void, env, int)
+DEF_HELPER_2(vmsave, void, env, int)
+DEF_HELPER_1(stgi, void, env)
+DEF_HELPER_1(clgi, void, env)
+DEF_HELPER_1(skinit, void, env)
+DEF_HELPER_2(invlpga, void, env, int)
/* x86 FPU */
-DEF_HELPER_1(flds_FT0, void, i32)
-DEF_HELPER_1(fldl_FT0, void, i64)
-DEF_HELPER_1(fildl_FT0, void, s32)
-DEF_HELPER_1(flds_ST0, void, i32)
-DEF_HELPER_1(fldl_ST0, void, i64)
-DEF_HELPER_1(fildl_ST0, void, s32)
-DEF_HELPER_1(fildll_ST0, void, s64)
-DEF_HELPER_0(fsts_ST0, i32)
-DEF_HELPER_0(fstl_ST0, i64)
-DEF_HELPER_0(fist_ST0, s32)
-DEF_HELPER_0(fistl_ST0, s32)
-DEF_HELPER_0(fistll_ST0, s64)
-DEF_HELPER_0(fistt_ST0, s32)
-DEF_HELPER_0(fisttl_ST0, s32)
-DEF_HELPER_0(fisttll_ST0, s64)
-DEF_HELPER_1(fldt_ST0, void, tl)
-DEF_HELPER_1(fstt_ST0, void, tl)
-DEF_HELPER_0(fpush, void)
-DEF_HELPER_0(fpop, void)
-DEF_HELPER_0(fdecstp, void)
-DEF_HELPER_0(fincstp, void)
-DEF_HELPER_1(ffree_STN, void, int)
-DEF_HELPER_0(fmov_ST0_FT0, void)
-DEF_HELPER_1(fmov_FT0_STN, void, int)
-DEF_HELPER_1(fmov_ST0_STN, void, int)
-DEF_HELPER_1(fmov_STN_ST0, void, int)
-DEF_HELPER_1(fxchg_ST0_STN, void, int)
-DEF_HELPER_0(fcom_ST0_FT0, void)
-DEF_HELPER_0(fucom_ST0_FT0, void)
-DEF_HELPER_0(fcomi_ST0_FT0, void)
-DEF_HELPER_0(fucomi_ST0_FT0, void)
-DEF_HELPER_0(fadd_ST0_FT0, void)
-DEF_HELPER_0(fmul_ST0_FT0, void)
-DEF_HELPER_0(fsub_ST0_FT0, void)
-DEF_HELPER_0(fsubr_ST0_FT0, void)
-DEF_HELPER_0(fdiv_ST0_FT0, void)
-DEF_HELPER_0(fdivr_ST0_FT0, void)
-DEF_HELPER_1(fadd_STN_ST0, void, int)
-DEF_HELPER_1(fmul_STN_ST0, void, int)
-DEF_HELPER_1(fsub_STN_ST0, void, int)
-DEF_HELPER_1(fsubr_STN_ST0, void, int)
-DEF_HELPER_1(fdiv_STN_ST0, void, int)
-DEF_HELPER_1(fdivr_STN_ST0, void, int)
-DEF_HELPER_0(fchs_ST0, void)
-DEF_HELPER_0(fabs_ST0, void)
-DEF_HELPER_0(fxam_ST0, void)
-DEF_HELPER_0(fld1_ST0, void)
-DEF_HELPER_0(fldl2t_ST0, void)
-DEF_HELPER_0(fldl2e_ST0, void)
-DEF_HELPER_0(fldpi_ST0, void)
-DEF_HELPER_0(fldlg2_ST0, void)
-DEF_HELPER_0(fldln2_ST0, void)
-DEF_HELPER_0(fldz_ST0, void)
-DEF_HELPER_0(fldz_FT0, void)
-DEF_HELPER_0(fnstsw, i32)
-DEF_HELPER_0(fnstcw, i32)
-DEF_HELPER_1(fldcw, void, i32)
-DEF_HELPER_0(fclex, void)
-DEF_HELPER_0(fwait, void)
-DEF_HELPER_0(fninit, void)
-DEF_HELPER_1(fbld_ST0, void, tl)
-DEF_HELPER_1(fbst_ST0, void, tl)
-DEF_HELPER_0(f2xm1, void)
-DEF_HELPER_0(fyl2x, void)
-DEF_HELPER_0(fptan, void)
-DEF_HELPER_0(fpatan, void)
-DEF_HELPER_0(fxtract, void)
-DEF_HELPER_0(fprem1, void)
-DEF_HELPER_0(fprem, void)
-DEF_HELPER_0(fyl2xp1, void)
-DEF_HELPER_0(fsqrt, void)
-DEF_HELPER_0(fsincos, void)
-DEF_HELPER_0(frndint, void)
-DEF_HELPER_0(fscale, void)
-DEF_HELPER_0(fsin, void)
-DEF_HELPER_0(fcos, void)
-DEF_HELPER_2(fstenv, void, tl, int)
-DEF_HELPER_2(fldenv, void, tl, int)
-DEF_HELPER_2(fsave, void, tl, int)
-DEF_HELPER_2(frstor, void, tl, int)
-DEF_HELPER_2(fxsave, void, tl, int)
-DEF_HELPER_2(fxrstor, void, tl, int)
+DEF_HELPER_2(flds_FT0, void, env, i32)
+DEF_HELPER_2(fldl_FT0, void, env, i64)
+DEF_HELPER_2(fildl_FT0, void, env, s32)
+DEF_HELPER_2(flds_ST0, void, env, i32)
+DEF_HELPER_2(fldl_ST0, void, env, i64)
+DEF_HELPER_2(fildl_ST0, void, env, s32)
+DEF_HELPER_2(fildll_ST0, void, env, s64)
+DEF_HELPER_1(fsts_ST0, i32, env)
+DEF_HELPER_1(fstl_ST0, i64, env)
+DEF_HELPER_1(fist_ST0, s32, env)
+DEF_HELPER_1(fistl_ST0, s32, env)
+DEF_HELPER_1(fistll_ST0, s64, env)
+DEF_HELPER_1(fistt_ST0, s32, env)
+DEF_HELPER_1(fisttl_ST0, s32, env)
+DEF_HELPER_1(fisttll_ST0, s64, env)
+DEF_HELPER_2(fldt_ST0, void, env, tl)
+DEF_HELPER_2(fstt_ST0, void, env, tl)
+DEF_HELPER_1(fpush, void, env)
+DEF_HELPER_1(fpop, void, env)
+DEF_HELPER_1(fdecstp, void, env)
+DEF_HELPER_1(fincstp, void, env)
+DEF_HELPER_2(ffree_STN, void, env, int)
+DEF_HELPER_1(fmov_ST0_FT0, void, env)
+DEF_HELPER_2(fmov_FT0_STN, void, env, int)
+DEF_HELPER_2(fmov_ST0_STN, void, env, int)
+DEF_HELPER_2(fmov_STN_ST0, void, env, int)
+DEF_HELPER_2(fxchg_ST0_STN, void, env, int)
+DEF_HELPER_1(fcom_ST0_FT0, void, env)
+DEF_HELPER_1(fucom_ST0_FT0, void, env)
+DEF_HELPER_1(fcomi_ST0_FT0, void, env)
+DEF_HELPER_1(fucomi_ST0_FT0, void, env)
+DEF_HELPER_1(fadd_ST0_FT0, void, env)
+DEF_HELPER_1(fmul_ST0_FT0, void, env)
+DEF_HELPER_1(fsub_ST0_FT0, void, env)
+DEF_HELPER_1(fsubr_ST0_FT0, void, env)
+DEF_HELPER_1(fdiv_ST0_FT0, void, env)
+DEF_HELPER_1(fdivr_ST0_FT0, void, env)
+DEF_HELPER_2(fadd_STN_ST0, void, env, int)
+DEF_HELPER_2(fmul_STN_ST0, void, env, int)
+DEF_HELPER_2(fsub_STN_ST0, void, env, int)
+DEF_HELPER_2(fsubr_STN_ST0, void, env, int)
+DEF_HELPER_2(fdiv_STN_ST0, void, env, int)
+DEF_HELPER_2(fdivr_STN_ST0, void, env, int)
+DEF_HELPER_1(fchs_ST0, void, env)
+DEF_HELPER_1(fabs_ST0, void, env)
+DEF_HELPER_1(fxam_ST0, void, env)
+DEF_HELPER_1(fld1_ST0, void, env)
+DEF_HELPER_1(fldl2t_ST0, void, env)
+DEF_HELPER_1(fldl2e_ST0, void, env)
+DEF_HELPER_1(fldpi_ST0, void, env)
+DEF_HELPER_1(fldlg2_ST0, void, env)
+DEF_HELPER_1(fldln2_ST0, void, env)
+DEF_HELPER_1(fldz_ST0, void, env)
+DEF_HELPER_1(fldz_FT0, void, env)
+DEF_HELPER_1(fnstsw, i32, env)
+DEF_HELPER_1(fnstcw, i32, env)
+DEF_HELPER_2(fldcw, void, env, i32)
+DEF_HELPER_1(fclex, void, env)
+DEF_HELPER_1(fwait, void, env)
+DEF_HELPER_1(fninit, void, env)
+DEF_HELPER_2(fbld_ST0, void, env, tl)
+DEF_HELPER_2(fbst_ST0, void, env, tl)
+DEF_HELPER_1(f2xm1, void, env)
+DEF_HELPER_1(fyl2x, void, env)
+DEF_HELPER_1(fptan, void, env)
+DEF_HELPER_1(fpatan, void, env)
+DEF_HELPER_1(fxtract, void, env)
+DEF_HELPER_1(fprem1, void, env)
+DEF_HELPER_1(fprem, void, env)
+DEF_HELPER_1(fyl2xp1, void, env)
+DEF_HELPER_1(fsqrt, void, env)
+DEF_HELPER_1(fsincos, void, env)
+DEF_HELPER_1(frndint, void, env)
+DEF_HELPER_1(fscale, void, env)
+DEF_HELPER_1(fsin, void, env)
+DEF_HELPER_1(fcos, void, env)
+DEF_HELPER_3(fstenv, void, env, tl, int)
+DEF_HELPER_3(fldenv, void, env, tl, int)
+DEF_HELPER_3(fsave, void, env, tl, int)
+DEF_HELPER_3(frstor, void, env, tl, int)
+DEF_HELPER_3(fxsave, void, env, tl, int)
+DEF_HELPER_3(fxrstor, void, env, tl, int)
DEF_HELPER_1(bsf, tl, tl)
DEF_HELPER_1(bsr, tl, tl)
DEF_HELPER_2(lzcnt, tl, tl, int)
/* MMX/SSE */
-DEF_HELPER_1(ldmxcsr, void, i32)
-DEF_HELPER_0(enter_mmx, void)
-DEF_HELPER_0(emms, void)
-DEF_HELPER_2(movq, void, ptr, ptr)
+DEF_HELPER_2(ldmxcsr, void, env, i32)
+DEF_HELPER_1(enter_mmx, void, env)
+DEF_HELPER_1(emms, void, env)
+DEF_HELPER_3(movq, void, env, ptr, ptr)
#define SHIFT 0
#include "ops_sse_header.h"
#define SHIFT 1
#include "ops_sse_header.h"
-DEF_HELPER_2(rclb, tl, tl, tl)
-DEF_HELPER_2(rclw, tl, tl, tl)
-DEF_HELPER_2(rcll, tl, tl, tl)
-DEF_HELPER_2(rcrb, tl, tl, tl)
-DEF_HELPER_2(rcrw, tl, tl, tl)
-DEF_HELPER_2(rcrl, tl, tl, tl)
+DEF_HELPER_3(rclb, tl, env, tl, tl)
+DEF_HELPER_3(rclw, tl, env, tl, tl)
+DEF_HELPER_3(rcll, tl, env, tl, tl)
+DEF_HELPER_3(rcrb, tl, env, tl, tl)
+DEF_HELPER_3(rcrw, tl, env, tl, tl)
+DEF_HELPER_3(rcrl, tl, env, tl, tl)
#ifdef TARGET_X86_64
-DEF_HELPER_2(rclq, tl, tl, tl)
-DEF_HELPER_2(rcrq, tl, tl, tl)
+DEF_HELPER_3(rclq, tl, env, tl, tl)
+DEF_HELPER_3(rcrq, tl, env, tl, tl)
#endif
#include "def-helper.h"
diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c
index e1f66f5..f39747e 100644
--- a/target-i386/int_helper.c
+++ b/target-i386/int_helper.c
@@ -18,7 +18,6 @@
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "host-utils.h"
#include "helper.h"
@@ -42,7 +41,7 @@ static const uint8_t rclw_table[32] = {
/* division, flags are undefined */
-void helper_divb_AL(target_ulong t0)
+void helper_divb_AL(CPUX86State *env, target_ulong t0)
{
unsigned int num, den, q, r;
@@ -60,7 +59,7 @@ void helper_divb_AL(target_ulong t0)
EAX = (EAX & ~0xffff) | (r << 8) | q;
}
-void helper_idivb_AL(target_ulong t0)
+void helper_idivb_AL(CPUX86State *env, target_ulong t0)
{
int num, den, q, r;
@@ -78,7 +77,7 @@ void helper_idivb_AL(target_ulong t0)
EAX = (EAX & ~0xffff) | (r << 8) | q;
}
-void helper_divw_AX(target_ulong t0)
+void helper_divw_AX(CPUX86State *env, target_ulong t0)
{
unsigned int num, den, q, r;
@@ -97,7 +96,7 @@ void helper_divw_AX(target_ulong t0)
EDX = (EDX & ~0xffff) | r;
}
-void helper_idivw_AX(target_ulong t0)
+void helper_idivw_AX(CPUX86State *env, target_ulong t0)
{
int num, den, q, r;
@@ -116,7 +115,7 @@ void helper_idivw_AX(target_ulong t0)
EDX = (EDX & ~0xffff) | r;
}
-void helper_divl_EAX(target_ulong t0)
+void helper_divl_EAX(CPUX86State *env, target_ulong t0)
{
unsigned int den, r;
uint64_t num, q;
@@ -135,7 +134,7 @@ void helper_divl_EAX(target_ulong t0)
EDX = (uint32_t)r;
}
-void helper_idivl_EAX(target_ulong t0)
+void helper_idivl_EAX(CPUX86State *env, target_ulong t0)
{
int den, r;
int64_t num, q;
@@ -157,7 +156,7 @@ void helper_idivl_EAX(target_ulong t0)
/* bcd */
/* XXX: exception */
-void helper_aam(int base)
+void helper_aam(CPUX86State *env, int base)
{
int al, ah;
@@ -168,7 +167,7 @@ void helper_aam(int base)
CC_DST = al;
}
-void helper_aad(int base)
+void helper_aad(CPUX86State *env, int base)
{
int al, ah;
@@ -179,13 +178,13 @@ void helper_aad(int base)
CC_DST = al;
}
-void helper_aaa(void)
+void helper_aaa(CPUX86State *env)
{
int icarry;
int al, ah, af;
int eflags;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
af = eflags & CC_A;
al = EAX & 0xff;
ah = (EAX >> 8) & 0xff;
@@ -203,13 +202,13 @@ void helper_aaa(void)
CC_SRC = eflags;
}
-void helper_aas(void)
+void helper_aas(CPUX86State *env)
{
int icarry;
int al, ah, af;
int eflags;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
af = eflags & CC_A;
al = EAX & 0xff;
ah = (EAX >> 8) & 0xff;
@@ -227,12 +226,12 @@ void helper_aas(void)
CC_SRC = eflags;
}
-void helper_daa(void)
+void helper_daa(CPUX86State *env)
{
int old_al, al, af, cf;
int eflags;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
cf = eflags & CC_C;
af = eflags & CC_A;
old_al = al = EAX & 0xff;
@@ -254,12 +253,12 @@ void helper_daa(void)
CC_SRC = eflags;
}
-void helper_das(void)
+void helper_das(CPUX86State *env)
{
int al, al1, af, cf;
int eflags;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
cf = eflags & CC_C;
af = eflags & CC_A;
al = EAX & 0xff;
@@ -375,7 +374,7 @@ static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
return 0;
}
-void helper_mulq_EAX_T0(target_ulong t0)
+void helper_mulq_EAX_T0(CPUX86State *env, target_ulong t0)
{
uint64_t r0, r1;
@@ -386,7 +385,7 @@ void helper_mulq_EAX_T0(target_ulong t0)
CC_SRC = r1;
}
-void helper_imulq_EAX_T0(target_ulong t0)
+void helper_imulq_EAX_T0(CPUX86State *env, target_ulong t0)
{
uint64_t r0, r1;
@@ -397,7 +396,8 @@ void helper_imulq_EAX_T0(target_ulong t0)
CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
}
-target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
+target_ulong helper_imulq_T0_T1(CPUX86State *env, target_ulong t0,
+ target_ulong t1)
{
uint64_t r0, r1;
@@ -407,7 +407,7 @@ target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1)
return r0;
}
-void helper_divq_EAX(target_ulong t0)
+void helper_divq_EAX(CPUX86State *env, target_ulong t0)
{
uint64_t r0, r1;
@@ -423,7 +423,7 @@ void helper_divq_EAX(target_ulong t0)
EDX = r1;
}
-void helper_idivq_EAX(target_ulong t0)
+void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
{
uint64_t r0, r1;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 696b14a..ffc294e 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -63,6 +63,7 @@ static bool has_msr_star;
static bool has_msr_hsave_pa;
static bool has_msr_tsc_deadline;
static bool has_msr_async_pf_en;
+static bool has_msr_pv_eoi_en;
static bool has_msr_misc_enable;
static int lm_capable_kernel;
@@ -455,6 +456,8 @@ int kvm_arch_init_vcpu(CPUX86State *env)
has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
+ has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI);
+
cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
for (i = 0; i <= limit; i++) {
@@ -1017,6 +1020,10 @@ static int kvm_put_msrs(CPUX86State *env, int level)
kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN,
env->async_pf_en_msr);
}
+ if (has_msr_pv_eoi_en) {
+ kvm_msr_entry_set(&msrs[n++], MSR_KVM_PV_EOI_EN,
+ env->pv_eoi_en_msr);
+ }
if (hyperv_hypercall_available()) {
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
@@ -1259,6 +1266,9 @@ static int kvm_get_msrs(CPUX86State *env)
if (has_msr_async_pf_en) {
msrs[n++].index = MSR_KVM_ASYNC_PF_EN;
}
+ if (has_msr_pv_eoi_en) {
+ msrs[n++].index = MSR_KVM_PV_EOI_EN;
+ }
if (env->mcg_cap) {
msrs[n++].index = MSR_MCG_STATUS;
@@ -1338,6 +1348,9 @@ static int kvm_get_msrs(CPUX86State *env)
case MSR_KVM_ASYNC_PF_EN:
env->async_pf_en_msr = msrs[i].data;
break;
+ case MSR_KVM_PV_EOI_EN:
+ env->pv_eoi_en_msr = msrs[i].data;
+ break;
}
}
diff --git a/target-i386/machine.c b/target-i386/machine.c
index a8be058..4771508 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -279,6 +279,13 @@ static bool async_pf_msr_needed(void *opaque)
return cpu->async_pf_en_msr != 0;
}
+static bool pv_eoi_msr_needed(void *opaque)
+{
+ CPUX86State *cpu = opaque;
+
+ return cpu->pv_eoi_en_msr != 0;
+}
+
static const VMStateDescription vmstate_async_pf_msr = {
.name = "cpu/async_pf_msr",
.version_id = 1,
@@ -290,6 +297,17 @@ static const VMStateDescription vmstate_async_pf_msr = {
}
};
+static const VMStateDescription vmstate_pv_eoi_msr = {
+ .name = "cpu/async_pv_eoi_msr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(pv_eoi_en_msr, CPUX86State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static bool fpop_ip_dp_needed(void *opaque)
{
CPUX86State *env = opaque;
@@ -454,6 +472,9 @@ static const VMStateDescription vmstate_cpu = {
.vmsd = &vmstate_async_pf_msr,
.needed = async_pf_msr_needed,
} , {
+ .vmsd = &vmstate_pv_eoi_msr,
+ .needed = pv_eoi_msr_needed,
+ } , {
.vmsd = &vmstate_fpop_ip_dp,
.needed = fpop_ip_dp_needed,
}, {
diff --git a/target-i386/mem_helper.c b/target-i386/mem_helper.c
index 91353c0..7f99c7c 100644
--- a/target-i386/mem_helper.c
+++ b/target-i386/mem_helper.c
@@ -18,7 +18,6 @@
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
#if !defined(CONFIG_USER_ONLY)
@@ -39,19 +38,19 @@ void helper_unlock(void)
spin_unlock(&global_cpu_lock);
}
-void helper_cmpxchg8b(target_ulong a0)
+void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)
{
uint64_t d;
int eflags;
- eflags = helper_cc_compute_all(CC_OP);
- d = ldq(a0);
+ eflags = cpu_cc_compute_all(env, CC_OP);
+ d = cpu_ldq_data(env, a0);
if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
- stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
+ cpu_stq_data(env, a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
eflags |= CC_Z;
} else {
/* always do the store */
- stq(a0, d);
+ cpu_stq_data(env, a0, d);
EDX = (uint32_t)(d >> 32);
EAX = (uint32_t)d;
eflags &= ~CC_Z;
@@ -60,7 +59,7 @@ void helper_cmpxchg8b(target_ulong a0)
}
#ifdef TARGET_X86_64
-void helper_cmpxchg16b(target_ulong a0)
+void helper_cmpxchg16b(CPUX86State *env, target_ulong a0)
{
uint64_t d0, d1;
int eflags;
@@ -68,17 +67,17 @@ void helper_cmpxchg16b(target_ulong a0)
if ((a0 & 0xf) != 0) {
raise_exception(env, EXCP0D_GPF);
}
- eflags = helper_cc_compute_all(CC_OP);
- d0 = ldq(a0);
- d1 = ldq(a0 + 8);
+ eflags = cpu_cc_compute_all(env, CC_OP);
+ d0 = cpu_ldq_data(env, a0);
+ d1 = cpu_ldq_data(env, a0 + 8);
if (d0 == EAX && d1 == EDX) {
- stq(a0, EBX);
- stq(a0 + 8, ECX);
+ cpu_stq_data(env, a0, EBX);
+ cpu_stq_data(env, a0 + 8, ECX);
eflags |= CC_Z;
} else {
/* always do the store */
- stq(a0, d0);
- stq(a0 + 8, d1);
+ cpu_stq_data(env, a0, d0);
+ cpu_stq_data(env, a0 + 8, d1);
EDX = d1;
EAX = d0;
eflags &= ~CC_Z;
@@ -87,24 +86,24 @@ void helper_cmpxchg16b(target_ulong a0)
}
#endif
-void helper_boundw(target_ulong a0, int v)
+void helper_boundw(CPUX86State *env, target_ulong a0, int v)
{
int low, high;
- low = ldsw(a0);
- high = ldsw(a0 + 2);
+ low = cpu_ldsw_data(env, a0);
+ high = cpu_ldsw_data(env, a0 + 2);
v = (int16_t)v;
if (v < low || v > high) {
raise_exception(env, EXCP05_BOUND);
}
}
-void helper_boundl(target_ulong a0, int v)
+void helper_boundl(CPUX86State *env, target_ulong a0, int v)
{
int low, high;
- low = ldl(a0);
- high = ldl(a0 + 4);
+ low = cpu_ldl_data(env, a0);
+ high = cpu_ldl_data(env, a0 + 4);
if (v < low || v > high) {
raise_exception(env, EXCP05_BOUND);
}
@@ -133,15 +132,11 @@ void helper_boundl(target_ulong a0, int v)
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
-void tlb_fill(CPUX86State *env1, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUX86State *env, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr)
{
TranslationBlock *tb;
int ret;
- CPUX86State *saved_env;
-
- saved_env = env;
- env = env1;
ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (ret) {
@@ -156,6 +151,5 @@ void tlb_fill(CPUX86State *env1, target_ulong addr, int is_write, int mmu_idx,
}
raise_exception_err(env, env->exception_index, env->error_code);
}
- env = saved_env;
}
#endif
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index ce675b7..a020379 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -18,7 +18,6 @@
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "ioport.h"
#include "helper.h"
@@ -27,7 +26,7 @@
#endif /* !defined(CONFIG_USER_ONLY) */
/* check if Port I/O is allowed in TSS */
-static inline void check_io(int addr, int size)
+static inline void check_io(CPUX86State *env, int addr, int size)
{
int io_offset, val, mask;
@@ -37,13 +36,13 @@ static inline void check_io(int addr, int size)
env->tr.limit < 103) {
goto fail;
}
- io_offset = lduw_kernel(env->tr.base + 0x66);
+ io_offset = cpu_lduw_kernel(env, env->tr.base + 0x66);
io_offset += (addr >> 3);
/* Note: the check needs two bytes */
if ((io_offset + 1) > env->tr.limit) {
goto fail;
}
- val = lduw_kernel(env->tr.base + io_offset);
+ val = cpu_lduw_kernel(env, env->tr.base + io_offset);
val >>= (addr & 7);
mask = (1 << size) - 1;
/* all bits must be zero to allow the I/O */
@@ -53,19 +52,19 @@ static inline void check_io(int addr, int size)
}
}
-void helper_check_iob(uint32_t t0)
+void helper_check_iob(CPUX86State *env, uint32_t t0)
{
- check_io(t0, 1);
+ check_io(env, t0, 1);
}
-void helper_check_iow(uint32_t t0)
+void helper_check_iow(CPUX86State *env, uint32_t t0)
{
- check_io(t0, 2);
+ check_io(env, t0, 2);
}
-void helper_check_iol(uint32_t t0)
+void helper_check_iol(CPUX86State *env, uint32_t t0)
{
- check_io(t0, 4);
+ check_io(env, t0, 4);
}
void helper_outb(uint32_t port, uint32_t data)
@@ -98,17 +97,17 @@ target_ulong helper_inl(uint32_t port)
return cpu_inl(port);
}
-void helper_into(int next_eip_addend)
+void helper_into(CPUX86State *env, int next_eip_addend)
{
int eflags;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
if (eflags & CC_O) {
raise_interrupt(env, EXCP04_INTO, 1, 0, next_eip_addend);
}
}
-void helper_single_step(void)
+void helper_single_step(CPUX86State *env)
{
#ifndef CONFIG_USER_ONLY
check_hw_breakpoints(env, 1);
@@ -117,7 +116,7 @@ void helper_single_step(void)
raise_exception(env, EXCP01_DB);
}
-void helper_cpuid(void)
+void helper_cpuid(CPUX86State *env)
{
uint32_t eax, ebx, ecx, edx;
@@ -131,20 +130,20 @@ void helper_cpuid(void)
}
#if defined(CONFIG_USER_ONLY)
-target_ulong helper_read_crN(int reg)
+target_ulong helper_read_crN(CPUX86State *env, int reg)
{
return 0;
}
-void helper_write_crN(int reg, target_ulong t0)
+void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
{
}
-void helper_movl_drN_T0(int reg, target_ulong t0)
+void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
{
}
#else
-target_ulong helper_read_crN(int reg)
+target_ulong helper_read_crN(CPUX86State *env, int reg)
{
target_ulong val;
@@ -164,7 +163,7 @@ target_ulong helper_read_crN(int reg)
return val;
}
-void helper_write_crN(int reg, target_ulong t0)
+void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
{
cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0);
switch (reg) {
@@ -189,7 +188,7 @@ void helper_write_crN(int reg, target_ulong t0)
}
}
-void helper_movl_drN_T0(int reg, target_ulong t0)
+void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
{
int i;
@@ -211,21 +210,21 @@ void helper_movl_drN_T0(int reg, target_ulong t0)
}
#endif
-void helper_lmsw(target_ulong t0)
+void helper_lmsw(CPUX86State *env, target_ulong t0)
{
/* only 4 lower bits of CR0 are modified. PE cannot be set to zero
if already set to one. */
t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
- helper_write_crN(0, t0);
+ helper_write_crN(env, 0, t0);
}
-void helper_invlpg(target_ulong addr)
+void helper_invlpg(CPUX86State *env, target_ulong addr)
{
cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0);
tlb_flush_page(env, addr);
}
-void helper_rdtsc(void)
+void helper_rdtsc(CPUX86State *env)
{
uint64_t val;
@@ -239,13 +238,13 @@ void helper_rdtsc(void)
EDX = (uint32_t)(val >> 32);
}
-void helper_rdtscp(void)
+void helper_rdtscp(CPUX86State *env)
{
- helper_rdtsc();
+ helper_rdtsc(env);
ECX = (uint32_t)(env->tsc_aux);
}
-void helper_rdpmc(void)
+void helper_rdpmc(CPUX86State *env)
{
if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
raise_exception(env, EXCP0D_GPF);
@@ -258,15 +257,15 @@ void helper_rdpmc(void)
}
#if defined(CONFIG_USER_ONLY)
-void helper_wrmsr(void)
+void helper_wrmsr(CPUX86State *env)
{
}
-void helper_rdmsr(void)
+void helper_rdmsr(CPUX86State *env)
{
}
#else
-void helper_wrmsr(void)
+void helper_wrmsr(CPUX86State *env)
{
uint64_t val;
@@ -413,7 +412,7 @@ void helper_wrmsr(void)
}
}
-void helper_rdmsr(void)
+void helper_rdmsr(CPUX86State *env)
{
uint64_t val;
@@ -554,7 +553,7 @@ void helper_rdmsr(void)
}
#endif
-static void do_hlt(void)
+static void do_hlt(CPUX86State *env)
{
env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
env->halted = 1;
@@ -562,15 +561,15 @@ static void do_hlt(void)
cpu_loop_exit(env);
}
-void helper_hlt(int next_eip_addend)
+void helper_hlt(CPUX86State *env, int next_eip_addend)
{
cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0);
EIP += next_eip_addend;
- do_hlt();
+ do_hlt(env);
}
-void helper_monitor(target_ulong ptr)
+void helper_monitor(CPUX86State *env, target_ulong ptr)
{
if ((uint32_t)ECX != 0) {
raise_exception(env, EXCP0D_GPF);
@@ -579,7 +578,7 @@ void helper_monitor(target_ulong ptr)
cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0);
}
-void helper_mwait(int next_eip_addend)
+void helper_mwait(CPUX86State *env, int next_eip_addend)
{
if ((uint32_t)ECX != 0) {
raise_exception(env, EXCP0D_GPF);
@@ -592,11 +591,11 @@ void helper_mwait(int next_eip_addend)
/* more than one CPU: do not sleep because another CPU may
wake this one */
} else {
- do_hlt();
+ do_hlt(env);
}
}
-void helper_debug(void)
+void helper_debug(CPUX86State *env)
{
env->exception_index = EXCP_DEBUG;
cpu_loop_exit(env);
diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h
index d109512..cad9d75 100644
--- a/target-i386/ops_sse.h
+++ b/target-i386/ops_sse.h
@@ -35,7 +35,7 @@
#define SUFFIX _xmm
#endif
-void glue(helper_psrlw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psrlw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift;
@@ -59,7 +59,7 @@ void glue(helper_psrlw, SUFFIX)(Reg *d, Reg *s)
}
}
-void glue(helper_psraw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psraw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift;
@@ -80,7 +80,7 @@ void glue(helper_psraw, SUFFIX)(Reg *d, Reg *s)
#endif
}
-void glue(helper_psllw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psllw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift;
@@ -104,7 +104,7 @@ void glue(helper_psllw, SUFFIX)(Reg *d, Reg *s)
}
}
-void glue(helper_psrld, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psrld, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift;
@@ -124,7 +124,7 @@ void glue(helper_psrld, SUFFIX)(Reg *d, Reg *s)
}
}
-void glue(helper_psrad, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psrad, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift;
@@ -141,7 +141,7 @@ void glue(helper_psrad, SUFFIX)(Reg *d, Reg *s)
#endif
}
-void glue(helper_pslld, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_pslld, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift;
@@ -161,7 +161,7 @@ void glue(helper_pslld, SUFFIX)(Reg *d, Reg *s)
}
}
-void glue(helper_psrlq, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psrlq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift;
@@ -179,7 +179,7 @@ void glue(helper_psrlq, SUFFIX)(Reg *d, Reg *s)
}
}
-void glue(helper_psllq, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psllq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift;
@@ -198,7 +198,7 @@ void glue(helper_psllq, SUFFIX)(Reg *d, Reg *s)
}
#if SHIFT == 1
-void glue(helper_psrldq, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psrldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift, i;
@@ -214,7 +214,7 @@ void glue(helper_psrldq, SUFFIX)(Reg *d, Reg *s)
}
}
-void glue(helper_pslldq, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_pslldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int shift, i;
@@ -232,7 +232,7 @@ void glue(helper_pslldq, SUFFIX)(Reg *d, Reg *s)
#endif
#define SSE_HELPER_B(name, F) \
- void glue(name, SUFFIX)(Reg *d, Reg *s) \
+ void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \
{ \
d->B(0) = F(d->B(0), s->B(0)); \
d->B(1) = F(d->B(1), s->B(1)); \
@@ -255,7 +255,7 @@ void glue(helper_pslldq, SUFFIX)(Reg *d, Reg *s)
}
#define SSE_HELPER_W(name, F) \
- void glue(name, SUFFIX)(Reg *d, Reg *s) \
+ void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \
{ \
d->W(0) = F(d->W(0), s->W(0)); \
d->W(1) = F(d->W(1), s->W(1)); \
@@ -270,7 +270,7 @@ void glue(helper_pslldq, SUFFIX)(Reg *d, Reg *s)
}
#define SSE_HELPER_L(name, F) \
- void glue(name, SUFFIX)(Reg *d, Reg *s) \
+ void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \
{ \
d->L(0) = F(d->L(0), s->L(0)); \
d->L(1) = F(d->L(1), s->L(1)); \
@@ -281,7 +281,7 @@ void glue(helper_pslldq, SUFFIX)(Reg *d, Reg *s)
}
#define SSE_HELPER_Q(name, F) \
- void glue(name, SUFFIX)(Reg *d, Reg *s) \
+ void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \
{ \
d->Q(0) = F(d->Q(0), s->Q(0)); \
XMM_ONLY( \
@@ -417,7 +417,7 @@ SSE_HELPER_W(helper_pmulhw, FMULHW)
SSE_HELPER_B(helper_pavgb, FAVG)
SSE_HELPER_W(helper_pavgw, FAVG)
-void glue(helper_pmuludq, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_pmuludq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->Q(0) = (uint64_t)s->L(0) * (uint64_t)d->L(0);
#if SHIFT == 1
@@ -425,7 +425,7 @@ void glue(helper_pmuludq, SUFFIX)(Reg *d, Reg *s)
#endif
}
-void glue(helper_pmaddwd, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_pmaddwd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int i;
@@ -445,7 +445,7 @@ static inline int abs1(int a)
}
}
#endif
-void glue(helper_psadbw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_psadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
unsigned int val;
@@ -473,13 +473,14 @@ void glue(helper_psadbw, SUFFIX)(Reg *d, Reg *s)
#endif
}
-void glue(helper_maskmov, SUFFIX)(Reg *d, Reg *s, target_ulong a0)
+void glue(helper_maskmov, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ target_ulong a0)
{
int i;
for (i = 0; i < (8 << SHIFT); i++) {
if (s->B(i) & 0x80) {
- stb(a0 + i, d->B(i));
+ cpu_stb_data(env, a0 + i, d->B(i));
}
}
}
@@ -575,29 +576,29 @@ void glue(helper_pshufhw, SUFFIX)(Reg *d, Reg *s, int order)
/* FPU ops */
/* XXX: not accurate */
-#define SSE_HELPER_S(name, F) \
- void helper_ ## name ## ps(Reg *d, Reg *s) \
- { \
- d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0)); \
- d->XMM_S(1) = F(32, d->XMM_S(1), s->XMM_S(1)); \
- d->XMM_S(2) = F(32, d->XMM_S(2), s->XMM_S(2)); \
- d->XMM_S(3) = F(32, d->XMM_S(3), s->XMM_S(3)); \
- } \
- \
- void helper_ ## name ## ss(Reg *d, Reg *s) \
- { \
- d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0)); \
- } \
- \
- void helper_ ## name ## pd(Reg *d, Reg *s) \
- { \
- d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0)); \
- d->XMM_D(1) = F(64, d->XMM_D(1), s->XMM_D(1)); \
- } \
- \
- void helper_ ## name ## sd(Reg *d, Reg *s) \
- { \
- d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0)); \
+#define SSE_HELPER_S(name, F) \
+ void helper_ ## name ## ps(CPUX86State *env, Reg *d, Reg *s) \
+ { \
+ d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0)); \
+ d->XMM_S(1) = F(32, d->XMM_S(1), s->XMM_S(1)); \
+ d->XMM_S(2) = F(32, d->XMM_S(2), s->XMM_S(2)); \
+ d->XMM_S(3) = F(32, d->XMM_S(3), s->XMM_S(3)); \
+ } \
+ \
+ void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s) \
+ { \
+ d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0)); \
+ } \
+ \
+ void helper_ ## name ## pd(CPUX86State *env, Reg *d, Reg *s) \
+ { \
+ d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0)); \
+ d->XMM_D(1) = F(64, d->XMM_D(1), s->XMM_D(1)); \
+ } \
+ \
+ void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s) \
+ { \
+ d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0)); \
}
#define FPU_ADD(size, a, b) float ## size ## _add(a, b, &env->sse_status)
@@ -625,7 +626,7 @@ SSE_HELPER_S(sqrt, FPU_SQRT)
/* float to float conversions */
-void helper_cvtps2pd(Reg *d, Reg *s)
+void helper_cvtps2pd(CPUX86State *env, Reg *d, Reg *s)
{
float32 s0, s1;
@@ -635,25 +636,25 @@ void helper_cvtps2pd(Reg *d, Reg *s)
d->XMM_D(1) = float32_to_float64(s1, &env->sse_status);
}
-void helper_cvtpd2ps(Reg *d, Reg *s)
+void helper_cvtpd2ps(CPUX86State *env, Reg *d, Reg *s)
{
d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status);
d->XMM_S(1) = float64_to_float32(s->XMM_D(1), &env->sse_status);
d->Q(1) = 0;
}
-void helper_cvtss2sd(Reg *d, Reg *s)
+void helper_cvtss2sd(CPUX86State *env, Reg *d, Reg *s)
{
d->XMM_D(0) = float32_to_float64(s->XMM_S(0), &env->sse_status);
}
-void helper_cvtsd2ss(Reg *d, Reg *s)
+void helper_cvtsd2ss(CPUX86State *env, Reg *d, Reg *s)
{
d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status);
}
/* integer to float */
-void helper_cvtdq2ps(Reg *d, Reg *s)
+void helper_cvtdq2ps(CPUX86State *env, Reg *d, Reg *s)
{
d->XMM_S(0) = int32_to_float32(s->XMM_L(0), &env->sse_status);
d->XMM_S(1) = int32_to_float32(s->XMM_L(1), &env->sse_status);
@@ -661,7 +662,7 @@ void helper_cvtdq2ps(Reg *d, Reg *s)
d->XMM_S(3) = int32_to_float32(s->XMM_L(3), &env->sse_status);
}
-void helper_cvtdq2pd(Reg *d, Reg *s)
+void helper_cvtdq2pd(CPUX86State *env, Reg *d, Reg *s)
{
int32_t l0, l1;
@@ -671,42 +672,42 @@ void helper_cvtdq2pd(Reg *d, Reg *s)
d->XMM_D(1) = int32_to_float64(l1, &env->sse_status);
}
-void helper_cvtpi2ps(XMMReg *d, MMXReg *s)
+void helper_cvtpi2ps(CPUX86State *env, XMMReg *d, MMXReg *s)
{
d->XMM_S(0) = int32_to_float32(s->MMX_L(0), &env->sse_status);
d->XMM_S(1) = int32_to_float32(s->MMX_L(1), &env->sse_status);
}
-void helper_cvtpi2pd(XMMReg *d, MMXReg *s)
+void helper_cvtpi2pd(CPUX86State *env, XMMReg *d, MMXReg *s)
{
d->XMM_D(0) = int32_to_float64(s->MMX_L(0), &env->sse_status);
d->XMM_D(1) = int32_to_float64(s->MMX_L(1), &env->sse_status);
}
-void helper_cvtsi2ss(XMMReg *d, uint32_t val)
+void helper_cvtsi2ss(CPUX86State *env, XMMReg *d, uint32_t val)
{
d->XMM_S(0) = int32_to_float32(val, &env->sse_status);
}
-void helper_cvtsi2sd(XMMReg *d, uint32_t val)
+void helper_cvtsi2sd(CPUX86State *env, XMMReg *d, uint32_t val)
{
d->XMM_D(0) = int32_to_float64(val, &env->sse_status);
}
#ifdef TARGET_X86_64
-void helper_cvtsq2ss(XMMReg *d, uint64_t val)
+void helper_cvtsq2ss(CPUX86State *env, XMMReg *d, uint64_t val)
{
d->XMM_S(0) = int64_to_float32(val, &env->sse_status);
}
-void helper_cvtsq2sd(XMMReg *d, uint64_t val)
+void helper_cvtsq2sd(CPUX86State *env, XMMReg *d, uint64_t val)
{
d->XMM_D(0) = int64_to_float64(val, &env->sse_status);
}
#endif
/* float to integer */
-void helper_cvtps2dq(XMMReg *d, XMMReg *s)
+void helper_cvtps2dq(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status);
d->XMM_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status);
@@ -714,49 +715,49 @@ void helper_cvtps2dq(XMMReg *d, XMMReg *s)
d->XMM_L(3) = float32_to_int32(s->XMM_S(3), &env->sse_status);
}
-void helper_cvtpd2dq(XMMReg *d, XMMReg *s)
+void helper_cvtpd2dq(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status);
d->XMM_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status);
d->XMM_Q(1) = 0;
}
-void helper_cvtps2pi(MMXReg *d, XMMReg *s)
+void helper_cvtps2pi(CPUX86State *env, MMXReg *d, XMMReg *s)
{
d->MMX_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status);
d->MMX_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status);
}
-void helper_cvtpd2pi(MMXReg *d, XMMReg *s)
+void helper_cvtpd2pi(CPUX86State *env, MMXReg *d, XMMReg *s)
{
d->MMX_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status);
d->MMX_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status);
}
-int32_t helper_cvtss2si(XMMReg *s)
+int32_t helper_cvtss2si(CPUX86State *env, XMMReg *s)
{
return float32_to_int32(s->XMM_S(0), &env->sse_status);
}
-int32_t helper_cvtsd2si(XMMReg *s)
+int32_t helper_cvtsd2si(CPUX86State *env, XMMReg *s)
{
return float64_to_int32(s->XMM_D(0), &env->sse_status);
}
#ifdef TARGET_X86_64
-int64_t helper_cvtss2sq(XMMReg *s)
+int64_t helper_cvtss2sq(CPUX86State *env, XMMReg *s)
{
return float32_to_int64(s->XMM_S(0), &env->sse_status);
}
-int64_t helper_cvtsd2sq(XMMReg *s)
+int64_t helper_cvtsd2sq(CPUX86State *env, XMMReg *s)
{
return float64_to_int64(s->XMM_D(0), &env->sse_status);
}
#endif
/* float to integer truncated */
-void helper_cvttps2dq(XMMReg *d, XMMReg *s)
+void helper_cvttps2dq(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
d->XMM_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status);
@@ -764,48 +765,48 @@ void helper_cvttps2dq(XMMReg *d, XMMReg *s)
d->XMM_L(3) = float32_to_int32_round_to_zero(s->XMM_S(3), &env->sse_status);
}
-void helper_cvttpd2dq(XMMReg *d, XMMReg *s)
+void helper_cvttpd2dq(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
d->XMM_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status);
d->XMM_Q(1) = 0;
}
-void helper_cvttps2pi(MMXReg *d, XMMReg *s)
+void helper_cvttps2pi(CPUX86State *env, MMXReg *d, XMMReg *s)
{
d->MMX_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
d->MMX_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status);
}
-void helper_cvttpd2pi(MMXReg *d, XMMReg *s)
+void helper_cvttpd2pi(CPUX86State *env, MMXReg *d, XMMReg *s)
{
d->MMX_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
d->MMX_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status);
}
-int32_t helper_cvttss2si(XMMReg *s)
+int32_t helper_cvttss2si(CPUX86State *env, XMMReg *s)
{
return float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
}
-int32_t helper_cvttsd2si(XMMReg *s)
+int32_t helper_cvttsd2si(CPUX86State *env, XMMReg *s)
{
return float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
}
#ifdef TARGET_X86_64
-int64_t helper_cvttss2sq(XMMReg *s)
+int64_t helper_cvttss2sq(CPUX86State *env, XMMReg *s)
{
return float32_to_int64_round_to_zero(s->XMM_S(0), &env->sse_status);
}
-int64_t helper_cvttsd2sq(XMMReg *s)
+int64_t helper_cvttsd2sq(CPUX86State *env, XMMReg *s)
{
return float64_to_int64_round_to_zero(s->XMM_D(0), &env->sse_status);
}
#endif
-void helper_rsqrtps(XMMReg *d, XMMReg *s)
+void helper_rsqrtps(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_S(0) = float32_div(float32_one,
float32_sqrt(s->XMM_S(0), &env->sse_status),
@@ -821,14 +822,14 @@ void helper_rsqrtps(XMMReg *d, XMMReg *s)
&env->sse_status);
}
-void helper_rsqrtss(XMMReg *d, XMMReg *s)
+void helper_rsqrtss(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_S(0) = float32_div(float32_one,
float32_sqrt(s->XMM_S(0), &env->sse_status),
&env->sse_status);
}
-void helper_rcpps(XMMReg *d, XMMReg *s)
+void helper_rcpps(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status);
d->XMM_S(1) = float32_div(float32_one, s->XMM_S(1), &env->sse_status);
@@ -836,7 +837,7 @@ void helper_rcpps(XMMReg *d, XMMReg *s)
d->XMM_S(3) = float32_div(float32_one, s->XMM_S(3), &env->sse_status);
}
-void helper_rcpss(XMMReg *d, XMMReg *s)
+void helper_rcpss(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_S(0) = float32_div(float32_one, s->XMM_S(0), &env->sse_status);
}
@@ -853,12 +854,12 @@ static inline uint64_t helper_extrq(uint64_t src, int shift, int len)
return (src >> shift) & mask;
}
-void helper_extrq_r(XMMReg *d, XMMReg *s)
+void helper_extrq_r(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_Q(0) = helper_extrq(d->XMM_Q(0), s->XMM_B(1), s->XMM_B(0));
}
-void helper_extrq_i(XMMReg *d, int index, int length)
+void helper_extrq_i(CPUX86State *env, XMMReg *d, int index, int length)
{
d->XMM_Q(0) = helper_extrq(d->XMM_Q(0), index, length);
}
@@ -875,17 +876,17 @@ static inline uint64_t helper_insertq(uint64_t src, int shift, int len)
return (src & ~(mask << shift)) | ((src & mask) << shift);
}
-void helper_insertq_r(XMMReg *d, XMMReg *s)
+void helper_insertq_r(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_Q(0) = helper_insertq(s->XMM_Q(0), s->XMM_B(9), s->XMM_B(8));
}
-void helper_insertq_i(XMMReg *d, int index, int length)
+void helper_insertq_i(CPUX86State *env, XMMReg *d, int index, int length)
{
d->XMM_Q(0) = helper_insertq(d->XMM_Q(0), index, length);
}
-void helper_haddps(XMMReg *d, XMMReg *s)
+void helper_haddps(CPUX86State *env, XMMReg *d, XMMReg *s)
{
XMMReg r;
@@ -896,7 +897,7 @@ void helper_haddps(XMMReg *d, XMMReg *s)
*d = r;
}
-void helper_haddpd(XMMReg *d, XMMReg *s)
+void helper_haddpd(CPUX86State *env, XMMReg *d, XMMReg *s)
{
XMMReg r;
@@ -905,7 +906,7 @@ void helper_haddpd(XMMReg *d, XMMReg *s)
*d = r;
}
-void helper_hsubps(XMMReg *d, XMMReg *s)
+void helper_hsubps(CPUX86State *env, XMMReg *d, XMMReg *s)
{
XMMReg r;
@@ -916,7 +917,7 @@ void helper_hsubps(XMMReg *d, XMMReg *s)
*d = r;
}
-void helper_hsubpd(XMMReg *d, XMMReg *s)
+void helper_hsubpd(CPUX86State *env, XMMReg *d, XMMReg *s)
{
XMMReg r;
@@ -925,7 +926,7 @@ void helper_hsubpd(XMMReg *d, XMMReg *s)
*d = r;
}
-void helper_addsubps(XMMReg *d, XMMReg *s)
+void helper_addsubps(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_S(0) = float32_sub(d->XMM_S(0), s->XMM_S(0), &env->sse_status);
d->XMM_S(1) = float32_add(d->XMM_S(1), s->XMM_S(1), &env->sse_status);
@@ -933,36 +934,36 @@ void helper_addsubps(XMMReg *d, XMMReg *s)
d->XMM_S(3) = float32_add(d->XMM_S(3), s->XMM_S(3), &env->sse_status);
}
-void helper_addsubpd(XMMReg *d, XMMReg *s)
+void helper_addsubpd(CPUX86State *env, XMMReg *d, XMMReg *s)
{
d->XMM_D(0) = float64_sub(d->XMM_D(0), s->XMM_D(0), &env->sse_status);
d->XMM_D(1) = float64_add(d->XMM_D(1), s->XMM_D(1), &env->sse_status);
}
/* XXX: unordered */
-#define SSE_HELPER_CMP(name, F) \
- void helper_ ## name ## ps(Reg *d, Reg *s) \
- { \
- d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0)); \
- d->XMM_L(1) = F(32, d->XMM_S(1), s->XMM_S(1)); \
- d->XMM_L(2) = F(32, d->XMM_S(2), s->XMM_S(2)); \
- d->XMM_L(3) = F(32, d->XMM_S(3), s->XMM_S(3)); \
- } \
- \
- void helper_ ## name ## ss(Reg *d, Reg *s) \
- { \
- d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0)); \
- } \
- \
- void helper_ ## name ## pd(Reg *d, Reg *s) \
- { \
- d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0)); \
- d->XMM_Q(1) = F(64, d->XMM_D(1), s->XMM_D(1)); \
- } \
- \
- void helper_ ## name ## sd(Reg *d, Reg *s) \
- { \
- d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0)); \
+#define SSE_HELPER_CMP(name, F) \
+ void helper_ ## name ## ps(CPUX86State *env, Reg *d, Reg *s) \
+ { \
+ d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0)); \
+ d->XMM_L(1) = F(32, d->XMM_S(1), s->XMM_S(1)); \
+ d->XMM_L(2) = F(32, d->XMM_S(2), s->XMM_S(2)); \
+ d->XMM_L(3) = F(32, d->XMM_S(3), s->XMM_S(3)); \
+ } \
+ \
+ void helper_ ## name ## ss(CPUX86State *env, Reg *d, Reg *s) \
+ { \
+ d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0)); \
+ } \
+ \
+ void helper_ ## name ## pd(CPUX86State *env, Reg *d, Reg *s) \
+ { \
+ d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0)); \
+ d->XMM_Q(1) = F(64, d->XMM_D(1), s->XMM_D(1)); \
+ } \
+ \
+ void helper_ ## name ## sd(CPUX86State *env, Reg *d, Reg *s) \
+ { \
+ d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0)); \
}
#define FPU_CMPEQ(size, a, b) \
@@ -993,7 +994,7 @@ SSE_HELPER_CMP(cmpord, FPU_CMPORD)
static const int comis_eflags[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
-void helper_ucomiss(Reg *d, Reg *s)
+void helper_ucomiss(CPUX86State *env, Reg *d, Reg *s)
{
int ret;
float32 s0, s1;
@@ -1004,7 +1005,7 @@ void helper_ucomiss(Reg *d, Reg *s)
CC_SRC = comis_eflags[ret + 1];
}
-void helper_comiss(Reg *d, Reg *s)
+void helper_comiss(CPUX86State *env, Reg *d, Reg *s)
{
int ret;
float32 s0, s1;
@@ -1015,7 +1016,7 @@ void helper_comiss(Reg *d, Reg *s)
CC_SRC = comis_eflags[ret + 1];
}
-void helper_ucomisd(Reg *d, Reg *s)
+void helper_ucomisd(CPUX86State *env, Reg *d, Reg *s)
{
int ret;
float64 d0, d1;
@@ -1026,7 +1027,7 @@ void helper_ucomisd(Reg *d, Reg *s)
CC_SRC = comis_eflags[ret + 1];
}
-void helper_comisd(Reg *d, Reg *s)
+void helper_comisd(CPUX86State *env, Reg *d, Reg *s)
{
int ret;
float64 d0, d1;
@@ -1037,7 +1038,7 @@ void helper_comisd(Reg *d, Reg *s)
CC_SRC = comis_eflags[ret + 1];
}
-uint32_t helper_movmskps(Reg *s)
+uint32_t helper_movmskps(CPUX86State *env, Reg *s)
{
int b0, b1, b2, b3;
@@ -1048,7 +1049,7 @@ uint32_t helper_movmskps(Reg *s)
return b0 | (b1 << 1) | (b2 << 2) | (b3 << 3);
}
-uint32_t helper_movmskpd(Reg *s)
+uint32_t helper_movmskpd(CPUX86State *env, Reg *s)
{
int b0, b1;
@@ -1059,7 +1060,7 @@ uint32_t helper_movmskpd(Reg *s)
#endif
-uint32_t glue(helper_pmovmskb, SUFFIX)(Reg *s)
+uint32_t glue(helper_pmovmskb, SUFFIX)(CPUX86State *env, Reg *s)
{
uint32_t val;
@@ -1085,7 +1086,7 @@ uint32_t glue(helper_pmovmskb, SUFFIX)(Reg *s)
return val;
}
-void glue(helper_packsswb, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_packsswb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
Reg r;
@@ -1112,7 +1113,7 @@ void glue(helper_packsswb, SUFFIX)(Reg *d, Reg *s)
*d = r;
}
-void glue(helper_packuswb, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_packuswb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
Reg r;
@@ -1139,7 +1140,7 @@ void glue(helper_packuswb, SUFFIX)(Reg *d, Reg *s)
*d = r;
}
-void glue(helper_packssdw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_packssdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
Reg r;
@@ -1160,7 +1161,8 @@ void glue(helper_packssdw, SUFFIX)(Reg *d, Reg *s)
#define UNPCK_OP(base_name, base) \
\
- void glue(helper_punpck ## base_name ## bw, SUFFIX)(Reg *d, Reg *s) \
+ void glue(helper_punpck ## base_name ## bw, SUFFIX)(CPUX86State *env,\
+ Reg *d, Reg *s) \
{ \
Reg r; \
\
@@ -1181,11 +1183,12 @@ void glue(helper_packssdw, SUFFIX)(Reg *d, Reg *s)
r.B(13) = s->B((base << (SHIFT + 2)) + 6); \
r.B(14) = d->B((base << (SHIFT + 2)) + 7); \
r.B(15) = s->B((base << (SHIFT + 2)) + 7); \
- ) \
+ ) \
*d = r; \
} \
\
- void glue(helper_punpck ## base_name ## wd, SUFFIX)(Reg *d, Reg *s) \
+ void glue(helper_punpck ## base_name ## wd, SUFFIX)(CPUX86State *env,\
+ Reg *d, Reg *s) \
{ \
Reg r; \
\
@@ -1198,11 +1201,12 @@ void glue(helper_packssdw, SUFFIX)(Reg *d, Reg *s)
r.W(5) = s->W((base << (SHIFT + 1)) + 2); \
r.W(6) = d->W((base << (SHIFT + 1)) + 3); \
r.W(7) = s->W((base << (SHIFT + 1)) + 3); \
- ) \
+ ) \
*d = r; \
} \
\
- void glue(helper_punpck ## base_name ## dq, SUFFIX)(Reg *d, Reg *s) \
+ void glue(helper_punpck ## base_name ## dq, SUFFIX)(CPUX86State *env,\
+ Reg *d, Reg *s) \
{ \
Reg r; \
\
@@ -1211,12 +1215,14 @@ void glue(helper_packssdw, SUFFIX)(Reg *d, Reg *s)
XMM_ONLY( \
r.L(2) = d->L((base << SHIFT) + 1); \
r.L(3) = s->L((base << SHIFT) + 1); \
- ) \
+ ) \
*d = r; \
} \
\
XMM_ONLY( \
- void glue(helper_punpck ## base_name ## qdq, SUFFIX)(Reg *d, \
+ void glue(helper_punpck ## base_name ## qdq, SUFFIX)(CPUX86State \
+ *env, \
+ Reg *d, \
Reg *s) \
{ \
Reg r; \
@@ -1232,25 +1238,25 @@ UNPCK_OP(h, 1)
/* 3DNow! float ops */
#if SHIFT == 0
-void helper_pi2fd(MMXReg *d, MMXReg *s)
+void helper_pi2fd(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_S(0) = int32_to_float32(s->MMX_L(0), &env->mmx_status);
d->MMX_S(1) = int32_to_float32(s->MMX_L(1), &env->mmx_status);
}
-void helper_pi2fw(MMXReg *d, MMXReg *s)
+void helper_pi2fw(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_S(0) = int32_to_float32((int16_t)s->MMX_W(0), &env->mmx_status);
d->MMX_S(1) = int32_to_float32((int16_t)s->MMX_W(2), &env->mmx_status);
}
-void helper_pf2id(MMXReg *d, MMXReg *s)
+void helper_pf2id(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_L(0) = float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status);
d->MMX_L(1) = float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status);
}
-void helper_pf2iw(MMXReg *d, MMXReg *s)
+void helper_pf2iw(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_L(0) = satsw(float32_to_int32_round_to_zero(s->MMX_S(0),
&env->mmx_status));
@@ -1258,7 +1264,7 @@ void helper_pf2iw(MMXReg *d, MMXReg *s)
&env->mmx_status));
}
-void helper_pfacc(MMXReg *d, MMXReg *s)
+void helper_pfacc(CPUX86State *env, MMXReg *d, MMXReg *s)
{
MMXReg r;
@@ -1267,13 +1273,13 @@ void helper_pfacc(MMXReg *d, MMXReg *s)
*d = r;
}
-void helper_pfadd(MMXReg *d, MMXReg *s)
+void helper_pfadd(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_S(0) = float32_add(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = float32_add(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
}
-void helper_pfcmpeq(MMXReg *d, MMXReg *s)
+void helper_pfcmpeq(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_L(0) = float32_eq_quiet(d->MMX_S(0), s->MMX_S(0),
&env->mmx_status) ? -1 : 0;
@@ -1281,7 +1287,7 @@ void helper_pfcmpeq(MMXReg *d, MMXReg *s)
&env->mmx_status) ? -1 : 0;
}
-void helper_pfcmpge(MMXReg *d, MMXReg *s)
+void helper_pfcmpge(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_L(0) = float32_le(s->MMX_S(0), d->MMX_S(0),
&env->mmx_status) ? -1 : 0;
@@ -1289,7 +1295,7 @@ void helper_pfcmpge(MMXReg *d, MMXReg *s)
&env->mmx_status) ? -1 : 0;
}
-void helper_pfcmpgt(MMXReg *d, MMXReg *s)
+void helper_pfcmpgt(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_L(0) = float32_lt(s->MMX_S(0), d->MMX_S(0),
&env->mmx_status) ? -1 : 0;
@@ -1297,7 +1303,7 @@ void helper_pfcmpgt(MMXReg *d, MMXReg *s)
&env->mmx_status) ? -1 : 0;
}
-void helper_pfmax(MMXReg *d, MMXReg *s)
+void helper_pfmax(CPUX86State *env, MMXReg *d, MMXReg *s)
{
if (float32_lt(d->MMX_S(0), s->MMX_S(0), &env->mmx_status)) {
d->MMX_S(0) = s->MMX_S(0);
@@ -1307,7 +1313,7 @@ void helper_pfmax(MMXReg *d, MMXReg *s)
}
}
-void helper_pfmin(MMXReg *d, MMXReg *s)
+void helper_pfmin(CPUX86State *env, MMXReg *d, MMXReg *s)
{
if (float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status)) {
d->MMX_S(0) = s->MMX_S(0);
@@ -1317,13 +1323,13 @@ void helper_pfmin(MMXReg *d, MMXReg *s)
}
}
-void helper_pfmul(MMXReg *d, MMXReg *s)
+void helper_pfmul(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_S(0) = float32_mul(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = float32_mul(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
}
-void helper_pfnacc(MMXReg *d, MMXReg *s)
+void helper_pfnacc(CPUX86State *env, MMXReg *d, MMXReg *s)
{
MMXReg r;
@@ -1332,7 +1338,7 @@ void helper_pfnacc(MMXReg *d, MMXReg *s)
*d = r;
}
-void helper_pfpnacc(MMXReg *d, MMXReg *s)
+void helper_pfpnacc(CPUX86State *env, MMXReg *d, MMXReg *s)
{
MMXReg r;
@@ -1341,13 +1347,13 @@ void helper_pfpnacc(MMXReg *d, MMXReg *s)
*d = r;
}
-void helper_pfrcp(MMXReg *d, MMXReg *s)
+void helper_pfrcp(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_S(0) = float32_div(float32_one, s->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = d->MMX_S(0);
}
-void helper_pfrsqrt(MMXReg *d, MMXReg *s)
+void helper_pfrsqrt(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_L(1) = s->MMX_L(0) & 0x7fffffff;
d->MMX_S(1) = float32_div(float32_one,
@@ -1357,19 +1363,19 @@ void helper_pfrsqrt(MMXReg *d, MMXReg *s)
d->MMX_L(0) = d->MMX_L(1);
}
-void helper_pfsub(MMXReg *d, MMXReg *s)
+void helper_pfsub(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_S(0) = float32_sub(d->MMX_S(0), s->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = float32_sub(d->MMX_S(1), s->MMX_S(1), &env->mmx_status);
}
-void helper_pfsubr(MMXReg *d, MMXReg *s)
+void helper_pfsubr(CPUX86State *env, MMXReg *d, MMXReg *s)
{
d->MMX_S(0) = float32_sub(s->MMX_S(0), d->MMX_S(0), &env->mmx_status);
d->MMX_S(1) = float32_sub(s->MMX_S(1), d->MMX_S(1), &env->mmx_status);
}
-void helper_pswapd(MMXReg *d, MMXReg *s)
+void helper_pswapd(CPUX86State *env, MMXReg *d, MMXReg *s)
{
MMXReg r;
@@ -1380,7 +1386,7 @@ void helper_pswapd(MMXReg *d, MMXReg *s)
#endif
/* SSSE3 op helpers */
-void glue(helper_pshufb, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_pshufb, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int i;
Reg r;
@@ -1392,7 +1398,7 @@ void glue(helper_pshufb, SUFFIX)(Reg *d, Reg *s)
*d = r;
}
-void glue(helper_phaddw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_phaddw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->W(0) = (int16_t)d->W(0) + (int16_t)d->W(1);
d->W(1) = (int16_t)d->W(2) + (int16_t)d->W(3);
@@ -1404,7 +1410,7 @@ void glue(helper_phaddw, SUFFIX)(Reg *d, Reg *s)
XMM_ONLY(d->W(7) = (int16_t)s->W(6) + (int16_t)s->W(7));
}
-void glue(helper_phaddd, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_phaddd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->L(0) = (int32_t)d->L(0) + (int32_t)d->L(1);
XMM_ONLY(d->L(1) = (int32_t)d->L(2) + (int32_t)d->L(3));
@@ -1412,7 +1418,7 @@ void glue(helper_phaddd, SUFFIX)(Reg *d, Reg *s)
XMM_ONLY(d->L(3) = (int32_t)s->L(2) + (int32_t)s->L(3));
}
-void glue(helper_phaddsw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_phaddsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->W(0) = satsw((int16_t)d->W(0) + (int16_t)d->W(1));
d->W(1) = satsw((int16_t)d->W(2) + (int16_t)d->W(3));
@@ -1424,7 +1430,7 @@ void glue(helper_phaddsw, SUFFIX)(Reg *d, Reg *s)
XMM_ONLY(d->W(7) = satsw((int16_t)s->W(6) + (int16_t)s->W(7)));
}
-void glue(helper_pmaddubsw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_pmaddubsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->W(0) = satsw((int8_t)s->B(0) * (uint8_t)d->B(0) +
(int8_t)s->B(1) * (uint8_t)d->B(1));
@@ -1446,7 +1452,7 @@ void glue(helper_pmaddubsw, SUFFIX)(Reg *d, Reg *s)
#endif
}
-void glue(helper_phsubw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_phsubw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->W(0) = (int16_t)d->W(0) - (int16_t)d->W(1);
d->W(1) = (int16_t)d->W(2) - (int16_t)d->W(3);
@@ -1458,7 +1464,7 @@ void glue(helper_phsubw, SUFFIX)(Reg *d, Reg *s)
XMM_ONLY(d->W(7) = (int16_t)s->W(6) - (int16_t)s->W(7));
}
-void glue(helper_phsubd, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_phsubd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->L(0) = (int32_t)d->L(0) - (int32_t)d->L(1);
XMM_ONLY(d->L(1) = (int32_t)d->L(2) - (int32_t)d->L(3));
@@ -1466,7 +1472,7 @@ void glue(helper_phsubd, SUFFIX)(Reg *d, Reg *s)
XMM_ONLY(d->L(3) = (int32_t)s->L(2) - (int32_t)s->L(3));
}
-void glue(helper_phsubsw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_phsubsw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->W(0) = satsw((int16_t)d->W(0) - (int16_t)d->W(1));
d->W(1) = satsw((int16_t)d->W(2) - (int16_t)d->W(3));
@@ -1495,7 +1501,8 @@ SSE_HELPER_B(helper_psignb, FSIGNB)
SSE_HELPER_W(helper_psignw, FSIGNW)
SSE_HELPER_L(helper_psignd, FSIGNL)
-void glue(helper_palignr, SUFFIX)(Reg *d, Reg *s, int32_t shift)
+void glue(helper_palignr, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ int32_t shift)
{
Reg r;
@@ -1529,7 +1536,7 @@ void glue(helper_palignr, SUFFIX)(Reg *d, Reg *s, int32_t shift)
#if SHIFT == 1
#define SSE_HELPER_V(name, elem, num, F) \
- void glue(name, SUFFIX)(Reg *d, Reg *s) \
+ void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \
{ \
d->elem(0) = F(d->elem(0), s->elem(0), XMM0.elem(0)); \
d->elem(1) = F(d->elem(1), s->elem(1), XMM0.elem(1)); \
@@ -1556,7 +1563,7 @@ void glue(helper_palignr, SUFFIX)(Reg *d, Reg *s, int32_t shift)
}
#define SSE_HELPER_I(name, elem, num, F) \
- void glue(name, SUFFIX)(Reg *d, Reg *s, uint32_t imm) \
+ void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t imm) \
{ \
d->elem(0) = F(d->elem(0), s->elem(0), ((imm >> 0) & 1)); \
d->elem(1) = F(d->elem(1), s->elem(1), ((imm >> 1) & 1)); \
@@ -1596,7 +1603,7 @@ SSE_HELPER_V(helper_pblendvb, B, 16, FBLENDVB)
SSE_HELPER_V(helper_blendvps, L, 4, FBLENDVPS)
SSE_HELPER_V(helper_blendvpd, Q, 2, FBLENDVPD)
-void glue(helper_ptest, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_ptest, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
uint64_t zf = (s->Q(0) & d->Q(0)) | (s->Q(1) & d->Q(1));
uint64_t cf = (s->Q(0) & ~d->Q(0)) | (s->Q(1) & ~d->Q(1));
@@ -1605,7 +1612,7 @@ void glue(helper_ptest, SUFFIX)(Reg *d, Reg *s)
}
#define SSE_HELPER_F(name, elem, num, F) \
- void glue(name, SUFFIX)(Reg *d, Reg *s) \
+ void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \
{ \
d->elem(0) = F(0); \
d->elem(1) = F(1); \
@@ -1634,7 +1641,7 @@ SSE_HELPER_F(helper_pmovzxwd, L, 4, s->W)
SSE_HELPER_F(helper_pmovzxwq, Q, 2, s->W)
SSE_HELPER_F(helper_pmovzxdq, Q, 2, s->L)
-void glue(helper_pmuldq, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_pmuldq, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->Q(0) = (int64_t)(int32_t) d->L(0) * (int32_t) s->L(0);
d->Q(1) = (int64_t)(int32_t) d->L(2) * (int32_t) s->L(2);
@@ -1643,7 +1650,7 @@ void glue(helper_pmuldq, SUFFIX)(Reg *d, Reg *s)
#define FCMPEQQ(d, s) (d == s ? -1 : 0)
SSE_HELPER_Q(helper_pcmpeqq, FCMPEQQ)
-void glue(helper_packusdw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_packusdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
d->W(0) = satuw((int32_t) d->L(0));
d->W(1) = satuw((int32_t) d->L(1));
@@ -1671,7 +1678,7 @@ SSE_HELPER_L(helper_pmaxud, MAX)
#define FMULLD(d, s) ((int32_t)d * (int32_t)s)
SSE_HELPER_L(helper_pmulld, FMULLD)
-void glue(helper_phminposuw, SUFFIX)(Reg *d, Reg *s)
+void glue(helper_phminposuw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s)
{
int idx = 0;
@@ -1703,7 +1710,8 @@ void glue(helper_phminposuw, SUFFIX)(Reg *d, Reg *s)
d->W(0) = s->W(idx);
}
-void glue(helper_roundps, SUFFIX)(Reg *d, Reg *s, uint32_t mode)
+void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t mode)
{
signed char prev_rounding_mode;
@@ -1740,7 +1748,8 @@ void glue(helper_roundps, SUFFIX)(Reg *d, Reg *s, uint32_t mode)
env->sse_status.float_rounding_mode = prev_rounding_mode;
}
-void glue(helper_roundpd, SUFFIX)(Reg *d, Reg *s, uint32_t mode)
+void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t mode)
{
signed char prev_rounding_mode;
@@ -1775,7 +1784,8 @@ void glue(helper_roundpd, SUFFIX)(Reg *d, Reg *s, uint32_t mode)
env->sse_status.float_rounding_mode = prev_rounding_mode;
}
-void glue(helper_roundss, SUFFIX)(Reg *d, Reg *s, uint32_t mode)
+void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t mode)
{
signed char prev_rounding_mode;
@@ -1809,7 +1819,8 @@ void glue(helper_roundss, SUFFIX)(Reg *d, Reg *s, uint32_t mode)
env->sse_status.float_rounding_mode = prev_rounding_mode;
}
-void glue(helper_roundsd, SUFFIX)(Reg *d, Reg *s, uint32_t mode)
+void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t mode)
{
signed char prev_rounding_mode;
@@ -1848,7 +1859,7 @@ SSE_HELPER_I(helper_blendps, L, 4, FBLENDP)
SSE_HELPER_I(helper_blendpd, Q, 2, FBLENDP)
SSE_HELPER_I(helper_pblendw, W, 8, FBLENDP)
-void glue(helper_dpps, SUFFIX)(Reg *d, Reg *s, uint32_t mask)
+void glue(helper_dpps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mask)
{
float32 iresult = float32_zero;
@@ -1882,7 +1893,7 @@ void glue(helper_dpps, SUFFIX)(Reg *d, Reg *s, uint32_t mask)
d->XMM_S(3) = (mask & (1 << 3)) ? iresult : float32_zero;
}
-void glue(helper_dppd, SUFFIX)(Reg *d, Reg *s, uint32_t mask)
+void glue(helper_dppd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mask)
{
float64 iresult = float64_zero;
@@ -1902,7 +1913,8 @@ void glue(helper_dppd, SUFFIX)(Reg *d, Reg *s, uint32_t mask)
d->XMM_D(1) = (mask & (1 << 1)) ? iresult : float64_zero;
}
-void glue(helper_mpsadbw, SUFFIX)(Reg *d, Reg *s, uint32_t offset)
+void glue(helper_mpsadbw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t offset)
{
int s0 = (offset & 3) << 2;
int d0 = (offset & 4) << 0;
@@ -1925,7 +1937,7 @@ void glue(helper_mpsadbw, SUFFIX)(Reg *d, Reg *s, uint32_t offset)
#define FCMPGTQ(d, s) (d > s ? -1 : 0)
SSE_HELPER_Q(helper_pcmpgtq, FCMPGTQ)
-static inline int pcmp_elen(int reg, uint32_t ctrl)
+static inline int pcmp_elen(CPUX86State *env, int reg, uint32_t ctrl)
{
int val;
@@ -1980,7 +1992,7 @@ static inline int pcmp_val(Reg *r, uint8_t ctrl, int i)
}
}
-static inline unsigned pcmpxstrx(Reg *d, Reg *s,
+static inline unsigned pcmpxstrx(CPUX86State *env, Reg *d, Reg *s,
int8_t ctrl, int valids, int validd)
{
unsigned int res = 0;
@@ -2080,11 +2092,12 @@ static inline int ffs1(unsigned int val)
return ret;
}
-void glue(helper_pcmpestri, SUFFIX)(Reg *d, Reg *s, uint32_t ctrl)
+void glue(helper_pcmpestri, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t ctrl)
{
- unsigned int res = pcmpxstrx(d, s, ctrl,
- pcmp_elen(R_EDX, ctrl),
- pcmp_elen(R_EAX, ctrl));
+ unsigned int res = pcmpxstrx(env, d, s, ctrl,
+ pcmp_elen(env, R_EDX, ctrl),
+ pcmp_elen(env, R_EAX, ctrl));
if (res) {
env->regs[R_ECX] = ((ctrl & (1 << 6)) ? rffs1 : ffs1)(res) - 1;
@@ -2093,12 +2106,13 @@ void glue(helper_pcmpestri, SUFFIX)(Reg *d, Reg *s, uint32_t ctrl)
}
}
-void glue(helper_pcmpestrm, SUFFIX)(Reg *d, Reg *s, uint32_t ctrl)
+void glue(helper_pcmpestrm, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t ctrl)
{
int i;
- unsigned int res = pcmpxstrx(d, s, ctrl,
- pcmp_elen(R_EDX, ctrl),
- pcmp_elen(R_EAX, ctrl));
+ unsigned int res = pcmpxstrx(env, d, s, ctrl,
+ pcmp_elen(env, R_EDX, ctrl),
+ pcmp_elen(env, R_EAX, ctrl));
if ((ctrl >> 6) & 1) {
if (ctrl & 1) {
@@ -2116,9 +2130,10 @@ void glue(helper_pcmpestrm, SUFFIX)(Reg *d, Reg *s, uint32_t ctrl)
}
}
-void glue(helper_pcmpistri, SUFFIX)(Reg *d, Reg *s, uint32_t ctrl)
+void glue(helper_pcmpistri, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t ctrl)
{
- unsigned int res = pcmpxstrx(d, s, ctrl,
+ unsigned int res = pcmpxstrx(env, d, s, ctrl,
pcmp_ilen(s, ctrl),
pcmp_ilen(d, ctrl));
@@ -2129,10 +2144,11 @@ void glue(helper_pcmpistri, SUFFIX)(Reg *d, Reg *s, uint32_t ctrl)
}
}
-void glue(helper_pcmpistrm, SUFFIX)(Reg *d, Reg *s, uint32_t ctrl)
+void glue(helper_pcmpistrm, SUFFIX)(CPUX86State *env, Reg *d, Reg *s,
+ uint32_t ctrl)
{
int i;
- unsigned int res = pcmpxstrx(d, s, ctrl,
+ unsigned int res = pcmpxstrx(env, d, s, ctrl,
pcmp_ilen(s, ctrl),
pcmp_ilen(d, ctrl));
@@ -2168,7 +2184,7 @@ target_ulong helper_crc32(uint32_t crc1, target_ulong msg, uint32_t len)
#define POPMASK(i) ((target_ulong) -1 / ((1LL << (1 << i)) + 1))
#define POPCOUNT(n, i) ((n & POPMASK(i)) + ((n >> (1 << i)) & POPMASK(i)))
-target_ulong helper_popcnt(target_ulong n, uint32_t type)
+target_ulong helper_popcnt(CPUX86State *env, target_ulong n, uint32_t type)
{
CC_SRC = n ? 0 : CC_Z;
diff --git a/target-i386/ops_sse_header.h b/target-i386/ops_sse_header.h
index 8d4b2b7..401eac6 100644
--- a/target-i386/ops_sse_header.h
+++ b/target-i386/ops_sse_header.h
@@ -34,31 +34,31 @@
#define dh_is_signed_XMMReg dh_is_signed_ptr
#define dh_is_signed_MMXReg dh_is_signed_ptr
-DEF_HELPER_2(glue(psrlw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psraw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psllw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psrld, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psrad, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pslld, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psrlq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psllq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_3(glue(psrlw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psraw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psllw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psrld, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psrad, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pslld, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psrlq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psllq, SUFFIX), void, env, Reg, Reg)
#if SHIFT == 1
-DEF_HELPER_2(glue(psrldq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pslldq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_3(glue(psrldq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pslldq, SUFFIX), void, env, Reg, Reg)
#endif
#define SSE_HELPER_B(name, F)\
- DEF_HELPER_2(glue(name, SUFFIX), void, Reg, Reg)
+ DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg)
#define SSE_HELPER_W(name, F)\
- DEF_HELPER_2(glue(name, SUFFIX), void, Reg, Reg)
+ DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg)
#define SSE_HELPER_L(name, F)\
- DEF_HELPER_2(glue(name, SUFFIX), void, Reg, Reg)
+ DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg)
#define SSE_HELPER_Q(name, F)\
- DEF_HELPER_2(glue(name, SUFFIX), void, Reg, Reg)
+ DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg)
SSE_HELPER_B(paddb, FADD)
SSE_HELPER_W(paddw, FADD)
@@ -109,11 +109,11 @@ SSE_HELPER_W(pmulhw, FMULHW)
SSE_HELPER_B(pavgb, FAVG)
SSE_HELPER_W(pavgw, FAVG)
-DEF_HELPER_2(glue(pmuludq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmaddwd, SUFFIX), void, Reg, Reg)
+DEF_HELPER_3(glue(pmuludq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmaddwd, SUFFIX), void, env, Reg, Reg)
-DEF_HELPER_2(glue(psadbw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_3(glue(maskmov, SUFFIX), void, Reg, Reg, tl)
+DEF_HELPER_3(glue(psadbw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_4(glue(maskmov, SUFFIX), void, env, Reg, Reg, tl)
DEF_HELPER_2(glue(movl_mm_T0, SUFFIX), void, Reg, i32)
#ifdef TARGET_X86_64
DEF_HELPER_2(glue(movq_mm_T0, SUFFIX), void, Reg, i64)
@@ -133,11 +133,11 @@ DEF_HELPER_3(glue(pshufhw, SUFFIX), void, Reg, Reg, int)
/* FPU ops */
/* XXX: not accurate */
-#define SSE_HELPER_S(name, F)\
- DEF_HELPER_2(name ## ps , void, Reg, Reg) \
- DEF_HELPER_2(name ## ss , void, Reg, Reg) \
- DEF_HELPER_2(name ## pd , void, Reg, Reg) \
- DEF_HELPER_2(name ## sd , void, Reg, Reg)
+#define SSE_HELPER_S(name, F) \
+ DEF_HELPER_3(name ## ps, void, env, Reg, Reg) \
+ DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \
+ DEF_HELPER_3(name ## pd, void, env, Reg, Reg) \
+ DEF_HELPER_3(name ## sd, void, env, Reg, Reg)
SSE_HELPER_S(add, FPU_ADD)
SSE_HELPER_S(sub, FPU_SUB)
@@ -148,64 +148,64 @@ SSE_HELPER_S(max, FPU_MAX)
SSE_HELPER_S(sqrt, FPU_SQRT)
-DEF_HELPER_2(cvtps2pd, void, Reg, Reg)
-DEF_HELPER_2(cvtpd2ps, void, Reg, Reg)
-DEF_HELPER_2(cvtss2sd, void, Reg, Reg)
-DEF_HELPER_2(cvtsd2ss, void, Reg, Reg)
-DEF_HELPER_2(cvtdq2ps, void, Reg, Reg)
-DEF_HELPER_2(cvtdq2pd, void, Reg, Reg)
-DEF_HELPER_2(cvtpi2ps, void, XMMReg, MMXReg)
-DEF_HELPER_2(cvtpi2pd, void, XMMReg, MMXReg)
-DEF_HELPER_2(cvtsi2ss, void, XMMReg, i32)
-DEF_HELPER_2(cvtsi2sd, void, XMMReg, i32)
+DEF_HELPER_3(cvtps2pd, void, env, Reg, Reg)
+DEF_HELPER_3(cvtpd2ps, void, env, Reg, Reg)
+DEF_HELPER_3(cvtss2sd, void, env, Reg, Reg)
+DEF_HELPER_3(cvtsd2ss, void, env, Reg, Reg)
+DEF_HELPER_3(cvtdq2ps, void, env, Reg, Reg)
+DEF_HELPER_3(cvtdq2pd, void, env, Reg, Reg)
+DEF_HELPER_3(cvtpi2ps, void, env, XMMReg, MMXReg)
+DEF_HELPER_3(cvtpi2pd, void, env, XMMReg, MMXReg)
+DEF_HELPER_3(cvtsi2ss, void, env, XMMReg, i32)
+DEF_HELPER_3(cvtsi2sd, void, env, XMMReg, i32)
#ifdef TARGET_X86_64
-DEF_HELPER_2(cvtsq2ss, void, XMMReg, i64)
-DEF_HELPER_2(cvtsq2sd, void, XMMReg, i64)
+DEF_HELPER_3(cvtsq2ss, void, env, XMMReg, i64)
+DEF_HELPER_3(cvtsq2sd, void, env, XMMReg, i64)
#endif
-DEF_HELPER_2(cvtps2dq, void, XMMReg, XMMReg)
-DEF_HELPER_2(cvtpd2dq, void, XMMReg, XMMReg)
-DEF_HELPER_2(cvtps2pi, void, MMXReg, XMMReg)
-DEF_HELPER_2(cvtpd2pi, void, MMXReg, XMMReg)
-DEF_HELPER_1(cvtss2si, s32, XMMReg)
-DEF_HELPER_1(cvtsd2si, s32, XMMReg)
+DEF_HELPER_3(cvtps2dq, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(cvtpd2dq, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(cvtps2pi, void, env, MMXReg, XMMReg)
+DEF_HELPER_3(cvtpd2pi, void, env, MMXReg, XMMReg)
+DEF_HELPER_2(cvtss2si, s32, env, XMMReg)
+DEF_HELPER_2(cvtsd2si, s32, env, XMMReg)
#ifdef TARGET_X86_64
-DEF_HELPER_1(cvtss2sq, s64, XMMReg)
-DEF_HELPER_1(cvtsd2sq, s64, XMMReg)
+DEF_HELPER_2(cvtss2sq, s64, env, XMMReg)
+DEF_HELPER_2(cvtsd2sq, s64, env, XMMReg)
#endif
-DEF_HELPER_2(cvttps2dq, void, XMMReg, XMMReg)
-DEF_HELPER_2(cvttpd2dq, void, XMMReg, XMMReg)
-DEF_HELPER_2(cvttps2pi, void, MMXReg, XMMReg)
-DEF_HELPER_2(cvttpd2pi, void, MMXReg, XMMReg)
-DEF_HELPER_1(cvttss2si, s32, XMMReg)
-DEF_HELPER_1(cvttsd2si, s32, XMMReg)
+DEF_HELPER_3(cvttps2dq, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(cvttpd2dq, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(cvttps2pi, void, env, MMXReg, XMMReg)
+DEF_HELPER_3(cvttpd2pi, void, env, MMXReg, XMMReg)
+DEF_HELPER_2(cvttss2si, s32, env, XMMReg)
+DEF_HELPER_2(cvttsd2si, s32, env, XMMReg)
#ifdef TARGET_X86_64
-DEF_HELPER_1(cvttss2sq, s64, XMMReg)
-DEF_HELPER_1(cvttsd2sq, s64, XMMReg)
+DEF_HELPER_2(cvttss2sq, s64, env, XMMReg)
+DEF_HELPER_2(cvttsd2sq, s64, env, XMMReg)
#endif
-DEF_HELPER_2(rsqrtps, void, XMMReg, XMMReg)
-DEF_HELPER_2(rsqrtss, void, XMMReg, XMMReg)
-DEF_HELPER_2(rcpps, void, XMMReg, XMMReg)
-DEF_HELPER_2(rcpss, void, XMMReg, XMMReg)
-DEF_HELPER_2(extrq_r, void, XMMReg, XMMReg)
-DEF_HELPER_3(extrq_i, void, XMMReg, int, int)
-DEF_HELPER_2(insertq_r, void, XMMReg, XMMReg)
-DEF_HELPER_3(insertq_i, void, XMMReg, int, int)
-DEF_HELPER_2(haddps, void, XMMReg, XMMReg)
-DEF_HELPER_2(haddpd, void, XMMReg, XMMReg)
-DEF_HELPER_2(hsubps, void, XMMReg, XMMReg)
-DEF_HELPER_2(hsubpd, void, XMMReg, XMMReg)
-DEF_HELPER_2(addsubps, void, XMMReg, XMMReg)
-DEF_HELPER_2(addsubpd, void, XMMReg, XMMReg)
-
-#define SSE_HELPER_CMP(name, F)\
- DEF_HELPER_2( name ## ps , void, Reg, Reg) \
- DEF_HELPER_2( name ## ss , void, Reg, Reg) \
- DEF_HELPER_2( name ## pd , void, Reg, Reg) \
- DEF_HELPER_2( name ## sd , void, Reg, Reg)
+DEF_HELPER_3(rsqrtps, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(rsqrtss, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(rcpps, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(rcpss, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(extrq_r, void, env, XMMReg, XMMReg)
+DEF_HELPER_4(extrq_i, void, env, XMMReg, int, int)
+DEF_HELPER_3(insertq_r, void, env, XMMReg, XMMReg)
+DEF_HELPER_4(insertq_i, void, env, XMMReg, int, int)
+DEF_HELPER_3(haddps, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(haddpd, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(hsubps, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(hsubpd, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(addsubps, void, env, XMMReg, XMMReg)
+DEF_HELPER_3(addsubpd, void, env, XMMReg, XMMReg)
+
+#define SSE_HELPER_CMP(name, F) \
+ DEF_HELPER_3(name ## ps, void, env, Reg, Reg) \
+ DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \
+ DEF_HELPER_3(name ## pd, void, env, Reg, Reg) \
+ DEF_HELPER_3(name ## sd, void, env, Reg, Reg)
SSE_HELPER_CMP(cmpeq, FPU_CMPEQ)
SSE_HELPER_CMP(cmplt, FPU_CMPLT)
@@ -216,124 +216,124 @@ SSE_HELPER_CMP(cmpnlt, FPU_CMPNLT)
SSE_HELPER_CMP(cmpnle, FPU_CMPNLE)
SSE_HELPER_CMP(cmpord, FPU_CMPORD)
-DEF_HELPER_2(ucomiss, void, Reg, Reg)
-DEF_HELPER_2(comiss, void, Reg, Reg)
-DEF_HELPER_2(ucomisd, void, Reg, Reg)
-DEF_HELPER_2(comisd, void, Reg, Reg)
-DEF_HELPER_1(movmskps, i32, Reg)
-DEF_HELPER_1(movmskpd, i32, Reg)
+DEF_HELPER_3(ucomiss, void, env, Reg, Reg)
+DEF_HELPER_3(comiss, void, env, Reg, Reg)
+DEF_HELPER_3(ucomisd, void, env, Reg, Reg)
+DEF_HELPER_3(comisd, void, env, Reg, Reg)
+DEF_HELPER_2(movmskps, i32, env, Reg)
+DEF_HELPER_2(movmskpd, i32, env, Reg)
#endif
-DEF_HELPER_1(glue(pmovmskb, SUFFIX), i32, Reg)
-DEF_HELPER_2(glue(packsswb, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(packuswb, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(packssdw, SUFFIX), void, Reg, Reg)
-#define UNPCK_OP(base_name, base) \
- DEF_HELPER_2(glue(punpck ## base_name ## bw, SUFFIX) , void, Reg, Reg) \
- DEF_HELPER_2(glue(punpck ## base_name ## wd, SUFFIX) , void, Reg, Reg) \
- DEF_HELPER_2(glue(punpck ## base_name ## dq, SUFFIX) , void, Reg, Reg)
+DEF_HELPER_2(glue(pmovmskb, SUFFIX), i32, env, Reg)
+DEF_HELPER_3(glue(packsswb, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(packuswb, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(packssdw, SUFFIX), void, env, Reg, Reg)
+#define UNPCK_OP(base_name, base) \
+ DEF_HELPER_3(glue(punpck ## base_name ## bw, SUFFIX), void, env, Reg, Reg) \
+ DEF_HELPER_3(glue(punpck ## base_name ## wd, SUFFIX), void, env, Reg, Reg) \
+ DEF_HELPER_3(glue(punpck ## base_name ## dq, SUFFIX), void, env, Reg, Reg)
UNPCK_OP(l, 0)
UNPCK_OP(h, 1)
#if SHIFT == 1
-DEF_HELPER_2(glue(punpcklqdq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(punpckhqdq, SUFFIX), void, Reg, Reg)
+DEF_HELPER_3(glue(punpcklqdq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(punpckhqdq, SUFFIX), void, env, Reg, Reg)
#endif
/* 3DNow! float ops */
#if SHIFT == 0
-DEF_HELPER_2(pi2fd, void, MMXReg, MMXReg)
-DEF_HELPER_2(pi2fw, void, MMXReg, MMXReg)
-DEF_HELPER_2(pf2id, void, MMXReg, MMXReg)
-DEF_HELPER_2(pf2iw, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfacc, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfadd, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfcmpeq, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfcmpge, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfcmpgt, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfmax, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfmin, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfmul, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfnacc, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfpnacc, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfrcp, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfrsqrt, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfsub, void, MMXReg, MMXReg)
-DEF_HELPER_2(pfsubr, void, MMXReg, MMXReg)
-DEF_HELPER_2(pswapd, void, MMXReg, MMXReg)
+DEF_HELPER_3(pi2fd, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pi2fw, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pf2id, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pf2iw, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfacc, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfadd, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfcmpeq, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfcmpge, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfcmpgt, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfmax, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfmin, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfmul, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfnacc, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfpnacc, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfrcp, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfrsqrt, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfsub, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pfsubr, void, env, MMXReg, MMXReg)
+DEF_HELPER_3(pswapd, void, env, MMXReg, MMXReg)
#endif
/* SSSE3 op helpers */
-DEF_HELPER_2(glue(phaddw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(phaddd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(phaddsw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(phsubw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(phsubd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(phsubsw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pabsb, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pabsw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pabsd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmaddubsw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmulhrsw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pshufb, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psignb, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psignw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(psignd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_3(glue(palignr, SUFFIX), void, Reg, Reg, s32)
+DEF_HELPER_3(glue(phaddw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(phaddd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(phaddsw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(phsubw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(phsubd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(phsubsw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pabsb, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pabsw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pabsd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmaddubsw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmulhrsw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pshufb, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psignb, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psignw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(psignd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_4(glue(palignr, SUFFIX), void, env, Reg, Reg, s32)
/* SSE4.1 op helpers */
#if SHIFT == 1
-DEF_HELPER_2(glue(pblendvb, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(blendvps, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(blendvpd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(ptest, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovsxbw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovsxbd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovsxbq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovsxwd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovsxwq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovsxdq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovzxbw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovzxbd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovzxbq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovzxwd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovzxwq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmovzxdq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmuldq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pcmpeqq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(packusdw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pminsb, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pminsd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pminuw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pminud, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmaxsb, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmaxsd, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmaxuw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmaxud, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(pmulld, SUFFIX), void, Reg, Reg)
-DEF_HELPER_2(glue(phminposuw, SUFFIX), void, Reg, Reg)
-DEF_HELPER_3(glue(roundps, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(roundpd, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(roundss, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(roundsd, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(blendps, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(blendpd, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(pblendw, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(dpps, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(dppd, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(mpsadbw, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(pblendvb, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(blendvps, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(blendvpd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(ptest, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovsxbw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovsxbd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovsxbq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovsxwd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovsxwq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovsxdq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovzxbw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovzxbd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovzxbq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovzxwd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovzxwq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmovzxdq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmuldq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pcmpeqq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(packusdw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pminsb, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pminsd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pminuw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pminud, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmaxsb, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmaxsd, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmaxuw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmaxud, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(pmulld, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_3(glue(phminposuw, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_4(glue(roundps, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(roundpd, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(roundss, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(roundsd, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(blendps, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(blendpd, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(pblendw, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(dpps, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(dppd, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(mpsadbw, SUFFIX), void, env, Reg, Reg, i32)
#endif
/* SSE4.2 op helpers */
#if SHIFT == 1
-DEF_HELPER_2(glue(pcmpgtq, SUFFIX), void, Reg, Reg)
-DEF_HELPER_3(glue(pcmpestri, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(pcmpestrm, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(pcmpistri, SUFFIX), void, Reg, Reg, i32)
-DEF_HELPER_3(glue(pcmpistrm, SUFFIX), void, Reg, Reg, i32)
+DEF_HELPER_3(glue(pcmpgtq, SUFFIX), void, env, Reg, Reg)
+DEF_HELPER_4(glue(pcmpestri, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(pcmpestrm, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(pcmpistri, SUFFIX), void, env, Reg, Reg, i32)
+DEF_HELPER_4(glue(pcmpistrm, SUFFIX), void, env, Reg, Reg, i32)
DEF_HELPER_3(crc32, tl, i32, tl, i32)
-DEF_HELPER_2(popcnt, tl, tl, i32)
+DEF_HELPER_3(popcnt, tl, env, tl, i32)
#endif
#undef SHIFT
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index a4b8b64..5fff8d5 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -19,16 +19,15 @@
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "qemu-log.h"
#include "helper.h"
+//#define DEBUG_PCALL
+
#if !defined(CONFIG_USER_ONLY)
#include "softmmu_exec.h"
#endif /* !defined(CONFIG_USER_ONLY) */
-//#define DEBUG_PCALL
-
#ifdef DEBUG_PCALL
# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
# define LOG_PCALL_STATE(env) \
@@ -39,8 +38,8 @@
#endif
/* return non zero if error */
-static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
- int selector)
+static inline int load_segment(CPUX86State *env, uint32_t *e1_ptr,
+ uint32_t *e2_ptr, int selector)
{
SegmentCache *dt;
int index;
@@ -56,8 +55,8 @@ static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
return -1;
}
ptr = dt->base + index;
- *e1_ptr = ldl_kernel(ptr);
- *e2_ptr = ldl_kernel(ptr + 4);
+ *e1_ptr = cpu_ldl_kernel(env, ptr);
+ *e2_ptr = cpu_ldl_kernel(env, ptr + 4);
return 0;
}
@@ -86,14 +85,14 @@ static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1,
}
/* init the segment cache in vm86 mode. */
-static inline void load_seg_vm(int seg, int selector)
+static inline void load_seg_vm(CPUX86State *env, int seg, int selector)
{
selector &= 0xffff;
cpu_x86_load_seg_cache(env, seg, selector,
(selector << 4), 0xffff, 0);
}
-static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
+static inline void get_ss_esp_from_tss(CPUX86State *env, uint32_t *ss_ptr,
uint32_t *esp_ptr, int dpl)
{
int type, index, shift;
@@ -125,22 +124,22 @@ static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
raise_exception_err(env, EXCP0A_TSS, env->tr.selector & 0xfffc);
}
if (shift == 0) {
- *esp_ptr = lduw_kernel(env->tr.base + index);
- *ss_ptr = lduw_kernel(env->tr.base + index + 2);
+ *esp_ptr = cpu_lduw_kernel(env, env->tr.base + index);
+ *ss_ptr = cpu_lduw_kernel(env, env->tr.base + index + 2);
} else {
- *esp_ptr = ldl_kernel(env->tr.base + index);
- *ss_ptr = lduw_kernel(env->tr.base + index + 4);
+ *esp_ptr = cpu_ldl_kernel(env, env->tr.base + index);
+ *ss_ptr = cpu_lduw_kernel(env, env->tr.base + index + 4);
}
}
/* XXX: merge with load_seg() */
-static void tss_load_seg(int seg_reg, int selector)
+static void tss_load_seg(CPUX86State *env, int seg_reg, int selector)
{
uint32_t e1, e2;
int rpl, dpl, cpl;
if ((selector & 0xfffc) != 0) {
- if (load_segment(&e1, &e2, selector) != 0) {
+ if (load_segment(env, &e1, &e2, selector) != 0) {
raise_exception_err(env, EXCP0A_TSS, selector & 0xfffc);
}
if (!(e2 & DESC_S_MASK)) {
@@ -199,7 +198,7 @@ static void tss_load_seg(int seg_reg, int selector)
#define SWITCH_TSS_CALL 2
/* XXX: restore CPU state in registers (PowerPC case) */
-static void switch_tss(int tss_selector,
+static void switch_tss(CPUX86State *env, int tss_selector,
uint32_t e1, uint32_t e2, int source,
uint32_t next_eip)
{
@@ -225,7 +224,7 @@ static void switch_tss(int tss_selector,
if (tss_selector & 4) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc);
}
- if (load_segment(&e1, &e2, tss_selector) != 0) {
+ if (load_segment(env, &e1, &e2, tss_selector) != 0) {
raise_exception_err(env, EXCP0D_GPF, tss_selector & 0xfffc);
}
if (e2 & DESC_S_MASK) {
@@ -262,29 +261,30 @@ static void switch_tss(int tss_selector,
/* read all the registers from the new TSS */
if (type & 8) {
/* 32 bit */
- new_cr3 = ldl_kernel(tss_base + 0x1c);
- new_eip = ldl_kernel(tss_base + 0x20);
- new_eflags = ldl_kernel(tss_base + 0x24);
+ new_cr3 = cpu_ldl_kernel(env, tss_base + 0x1c);
+ new_eip = cpu_ldl_kernel(env, tss_base + 0x20);
+ new_eflags = cpu_ldl_kernel(env, tss_base + 0x24);
for (i = 0; i < 8; i++) {
- new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
+ new_regs[i] = cpu_ldl_kernel(env, tss_base + (0x28 + i * 4));
}
for (i = 0; i < 6; i++) {
- new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
+ new_segs[i] = cpu_lduw_kernel(env, tss_base + (0x48 + i * 4));
}
- new_ldt = lduw_kernel(tss_base + 0x60);
- new_trap = ldl_kernel(tss_base + 0x64);
+ new_ldt = cpu_lduw_kernel(env, tss_base + 0x60);
+ new_trap = cpu_ldl_kernel(env, tss_base + 0x64);
} else {
/* 16 bit */
new_cr3 = 0;
- new_eip = lduw_kernel(tss_base + 0x0e);
- new_eflags = lduw_kernel(tss_base + 0x10);
+ new_eip = cpu_lduw_kernel(env, tss_base + 0x0e);
+ new_eflags = cpu_lduw_kernel(env, tss_base + 0x10);
for (i = 0; i < 8; i++) {
- new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
+ new_regs[i] = cpu_lduw_kernel(env, tss_base + (0x12 + i * 2)) |
+ 0xffff0000;
}
for (i = 0; i < 4; i++) {
- new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
+ new_segs[i] = cpu_lduw_kernel(env, tss_base + (0x22 + i * 4));
}
- new_ldt = lduw_kernel(tss_base + 0x2a);
+ new_ldt = cpu_lduw_kernel(env, tss_base + 0x2a);
new_segs[R_FS] = 0;
new_segs[R_GS] = 0;
new_trap = 0;
@@ -299,10 +299,10 @@ static void switch_tss(int tss_selector,
/* XXX: it can still fail in some cases, so a bigger hack is
necessary to valid the TLB after having done the accesses */
- v1 = ldub_kernel(env->tr.base);
- v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
- stb_kernel(env->tr.base, v1);
- stb_kernel(env->tr.base + old_tss_limit_max, v2);
+ v1 = cpu_ldub_kernel(env, env->tr.base);
+ v2 = cpu_ldub_kernel(env, env->tr.base + old_tss_limit_max);
+ cpu_stb_kernel(env, env->tr.base, v1);
+ cpu_stb_kernel(env, env->tr.base + old_tss_limit_max, v2);
/* clear busy bit (it is restartable) */
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
@@ -310,9 +310,9 @@ static void switch_tss(int tss_selector,
uint32_t e2;
ptr = env->gdt.base + (env->tr.selector & ~7);
- e2 = ldl_kernel(ptr + 4);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
e2 &= ~DESC_TSS_BUSY_MASK;
- stl_kernel(ptr + 4, e2);
+ cpu_stl_kernel(env, ptr + 4, e2);
}
old_eflags = cpu_compute_eflags(env);
if (source == SWITCH_TSS_IRET) {
@@ -322,33 +322,35 @@ static void switch_tss(int tss_selector,
/* save the current state in the old TSS */
if (type & 8) {
/* 32 bit */
- stl_kernel(env->tr.base + 0x20, next_eip);
- stl_kernel(env->tr.base + 0x24, old_eflags);
- stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
- stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
- stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
- stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
- stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
- stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
- stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
- stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
+ cpu_stl_kernel(env, env->tr.base + 0x20, next_eip);
+ cpu_stl_kernel(env, env->tr.base + 0x24, old_eflags);
+ cpu_stl_kernel(env, env->tr.base + (0x28 + 0 * 4), EAX);
+ cpu_stl_kernel(env, env->tr.base + (0x28 + 1 * 4), ECX);
+ cpu_stl_kernel(env, env->tr.base + (0x28 + 2 * 4), EDX);
+ cpu_stl_kernel(env, env->tr.base + (0x28 + 3 * 4), EBX);
+ cpu_stl_kernel(env, env->tr.base + (0x28 + 4 * 4), ESP);
+ cpu_stl_kernel(env, env->tr.base + (0x28 + 5 * 4), EBP);
+ cpu_stl_kernel(env, env->tr.base + (0x28 + 6 * 4), ESI);
+ cpu_stl_kernel(env, env->tr.base + (0x28 + 7 * 4), EDI);
for (i = 0; i < 6; i++) {
- stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
+ cpu_stw_kernel(env, env->tr.base + (0x48 + i * 4),
+ env->segs[i].selector);
}
} else {
/* 16 bit */
- stw_kernel(env->tr.base + 0x0e, next_eip);
- stw_kernel(env->tr.base + 0x10, old_eflags);
- stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
- stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
- stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
- stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
- stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
- stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
- stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
- stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
+ cpu_stw_kernel(env, env->tr.base + 0x0e, next_eip);
+ cpu_stw_kernel(env, env->tr.base + 0x10, old_eflags);
+ cpu_stw_kernel(env, env->tr.base + (0x12 + 0 * 2), EAX);
+ cpu_stw_kernel(env, env->tr.base + (0x12 + 1 * 2), ECX);
+ cpu_stw_kernel(env, env->tr.base + (0x12 + 2 * 2), EDX);
+ cpu_stw_kernel(env, env->tr.base + (0x12 + 3 * 2), EBX);
+ cpu_stw_kernel(env, env->tr.base + (0x12 + 4 * 2), ESP);
+ cpu_stw_kernel(env, env->tr.base + (0x12 + 5 * 2), EBP);
+ cpu_stw_kernel(env, env->tr.base + (0x12 + 6 * 2), ESI);
+ cpu_stw_kernel(env, env->tr.base + (0x12 + 7 * 2), EDI);
for (i = 0; i < 4; i++) {
- stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
+ cpu_stw_kernel(env, env->tr.base + (0x22 + i * 4),
+ env->segs[i].selector);
}
}
@@ -356,7 +358,7 @@ static void switch_tss(int tss_selector,
context */
if (source == SWITCH_TSS_CALL) {
- stw_kernel(tss_base, env->tr.selector);
+ cpu_stw_kernel(env, tss_base, env->tr.selector);
new_eflags |= NT_MASK;
}
@@ -366,9 +368,9 @@ static void switch_tss(int tss_selector,
uint32_t e2;
ptr = env->gdt.base + (tss_selector & ~7);
- e2 = ldl_kernel(ptr + 4);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
e2 |= DESC_TSS_BUSY_MASK;
- stl_kernel(ptr + 4, e2);
+ cpu_stl_kernel(env, ptr + 4, e2);
}
/* set the new CPU state */
@@ -404,7 +406,7 @@ static void switch_tss(int tss_selector,
EDI = new_regs[7];
if (new_eflags & VM_MASK) {
for (i = 0; i < 6; i++) {
- load_seg_vm(i, new_segs[i]);
+ load_seg_vm(env, i, new_segs[i]);
}
/* in vm86, CPL is always 3 */
cpu_x86_set_cpl(env, 3);
@@ -434,8 +436,8 @@ static void switch_tss(int tss_selector,
raise_exception_err(env, EXCP0A_TSS, new_ldt & 0xfffc);
}
ptr = dt->base + index;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
+ e1 = cpu_ldl_kernel(env, ptr);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) {
raise_exception_err(env, EXCP0A_TSS, new_ldt & 0xfffc);
}
@@ -447,12 +449,12 @@ static void switch_tss(int tss_selector,
/* load the segments */
if (!(new_eflags & VM_MASK)) {
- tss_load_seg(R_CS, new_segs[R_CS]);
- tss_load_seg(R_SS, new_segs[R_SS]);
- tss_load_seg(R_ES, new_segs[R_ES]);
- tss_load_seg(R_DS, new_segs[R_DS]);
- tss_load_seg(R_FS, new_segs[R_FS]);
- tss_load_seg(R_GS, new_segs[R_GS]);
+ tss_load_seg(env, R_CS, new_segs[R_CS]);
+ tss_load_seg(env, R_SS, new_segs[R_SS]);
+ tss_load_seg(env, R_ES, new_segs[R_ES]);
+ tss_load_seg(env, R_DS, new_segs[R_DS]);
+ tss_load_seg(env, R_FS, new_segs[R_FS]);
+ tss_load_seg(env, R_GS, new_segs[R_GS]);
}
/* check that EIP is in the CS segment limits */
@@ -521,33 +523,34 @@ static int exception_has_error_code(int intno)
#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
/* XXX: add a is_user flag to have proper security support */
-#define PUSHW(ssp, sp, sp_mask, val) \
- { \
- sp -= 2; \
- stw_kernel((ssp) + (sp & (sp_mask)), (val)); \
+#define PUSHW(ssp, sp, sp_mask, val) \
+ { \
+ sp -= 2; \
+ cpu_stw_kernel(env, (ssp) + (sp & (sp_mask)), (val)); \
}
#define PUSHL(ssp, sp, sp_mask, val) \
{ \
sp -= 4; \
- stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val)); \
+ cpu_stl_kernel(env, SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val)); \
}
-#define POPW(ssp, sp, sp_mask, val) \
- { \
- val = lduw_kernel((ssp) + (sp & (sp_mask))); \
- sp += 2; \
+#define POPW(ssp, sp, sp_mask, val) \
+ { \
+ val = cpu_lduw_kernel(env, (ssp) + (sp & (sp_mask))); \
+ sp += 2; \
}
-#define POPL(ssp, sp, sp_mask, val) \
- { \
- val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask)); \
- sp += 4; \
+#define POPL(ssp, sp, sp_mask, val) \
+ { \
+ val = (uint32_t)cpu_ldl_kernel(env, SEG_ADDL(ssp, sp, sp_mask)); \
+ sp += 4; \
}
/* protected mode interrupt */
-static void do_interrupt_protected(int intno, int is_int, int error_code,
- unsigned int next_eip, int is_hw)
+static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
+ int error_code, unsigned int next_eip,
+ int is_hw)
{
SegmentCache *dt;
target_ulong ptr, ssp;
@@ -571,8 +574,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
raise_exception_err(env, EXCP0D_GPF, intno * 8 + 2);
}
ptr = dt->base + intno * 8;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
+ e1 = cpu_ldl_kernel(env, ptr);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
/* check gate type */
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
switch (type) {
@@ -581,7 +584,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
if (!(e2 & DESC_P_MASK)) {
raise_exception_err(env, EXCP0B_NOSEG, intno * 8 + 2);
}
- switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
+ switch_tss(env, intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
if (has_error_code) {
int type;
uint32_t mask;
@@ -597,9 +600,9 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
esp = (ESP - (2 << shift)) & mask;
ssp = env->segs[R_SS].base + esp;
if (shift) {
- stl_kernel(ssp, error_code);
+ cpu_stl_kernel(env, ssp, error_code);
} else {
- stw_kernel(ssp, error_code);
+ cpu_stw_kernel(env, ssp, error_code);
}
SET_ESP(esp, mask);
}
@@ -628,7 +631,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
if ((selector & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, 0);
}
- if (load_segment(&e1, &e2, selector) != 0) {
+ if (load_segment(env, &e1, &e2, selector) != 0) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) {
@@ -643,14 +646,14 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
}
if (!(e2 & DESC_C_MASK) && dpl < cpl) {
/* to inner privilege */
- get_ss_esp_from_tss(&ss, &esp, dpl);
+ get_ss_esp_from_tss(env, &ss, &esp, dpl);
if ((ss & 0xfffc) == 0) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc);
}
if ((ss & 3) != dpl) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc);
}
- if (load_segment(&ss_e1, &ss_e2, ss) != 0) {
+ if (load_segment(env, &ss_e1, &ss_e2, ss) != 0) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc);
}
ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
@@ -765,16 +768,16 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
#define PUSHQ(sp, val) \
{ \
sp -= 8; \
- stq_kernel(sp, (val)); \
+ cpu_stq_kernel(env, sp, (val)); \
}
#define POPQ(sp, val) \
{ \
- val = ldq_kernel(sp); \
+ val = cpu_ldq_kernel(env, sp); \
sp += 8; \
}
-static inline target_ulong get_rsp_from_tss(int level)
+static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level)
{
int index;
@@ -790,12 +793,12 @@ static inline target_ulong get_rsp_from_tss(int level)
if ((index + 7) > env->tr.limit) {
raise_exception_err(env, EXCP0A_TSS, env->tr.selector & 0xfffc);
}
- return ldq_kernel(env->tr.base + index);
+ return cpu_ldq_kernel(env, env->tr.base + index);
}
/* 64 bit interrupt */
-static void do_interrupt64(int intno, int is_int, int error_code,
- target_ulong next_eip, int is_hw)
+static void do_interrupt64(CPUX86State *env, int intno, int is_int,
+ int error_code, target_ulong next_eip, int is_hw)
{
SegmentCache *dt;
target_ulong ptr;
@@ -819,9 +822,9 @@ static void do_interrupt64(int intno, int is_int, int error_code,
raise_exception_err(env, EXCP0D_GPF, intno * 16 + 2);
}
ptr = dt->base + intno * 16;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
- e3 = ldl_kernel(ptr + 8);
+ e1 = cpu_ldl_kernel(env, ptr);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
+ e3 = cpu_ldl_kernel(env, ptr + 8);
/* check gate type */
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
switch (type) {
@@ -849,7 +852,7 @@ static void do_interrupt64(int intno, int is_int, int error_code,
raise_exception_err(env, EXCP0D_GPF, 0);
}
- if (load_segment(&e1, &e2, selector) != 0) {
+ if (load_segment(env, &e1, &e2, selector) != 0) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) {
@@ -868,9 +871,9 @@ static void do_interrupt64(int intno, int is_int, int error_code,
if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
/* to inner privilege */
if (ist != 0) {
- esp = get_rsp_from_tss(ist + 3);
+ esp = get_rsp_from_tss(env, ist + 3);
} else {
- esp = get_rsp_from_tss(dpl);
+ esp = get_rsp_from_tss(env, dpl);
}
esp &= ~0xfLL; /* align stack */
ss = 0;
@@ -882,7 +885,7 @@ static void do_interrupt64(int intno, int is_int, int error_code,
}
new_stack = 0;
if (ist != 0) {
- esp = get_rsp_from_tss(ist + 3);
+ esp = get_rsp_from_tss(env, ist + 3);
} else {
esp = ESP;
}
@@ -927,14 +930,14 @@ static void do_interrupt64(int intno, int is_int, int error_code,
#ifdef TARGET_X86_64
#if defined(CONFIG_USER_ONLY)
-void helper_syscall(int next_eip_addend)
+void helper_syscall(CPUX86State *env, int next_eip_addend)
{
env->exception_index = EXCP_SYSCALL;
env->exception_next_eip = env->eip + next_eip_addend;
cpu_loop_exit(env);
}
#else
-void helper_syscall(int next_eip_addend)
+void helper_syscall(CPUX86State *env, int next_eip_addend)
{
int selector;
@@ -991,7 +994,7 @@ void helper_syscall(int next_eip_addend)
#endif
#ifdef TARGET_X86_64
-void helper_sysret(int dflag)
+void helper_sysret(CPUX86State *env, int dflag)
{
int cpl, selector;
@@ -1048,8 +1051,8 @@ void helper_sysret(int dflag)
#endif
/* real mode interrupt */
-static void do_interrupt_real(int intno, int is_int, int error_code,
- unsigned int next_eip)
+static void do_interrupt_real(CPUX86State *env, int intno, int is_int,
+ int error_code, unsigned int next_eip)
{
SegmentCache *dt;
target_ulong ptr, ssp;
@@ -1063,8 +1066,8 @@ static void do_interrupt_real(int intno, int is_int, int error_code,
raise_exception_err(env, EXCP0D_GPF, intno * 8 + 2);
}
ptr = dt->base + intno * 4;
- offset = lduw_kernel(ptr);
- selector = lduw_kernel(ptr + 2);
+ offset = cpu_lduw_kernel(env, ptr);
+ selector = cpu_lduw_kernel(env, ptr + 2);
esp = ESP;
ssp = env->segs[R_SS].base;
if (is_int) {
@@ -1088,8 +1091,8 @@ static void do_interrupt_real(int intno, int is_int, int error_code,
#if defined(CONFIG_USER_ONLY)
/* fake user mode interrupt */
-static void do_interrupt_user(int intno, int is_int, int error_code,
- target_ulong next_eip)
+static void do_interrupt_user(CPUX86State *env, int intno, int is_int,
+ int error_code, target_ulong next_eip)
{
SegmentCache *dt;
target_ulong ptr;
@@ -1103,7 +1106,7 @@ static void do_interrupt_user(int intno, int is_int, int error_code,
shift = 3;
}
ptr = dt->base + (intno << shift);
- e2 = ldl_kernel(ptr + 4);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
cpl = env->hflags & HF_CPL_MASK;
@@ -1122,8 +1125,8 @@ static void do_interrupt_user(int intno, int is_int, int error_code,
#else
-static void handle_even_inj(int intno, int is_int, int error_code,
- int is_hw, int rm)
+static void handle_even_inj(CPUX86State *env, int intno, int is_int,
+ int error_code, int is_hw, int rm)
{
uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
control.event_inj));
@@ -1154,8 +1157,8 @@ static void handle_even_inj(int intno, int is_int, int error_code,
* the int instruction. next_eip is the EIP value AFTER the interrupt
* instruction. It is only relevant if is_int is TRUE.
*/
-static void do_interrupt_all(int intno, int is_int, int error_code,
- target_ulong next_eip, int is_hw)
+static void do_interrupt_all(CPUX86State *env, int intno, int is_int,
+ int error_code, target_ulong next_eip, int is_hw)
{
if (qemu_loglevel_mask(CPU_LOG_INT)) {
if ((env->cr[0] & CR0_PE_MASK)) {
@@ -1194,24 +1197,25 @@ static void do_interrupt_all(int intno, int is_int, int error_code,
if (env->cr[0] & CR0_PE_MASK) {
#if !defined(CONFIG_USER_ONLY)
if (env->hflags & HF_SVMI_MASK) {
- handle_even_inj(intno, is_int, error_code, is_hw, 0);
+ handle_even_inj(env, intno, is_int, error_code, is_hw, 0);
}
#endif
#ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) {
- do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
+ do_interrupt64(env, intno, is_int, error_code, next_eip, is_hw);
} else
#endif
{
- do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
+ do_interrupt_protected(env, intno, is_int, error_code, next_eip,
+ is_hw);
}
} else {
#if !defined(CONFIG_USER_ONLY)
if (env->hflags & HF_SVMI_MASK) {
- handle_even_inj(intno, is_int, error_code, is_hw, 1);
+ handle_even_inj(env, intno, is_int, error_code, is_hw, 1);
}
#endif
- do_interrupt_real(intno, is_int, error_code, next_eip);
+ do_interrupt_real(env, intno, is_int, error_code, next_eip);
}
#if !defined(CONFIG_USER_ONLY)
@@ -1226,17 +1230,13 @@ static void do_interrupt_all(int intno, int is_int, int error_code,
#endif
}
-void do_interrupt(CPUX86State *env1)
+void do_interrupt(CPUX86State *env)
{
- CPUX86State *saved_env;
-
- saved_env = env;
- env = env1;
#if defined(CONFIG_USER_ONLY)
/* if user mode only, we simulate a fake exception
which will be handled outside the cpu execution
loop */
- do_interrupt_user(env->exception_index,
+ do_interrupt_user(env, env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
@@ -1246,27 +1246,22 @@ void do_interrupt(CPUX86State *env1)
/* simulate a real cpu exception. On i386, it can
trigger new exceptions, but we do not handle
double or triple faults yet. */
- do_interrupt_all(env->exception_index,
+ do_interrupt_all(env, env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip, 0);
/* successfully delivered */
env->old_exception = -1;
#endif
- env = saved_env;
}
-void do_interrupt_x86_hardirq(CPUX86State *env1, int intno, int is_hw)
+void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw)
{
- CPUX86State *saved_env;
-
- saved_env = env;
- env = env1;
- do_interrupt_all(intno, 0, 0, 0, is_hw);
- env = saved_env;
+ do_interrupt_all(env, intno, 0, 0, 0, is_hw);
}
-void helper_enter_level(int level, int data32, target_ulong t1)
+void helper_enter_level(CPUX86State *env, int level, int data32,
+ target_ulong t1)
{
target_ulong ssp;
uint32_t esp_mask, esp, ebp;
@@ -1281,25 +1276,28 @@ void helper_enter_level(int level, int data32, target_ulong t1)
while (--level) {
esp -= 4;
ebp -= 4;
- stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
+ cpu_stl_data(env, ssp + (esp & esp_mask),
+ cpu_ldl_data(env, ssp + (ebp & esp_mask)));
}
esp -= 4;
- stl(ssp + (esp & esp_mask), t1);
+ cpu_stl_data(env, ssp + (esp & esp_mask), t1);
} else {
/* 16 bit */
esp -= 2;
while (--level) {
esp -= 2;
ebp -= 2;
- stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
+ cpu_stw_data(env, ssp + (esp & esp_mask),
+ cpu_lduw_data(env, ssp + (ebp & esp_mask)));
}
esp -= 2;
- stw(ssp + (esp & esp_mask), t1);
+ cpu_stw_data(env, ssp + (esp & esp_mask), t1);
}
}
#ifdef TARGET_X86_64
-void helper_enter64_level(int level, int data64, target_ulong t1)
+void helper_enter64_level(CPUX86State *env, int level, int data64,
+ target_ulong t1)
{
target_ulong esp, ebp;
@@ -1312,25 +1310,25 @@ void helper_enter64_level(int level, int data64, target_ulong t1)
while (--level) {
esp -= 8;
ebp -= 8;
- stq(esp, ldq(ebp));
+ cpu_stq_data(env, esp, cpu_ldq_data(env, ebp));
}
esp -= 8;
- stq(esp, t1);
+ cpu_stq_data(env, esp, t1);
} else {
/* 16 bit */
esp -= 2;
while (--level) {
esp -= 2;
ebp -= 2;
- stw(esp, lduw(ebp));
+ cpu_stw_data(env, esp, cpu_lduw_data(env, ebp));
}
esp -= 2;
- stw(esp, t1);
+ cpu_stw_data(env, esp, t1);
}
}
#endif
-void helper_lldt(int selector)
+void helper_lldt(CPUX86State *env, int selector)
{
SegmentCache *dt;
uint32_t e1, e2;
@@ -1360,8 +1358,8 @@ void helper_lldt(int selector)
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
ptr = dt->base + index;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
+ e1 = cpu_ldl_kernel(env, ptr);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
@@ -1372,7 +1370,7 @@ void helper_lldt(int selector)
if (env->hflags & HF_LMA_MASK) {
uint32_t e3;
- e3 = ldl_kernel(ptr + 8);
+ e3 = cpu_ldl_kernel(env, ptr + 8);
load_seg_cache_raw_dt(&env->ldt, e1, e2);
env->ldt.base |= (target_ulong)e3 << 32;
} else
@@ -1384,7 +1382,7 @@ void helper_lldt(int selector)
env->ldt.selector = selector;
}
-void helper_ltr(int selector)
+void helper_ltr(CPUX86State *env, int selector)
{
SegmentCache *dt;
uint32_t e1, e2;
@@ -1415,8 +1413,8 @@ void helper_ltr(int selector)
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
ptr = dt->base + index;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
+ e1 = cpu_ldl_kernel(env, ptr);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
if ((e2 & DESC_S_MASK) ||
(type != 1 && type != 9)) {
@@ -1429,8 +1427,8 @@ void helper_ltr(int selector)
if (env->hflags & HF_LMA_MASK) {
uint32_t e3, e4;
- e3 = ldl_kernel(ptr + 8);
- e4 = ldl_kernel(ptr + 12);
+ e3 = cpu_ldl_kernel(env, ptr + 8);
+ e4 = cpu_ldl_kernel(env, ptr + 12);
if ((e4 >> DESC_TYPE_SHIFT) & 0xf) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
@@ -1442,13 +1440,13 @@ void helper_ltr(int selector)
load_seg_cache_raw_dt(&env->tr, e1, e2);
}
e2 |= DESC_TSS_BUSY_MASK;
- stl_kernel(ptr + 4, e2);
+ cpu_stl_kernel(env, ptr + 4, e2);
}
env->tr.selector = selector;
}
/* only works if protected mode and not VM86. seg_reg must be != R_CS */
-void helper_load_seg(int seg_reg, int selector)
+void helper_load_seg(CPUX86State *env, int seg_reg, int selector)
{
uint32_t e1, e2;
int cpl, dpl, rpl;
@@ -1480,8 +1478,8 @@ void helper_load_seg(int seg_reg, int selector)
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
ptr = dt->base + index;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
+ e1 = cpu_ldl_kernel(env, ptr);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
if (!(e2 & DESC_S_MASK)) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
@@ -1521,7 +1519,7 @@ void helper_load_seg(int seg_reg, int selector)
/* set the access bit if not already set */
if (!(e2 & DESC_A_MASK)) {
e2 |= DESC_A_MASK;
- stl_kernel(ptr + 4, e2);
+ cpu_stl_kernel(env, ptr + 4, e2);
}
cpu_x86_load_seg_cache(env, seg_reg, selector,
@@ -1536,7 +1534,7 @@ void helper_load_seg(int seg_reg, int selector)
}
/* protected mode jump */
-void helper_ljmp_protected(int new_cs, target_ulong new_eip,
+void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
int next_eip_addend)
{
int gate_cs, type;
@@ -1546,7 +1544,7 @@ void helper_ljmp_protected(int new_cs, target_ulong new_eip,
if ((new_cs & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, 0);
}
- if (load_segment(&e1, &e2, new_cs) != 0) {
+ if (load_segment(env, &e1, &e2, new_cs) != 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc);
}
cpl = env->hflags & HF_CPL_MASK;
@@ -1595,7 +1593,7 @@ void helper_ljmp_protected(int new_cs, target_ulong new_eip,
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc);
}
next_eip = env->eip + next_eip_addend;
- switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
+ switch_tss(env, new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
CC_OP = CC_OP_EFLAGS;
break;
case 4: /* 286 call gate */
@@ -1611,7 +1609,7 @@ void helper_ljmp_protected(int new_cs, target_ulong new_eip,
if (type == 12) {
new_eip |= (e2 & 0xffff0000);
}
- if (load_segment(&e1, &e2, gate_cs) != 0) {
+ if (load_segment(env, &e1, &e2, gate_cs) != 0) {
raise_exception_err(env, EXCP0D_GPF, gate_cs & 0xfffc);
}
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
@@ -1643,7 +1641,7 @@ void helper_ljmp_protected(int new_cs, target_ulong new_eip,
}
/* real mode call */
-void helper_lcall_real(int new_cs, target_ulong new_eip1,
+void helper_lcall_real(CPUX86State *env, int new_cs, target_ulong new_eip1,
int shift, int next_eip)
{
int new_eip;
@@ -1669,7 +1667,7 @@ void helper_lcall_real(int new_cs, target_ulong new_eip1,
}
/* protected mode call */
-void helper_lcall_protected(int new_cs, target_ulong new_eip,
+void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
int shift, int next_eip_addend)
{
int new_stack, i;
@@ -1684,7 +1682,7 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
if ((new_cs & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, 0);
}
- if (load_segment(&e1, &e2, new_cs) != 0) {
+ if (load_segment(env, &e1, &e2, new_cs) != 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc);
}
cpl = env->hflags & HF_CPL_MASK;
@@ -1764,7 +1762,7 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
if (dpl < cpl || dpl < rpl) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc);
}
- switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
+ switch_tss(env, new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
CC_OP = CC_OP_EFLAGS;
return;
case 4: /* 286 call gate */
@@ -1790,7 +1788,7 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
raise_exception_err(env, EXCP0D_GPF, 0);
}
- if (load_segment(&e1, &e2, selector) != 0) {
+ if (load_segment(env, &e1, &e2, selector) != 0) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
}
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) {
@@ -1806,7 +1804,7 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
if (!(e2 & DESC_C_MASK) && dpl < cpl) {
/* to inner privilege */
- get_ss_esp_from_tss(&ss, &sp, dpl);
+ get_ss_esp_from_tss(env, &ss, &sp, dpl);
LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx
"\n",
ss, sp, param_count, ESP);
@@ -1816,7 +1814,7 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
if ((ss & 3) != dpl) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc);
}
- if (load_segment(&ss_e1, &ss_e2, ss) != 0) {
+ if (load_segment(env, &ss_e1, &ss_e2, ss) != 0) {
raise_exception_err(env, EXCP0A_TSS, ss & 0xfffc);
}
ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
@@ -1843,14 +1841,16 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
PUSHL(ssp, sp, sp_mask, ESP);
for (i = param_count - 1; i >= 0; i--) {
- val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
+ val = cpu_ldl_kernel(env, old_ssp + ((ESP + i * 4) &
+ old_sp_mask));
PUSHL(ssp, sp, sp_mask, val);
}
} else {
PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
PUSHW(ssp, sp, sp_mask, ESP);
for (i = param_count - 1; i >= 0; i--) {
- val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
+ val = cpu_lduw_kernel(env, old_ssp + ((ESP + i * 2) &
+ old_sp_mask));
PUSHW(ssp, sp, sp_mask, val);
}
}
@@ -1894,7 +1894,7 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
}
/* real and vm86 mode iret */
-void helper_iret_real(int shift)
+void helper_iret_real(CPUX86State *env, int shift)
{
uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
target_ulong ssp;
@@ -1933,7 +1933,7 @@ void helper_iret_real(int shift)
env->hflags2 &= ~HF2_NMI_MASK;
}
-static inline void validate_seg(int seg_reg, int cpl)
+static inline void validate_seg(CPUX86State *env, int seg_reg, int cpl)
{
int dpl;
uint32_t e2;
@@ -1957,7 +1957,8 @@ static inline void validate_seg(int seg_reg, int cpl)
}
/* protected mode iret */
-static inline void helper_ret_protected(int shift, int is_iret, int addend)
+static inline void helper_ret_protected(CPUX86State *env, int shift,
+ int is_iret, int addend)
{
uint32_t new_cs, new_eflags, new_ss;
uint32_t new_es, new_ds, new_fs, new_gs;
@@ -2013,7 +2014,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
if ((new_cs & 0xfffc) == 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc);
}
- if (load_segment(&e1, &e2, new_cs) != 0) {
+ if (load_segment(env, &e1, &e2, new_cs) != 0) {
raise_exception_err(env, EXCP0D_GPF, new_cs & 0xfffc);
}
if (!(e2 & DESC_S_MASK) ||
@@ -2090,7 +2091,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
if ((new_ss & 3) != rpl) {
raise_exception_err(env, EXCP0D_GPF, new_ss & 0xfffc);
}
- if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) {
+ if (load_segment(env, &ss_e1, &ss_e2, new_ss) != 0) {
raise_exception_err(env, EXCP0D_GPF, new_ss & 0xfffc);
}
if (!(ss_e2 & DESC_S_MASK) ||
@@ -2127,10 +2128,10 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
}
/* validate data segments */
- validate_seg(R_ES, rpl);
- validate_seg(R_DS, rpl);
- validate_seg(R_FS, rpl);
- validate_seg(R_GS, rpl);
+ validate_seg(env, R_ES, rpl);
+ validate_seg(env, R_DS, rpl);
+ validate_seg(env, R_FS, rpl);
+ validate_seg(env, R_GS, rpl);
sp += addend;
}
@@ -2165,19 +2166,19 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
cpu_load_eflags(env, new_eflags, TF_MASK | AC_MASK | ID_MASK |
IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK |
VIP_MASK);
- load_seg_vm(R_CS, new_cs & 0xffff);
+ load_seg_vm(env, R_CS, new_cs & 0xffff);
cpu_x86_set_cpl(env, 3);
- load_seg_vm(R_SS, new_ss & 0xffff);
- load_seg_vm(R_ES, new_es & 0xffff);
- load_seg_vm(R_DS, new_ds & 0xffff);
- load_seg_vm(R_FS, new_fs & 0xffff);
- load_seg_vm(R_GS, new_gs & 0xffff);
+ load_seg_vm(env, R_SS, new_ss & 0xffff);
+ load_seg_vm(env, R_ES, new_es & 0xffff);
+ load_seg_vm(env, R_DS, new_ds & 0xffff);
+ load_seg_vm(env, R_FS, new_fs & 0xffff);
+ load_seg_vm(env, R_GS, new_gs & 0xffff);
env->eip = new_eip & 0xffff;
ESP = new_esp;
}
-void helper_iret_protected(int shift, int next_eip)
+void helper_iret_protected(CPUX86State *env, int shift, int next_eip)
{
int tss_selector, type;
uint32_t e1, e2;
@@ -2189,11 +2190,11 @@ void helper_iret_protected(int shift, int next_eip)
raise_exception_err(env, EXCP0D_GPF, 0);
}
#endif
- tss_selector = lduw_kernel(env->tr.base + 0);
+ tss_selector = cpu_lduw_kernel(env, env->tr.base + 0);
if (tss_selector & 4) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc);
}
- if (load_segment(&e1, &e2, tss_selector) != 0) {
+ if (load_segment(env, &e1, &e2, tss_selector) != 0) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc);
}
type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
@@ -2201,19 +2202,19 @@ void helper_iret_protected(int shift, int next_eip)
if (type != 3) {
raise_exception_err(env, EXCP0A_TSS, tss_selector & 0xfffc);
}
- switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
+ switch_tss(env, tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
} else {
- helper_ret_protected(shift, 1, 0);
+ helper_ret_protected(env, shift, 1, 0);
}
env->hflags2 &= ~HF2_NMI_MASK;
}
-void helper_lret_protected(int shift, int addend)
+void helper_lret_protected(CPUX86State *env, int shift, int addend)
{
- helper_ret_protected(shift, 0, addend);
+ helper_ret_protected(env, shift, 0, addend);
}
-void helper_sysenter(void)
+void helper_sysenter(CPUX86State *env)
{
if (env->sysenter_cs == 0) {
raise_exception_err(env, EXCP0D_GPF, 0);
@@ -2247,7 +2248,7 @@ void helper_sysenter(void)
EIP = env->sysenter_eip;
}
-void helper_sysexit(int dflag)
+void helper_sysexit(CPUX86State *env, int dflag)
{
int cpl;
@@ -2287,18 +2288,18 @@ void helper_sysexit(int dflag)
EIP = EDX;
}
-target_ulong helper_lsl(target_ulong selector1)
+target_ulong helper_lsl(CPUX86State *env, target_ulong selector1)
{
unsigned int limit;
uint32_t e1, e2, eflags, selector;
int rpl, dpl, cpl, type;
selector = selector1 & 0xffff;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
if ((selector & 0xfffc) == 0) {
goto fail;
}
- if (load_segment(&e1, &e2, selector) != 0) {
+ if (load_segment(env, &e1, &e2, selector) != 0) {
goto fail;
}
rpl = selector & 3;
@@ -2335,17 +2336,17 @@ target_ulong helper_lsl(target_ulong selector1)
return limit;
}
-target_ulong helper_lar(target_ulong selector1)
+target_ulong helper_lar(CPUX86State *env, target_ulong selector1)
{
uint32_t e1, e2, eflags, selector;
int rpl, dpl, cpl, type;
selector = selector1 & 0xffff;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
if ((selector & 0xfffc) == 0) {
goto fail;
}
- if (load_segment(&e1, &e2, selector) != 0) {
+ if (load_segment(env, &e1, &e2, selector) != 0) {
goto fail;
}
rpl = selector & 3;
@@ -2384,17 +2385,17 @@ target_ulong helper_lar(target_ulong selector1)
return e2 & 0x00f0ff00;
}
-void helper_verr(target_ulong selector1)
+void helper_verr(CPUX86State *env, target_ulong selector1)
{
uint32_t e1, e2, eflags, selector;
int rpl, dpl, cpl;
selector = selector1 & 0xffff;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
if ((selector & 0xfffc) == 0) {
goto fail;
}
- if (load_segment(&e1, &e2, selector) != 0) {
+ if (load_segment(env, &e1, &e2, selector) != 0) {
goto fail;
}
if (!(e2 & DESC_S_MASK)) {
@@ -2422,17 +2423,17 @@ void helper_verr(target_ulong selector1)
CC_SRC = eflags | CC_Z;
}
-void helper_verw(target_ulong selector1)
+void helper_verw(CPUX86State *env, target_ulong selector1)
{
uint32_t e1, e2, eflags, selector;
int rpl, dpl, cpl;
selector = selector1 & 0xffff;
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = cpu_cc_compute_all(env, CC_OP);
if ((selector & 0xfffc) == 0) {
goto fail;
}
- if (load_segment(&e1, &e2, selector) != 0) {
+ if (load_segment(env, &e1, &e2, selector) != 0) {
goto fail;
}
if (!(e2 & DESC_S_MASK)) {
@@ -2457,19 +2458,14 @@ void helper_verw(target_ulong selector1)
}
#if defined(CONFIG_USER_ONLY)
-void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
+void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector)
{
- CPUX86State *saved_env;
-
- saved_env = env;
- env = s;
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
selector &= 0xffff;
cpu_x86_load_seg_cache(env, seg_reg, selector,
(selector << 4), 0xffff, 0);
} else {
- helper_load_seg(seg_reg, selector);
+ helper_load_seg(env, seg_reg, selector);
}
- env = saved_env;
}
#endif
diff --git a/target-i386/shift_helper_template.h b/target-i386/shift_helper_template.h
index 239ee09..dda0da3 100644
--- a/target-i386/shift_helper_template.h
+++ b/target-i386/shift_helper_template.h
@@ -41,7 +41,8 @@
#error unhandled operand size
#endif
-target_ulong glue(helper_rcl, SUFFIX)(target_ulong t0, target_ulong t1)
+target_ulong glue(helper_rcl, SUFFIX)(CPUX86State *env, target_ulong t0,
+ target_ulong t1)
{
int count, eflags;
target_ulong src;
@@ -54,7 +55,7 @@ target_ulong glue(helper_rcl, SUFFIX)(target_ulong t0, target_ulong t1)
count = rclb_table[count];
#endif
if (count) {
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = helper_cc_compute_all(env, CC_OP);
t0 &= DATA_MASK;
src = t0;
res = (t0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1));
@@ -71,7 +72,8 @@ target_ulong glue(helper_rcl, SUFFIX)(target_ulong t0, target_ulong t1)
return t0;
}
-target_ulong glue(helper_rcr, SUFFIX)(target_ulong t0, target_ulong t1)
+target_ulong glue(helper_rcr, SUFFIX)(CPUX86State *env, target_ulong t0,
+ target_ulong t1)
{
int count, eflags;
target_ulong src;
@@ -84,7 +86,7 @@ target_ulong glue(helper_rcr, SUFFIX)(target_ulong t0, target_ulong t1)
count = rclb_table[count];
#endif
if (count) {
- eflags = helper_cc_compute_all(CC_OP);
+ eflags = helper_cc_compute_all(env, CC_OP);
t0 &= DATA_MASK;
src = t0;
res = (t0 >> count) |
diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c
index bc1bfa2..8b04eb2 100644
--- a/target-i386/smm_helper.c
+++ b/target-i386/smm_helper.c
@@ -18,18 +18,17 @@
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
/* SMM support */
#if defined(CONFIG_USER_ONLY)
-void do_smm_enter(CPUX86State *env1)
+void do_smm_enter(CPUX86State *env)
{
}
-void helper_rsm(void)
+void helper_rsm(CPUX86State *env)
{
}
@@ -41,15 +40,11 @@ void helper_rsm(void)
#define SMM_REVISION_ID 0x00020000
#endif
-void do_smm_enter(CPUX86State *env1)
+void do_smm_enter(CPUX86State *env)
{
target_ulong sm_state;
SegmentCache *dt;
int i, offset;
- CPUX86State *saved_env;
-
- saved_env = env;
- env = env1;
qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
@@ -180,10 +175,9 @@ void do_smm_enter(CPUX86State *env1)
cpu_x86_update_cr4(env, 0);
env->dr[7] = 0x00000400;
CC_OP = CC_OP_EFLAGS;
- env = saved_env;
}
-void helper_rsm(void)
+void helper_rsm(CPUX86State *env)
{
target_ulong sm_state;
int i, offset;
diff --git a/target-i386/svm_helper.c b/target-i386/svm_helper.c
index 64d842c..4943c37 100644
--- a/target-i386/svm_helper.c
+++ b/target-i386/svm_helper.c
@@ -18,46 +18,50 @@
*/
#include "cpu.h"
-#include "dyngen-exec.h"
+#include "cpu-all.h"
#include "helper.h"
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
/* Secure Virtual Machine helpers */
#if defined(CONFIG_USER_ONLY)
-void helper_vmrun(int aflag, int next_eip_addend)
+void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
{
}
-void helper_vmmcall(void)
+void helper_vmmcall(CPUX86State *env)
{
}
-void helper_vmload(int aflag)
+void helper_vmload(CPUX86State *env, int aflag)
{
}
-void helper_vmsave(int aflag)
+void helper_vmsave(CPUX86State *env, int aflag)
{
}
-void helper_stgi(void)
+void helper_stgi(CPUX86State *env)
{
}
-void helper_clgi(void)
+void helper_clgi(CPUX86State *env)
{
}
-void helper_skinit(void)
+void helper_skinit(CPUX86State *env)
{
}
-void helper_invlpga(int aflag)
+void helper_invlpga(CPUX86State *env, int aflag)
{
}
-void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
+void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
{
}
@@ -65,7 +69,8 @@ void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1)
{
}
-void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
+void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
+ uint64_t param)
{
}
@@ -74,13 +79,13 @@ void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
{
}
-void helper_svm_check_io(uint32_t port, uint32_t param,
+void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
uint32_t next_eip_addend)
{
}
#else
-static inline void svm_save_seg(target_phys_addr_t addr,
+static inline void svm_save_seg(CPUX86State *env, target_phys_addr_t addr,
const SegmentCache *sc)
{
stw_phys(addr + offsetof(struct vmcb_seg, selector),
@@ -93,7 +98,8 @@ static inline void svm_save_seg(target_phys_addr_t addr,
((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
}
-static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
+static inline void svm_load_seg(CPUX86State *env, target_phys_addr_t addr,
+ SegmentCache *sc)
{
unsigned int flags;
@@ -104,23 +110,23 @@ static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
}
-static inline void svm_load_seg_cache(target_phys_addr_t addr,
- CPUX86State *env, int seg_reg)
+static inline void svm_load_seg_cache(CPUX86State *env, target_phys_addr_t addr,
+ int seg_reg)
{
SegmentCache sc1, *sc = &sc1;
- svm_load_seg(addr, sc);
+ svm_load_seg(env, addr, sc);
cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
sc->base, sc->limit, sc->flags);
}
-void helper_vmrun(int aflag, int next_eip_addend)
+void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
{
target_ulong addr;
uint32_t event_inj;
uint32_t int_ctl;
- helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
+ cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0);
if (aflag == 2) {
addr = EAX;
@@ -154,13 +160,13 @@ void helper_vmrun(int aflag, int next_eip_addend)
stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags),
cpu_compute_eflags(env));
- svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.es),
+ svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es),
&env->segs[R_ES]);
- svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.cs),
+ svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
&env->segs[R_CS]);
- svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ss),
+ svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
&env->segs[R_SS]);
- svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds),
+ svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
&env->segs[R_DS]);
stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
@@ -233,14 +239,14 @@ void helper_vmrun(int aflag, int next_eip_addend)
~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
CC_OP = CC_OP_EFLAGS;
- svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.es),
- env, R_ES);
- svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.cs),
- env, R_CS);
- svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ss),
- env, R_SS);
- svm_load_seg_cache(env->vm_vmcb + offsetof(struct vmcb, save.ds),
- env, R_DS);
+ svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
+ R_ES);
+ svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
+ R_CS);
+ svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
+ R_SS);
+ svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
+ R_DS);
EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
env->eip = EIP;
@@ -320,17 +326,17 @@ void helper_vmrun(int aflag, int next_eip_addend)
}
}
-void helper_vmmcall(void)
+void helper_vmmcall(CPUX86State *env)
{
- helper_svm_check_intercept_param(SVM_EXIT_VMMCALL, 0);
+ cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0);
raise_exception(env, EXCP06_ILLOP);
}
-void helper_vmload(int aflag)
+void helper_vmload(CPUX86State *env, int aflag)
{
target_ulong addr;
- helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
+ cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
if (aflag == 2) {
addr = EAX;
@@ -340,17 +346,14 @@ void helper_vmload(int aflag)
qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx
"\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
- addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
+ addr, ldq_phys(addr + offsetof(struct vmcb,
+ save.fs.base)),
env->segs[R_FS].base);
- svm_load_seg_cache(addr + offsetof(struct vmcb, save.fs),
- env, R_FS);
- svm_load_seg_cache(addr + offsetof(struct vmcb, save.gs),
- env, R_GS);
- svm_load_seg(addr + offsetof(struct vmcb, save.tr),
- &env->tr);
- svm_load_seg(addr + offsetof(struct vmcb, save.ldtr),
- &env->ldt);
+ svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS);
+ svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS);
+ svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr);
+ svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
#ifdef TARGET_X86_64
env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb,
@@ -367,11 +370,11 @@ void helper_vmload(int aflag)
save.sysenter_eip));
}
-void helper_vmsave(int aflag)
+void helper_vmsave(CPUX86State *env, int aflag)
{
target_ulong addr;
- helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
+ cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
if (aflag == 2) {
addr = EAX;
@@ -384,13 +387,13 @@ void helper_vmsave(int aflag)
addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
env->segs[R_FS].base);
- svm_save_seg(addr + offsetof(struct vmcb, save.fs),
+ svm_save_seg(env, addr + offsetof(struct vmcb, save.fs),
&env->segs[R_FS]);
- svm_save_seg(addr + offsetof(struct vmcb, save.gs),
+ svm_save_seg(env, addr + offsetof(struct vmcb, save.gs),
&env->segs[R_GS]);
- svm_save_seg(addr + offsetof(struct vmcb, save.tr),
+ svm_save_seg(env, addr + offsetof(struct vmcb, save.tr),
&env->tr);
- svm_save_seg(addr + offsetof(struct vmcb, save.ldtr),
+ svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr),
&env->ldt);
#ifdef TARGET_X86_64
@@ -408,30 +411,30 @@ void helper_vmsave(int aflag)
env->sysenter_eip);
}
-void helper_stgi(void)
+void helper_stgi(CPUX86State *env)
{
- helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
+ cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0);
env->hflags2 |= HF2_GIF_MASK;
}
-void helper_clgi(void)
+void helper_clgi(CPUX86State *env)
{
- helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
+ cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0);
env->hflags2 &= ~HF2_GIF_MASK;
}
-void helper_skinit(void)
+void helper_skinit(CPUX86State *env)
{
- helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
+ cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0);
/* XXX: not implemented */
raise_exception(env, EXCP06_ILLOP);
}
-void helper_invlpga(int aflag)
+void helper_invlpga(CPUX86State *env, int aflag)
{
target_ulong addr;
- helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
+ cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
if (aflag == 2) {
addr = EAX;
@@ -444,7 +447,8 @@ void helper_invlpga(int aflag)
tlb_flush_page(env, addr);
}
-void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
+void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
+ uint64_t param)
{
if (likely(!(env->hflags & HF_SVMI_MASK))) {
return;
@@ -452,27 +456,27 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
switch (type) {
case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
- helper_vmexit(type, param);
+ helper_vmexit(env, type, param);
}
break;
case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
- helper_vmexit(type, param);
+ helper_vmexit(env, type, param);
}
break;
case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
- helper_vmexit(type, param);
+ helper_vmexit(env, type, param);
}
break;
case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
- helper_vmexit(type, param);
+ helper_vmexit(env, type, param);
}
break;
case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
- helper_vmexit(type, param);
+ helper_vmexit(env, type, param);
}
break;
case SVM_EXIT_MSR:
@@ -499,36 +503,31 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
t0 %= 8;
break;
default:
- helper_vmexit(type, param);
+ helper_vmexit(env, type, param);
t0 = 0;
t1 = 0;
break;
}
if (ldub_phys(addr + t1) & ((1 << param) << t0)) {
- helper_vmexit(type, param);
+ helper_vmexit(env, type, param);
}
}
break;
default:
if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
- helper_vmexit(type, param);
+ helper_vmexit(env, type, param);
}
break;
}
}
-void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
+void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
uint64_t param)
{
- CPUX86State *saved_env;
-
- saved_env = env;
- env = env1;
- helper_svm_check_intercept_param(type, param);
- env = saved_env;
+ helper_svm_check_intercept_param(env, type, param);
}
-void helper_svm_check_io(uint32_t port, uint32_t param,
+void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
uint32_t next_eip_addend)
{
if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
@@ -541,13 +540,13 @@ void helper_svm_check_io(uint32_t port, uint32_t param,
/* next EIP */
stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
env->eip + next_eip_addend);
- helper_vmexit(SVM_EXIT_IOIO, param | (port << 16));
+ helper_vmexit(env, SVM_EXIT_IOIO, param | (port << 16));
}
}
}
/* Note: currently only 32 bits of exit_code are used */
-void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
+void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
{
uint32_t int_ctl;
@@ -567,13 +566,13 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
}
/* Save the VM state in the vmcb */
- svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.es),
+ svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
&env->segs[R_ES]);
- svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.cs),
+ svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
&env->segs[R_CS]);
- svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ss),
+ svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
&env->segs[R_SS]);
- svm_save_seg(env->vm_vmcb + offsetof(struct vmcb, save.ds),
+ svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
&env->segs[R_DS]);
stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
@@ -602,7 +601,8 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags),
cpu_compute_eflags(env));
- stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
+ stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip),
+ env->eip);
stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
@@ -645,14 +645,14 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
CC_OP = CC_OP_EFLAGS;
- svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.es),
- env, R_ES);
- svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.cs),
- env, R_CS);
- svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ss),
- env, R_SS);
- svm_load_seg_cache(env->vm_hsave + offsetof(struct vmcb, save.ds),
- env, R_DS);
+ svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es),
+ R_ES);
+ svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
+ R_CS);
+ svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
+ R_SS);
+ svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
+ R_DS);
EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
@@ -707,10 +707,9 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
cpu_loop_exit(env);
}
-void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1)
+void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
{
- env = nenv;
- helper_vmexit(exit_code, exit_info_1);
+ helper_vmexit(env, exit_code, exit_info_1);
}
#endif
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 2b11333..eb0cabc 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -740,9 +740,15 @@ static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip,
state_saved = 1;
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
switch (ot) {
- case 0: gen_helper_check_iob(cpu_tmp2_i32); break;
- case 1: gen_helper_check_iow(cpu_tmp2_i32); break;
- case 2: gen_helper_check_iol(cpu_tmp2_i32); break;
+ case 0:
+ gen_helper_check_iob(cpu_env, cpu_tmp2_i32);
+ break;
+ case 1:
+ gen_helper_check_iow(cpu_env, cpu_tmp2_i32);
+ break;
+ case 2:
+ gen_helper_check_iol(cpu_env, cpu_tmp2_i32);
+ break;
}
}
if(s->flags & HF_SVMI_MASK) {
@@ -754,7 +760,8 @@ static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip,
svm_flags |= (1 << (4 + ot));
next_eip = s->pc - s->cs_base;
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_svm_check_io(cpu_tmp2_i32, tcg_const_i32(svm_flags),
+ gen_helper_svm_check_io(cpu_env, cpu_tmp2_i32,
+ tcg_const_i32(svm_flags),
tcg_const_i32(next_eip - cur_eip));
}
}
@@ -811,14 +818,14 @@ static void gen_op_update_neg_cc(void)
/* compute eflags.C to reg */
static void gen_compute_eflags_c(TCGv reg)
{
- gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_cc_op);
+ gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op);
tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
}
/* compute all eflags to cc_src */
static void gen_compute_eflags(TCGv reg)
{
- gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_cc_op);
+ gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_env, cpu_cc_op);
tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
}
@@ -1266,14 +1273,30 @@ GEN_REPZ2(cmps)
static void gen_helper_fp_arith_ST0_FT0(int op)
{
switch (op) {
- case 0: gen_helper_fadd_ST0_FT0(); break;
- case 1: gen_helper_fmul_ST0_FT0(); break;
- case 2: gen_helper_fcom_ST0_FT0(); break;
- case 3: gen_helper_fcom_ST0_FT0(); break;
- case 4: gen_helper_fsub_ST0_FT0(); break;
- case 5: gen_helper_fsubr_ST0_FT0(); break;
- case 6: gen_helper_fdiv_ST0_FT0(); break;
- case 7: gen_helper_fdivr_ST0_FT0(); break;
+ case 0:
+ gen_helper_fadd_ST0_FT0(cpu_env);
+ break;
+ case 1:
+ gen_helper_fmul_ST0_FT0(cpu_env);
+ break;
+ case 2:
+ gen_helper_fcom_ST0_FT0(cpu_env);
+ break;
+ case 3:
+ gen_helper_fcom_ST0_FT0(cpu_env);
+ break;
+ case 4:
+ gen_helper_fsub_ST0_FT0(cpu_env);
+ break;
+ case 5:
+ gen_helper_fsubr_ST0_FT0(cpu_env);
+ break;
+ case 6:
+ gen_helper_fdiv_ST0_FT0(cpu_env);
+ break;
+ case 7:
+ gen_helper_fdivr_ST0_FT0(cpu_env);
+ break;
}
}
@@ -1282,12 +1305,24 @@ static void gen_helper_fp_arith_STN_ST0(int op, int opreg)
{
TCGv_i32 tmp = tcg_const_i32(opreg);
switch (op) {
- case 0: gen_helper_fadd_STN_ST0(tmp); break;
- case 1: gen_helper_fmul_STN_ST0(tmp); break;
- case 4: gen_helper_fsubr_STN_ST0(tmp); break;
- case 5: gen_helper_fsub_STN_ST0(tmp); break;
- case 6: gen_helper_fdivr_STN_ST0(tmp); break;
- case 7: gen_helper_fdiv_STN_ST0(tmp); break;
+ case 0:
+ gen_helper_fadd_STN_ST0(cpu_env, tmp);
+ break;
+ case 1:
+ gen_helper_fmul_STN_ST0(cpu_env, tmp);
+ break;
+ case 4:
+ gen_helper_fsubr_STN_ST0(cpu_env, tmp);
+ break;
+ case 5:
+ gen_helper_fsub_STN_ST0(cpu_env, tmp);
+ break;
+ case 6:
+ gen_helper_fdivr_STN_ST0(cpu_env, tmp);
+ break;
+ case 7:
+ gen_helper_fdiv_STN_ST0(cpu_env, tmp);
+ break;
}
}
@@ -1745,20 +1780,36 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
if (is_right) {
switch (ot) {
- case 0: gen_helper_rcrb(cpu_T[0], cpu_T[0], cpu_T[1]); break;
- case 1: gen_helper_rcrw(cpu_T[0], cpu_T[0], cpu_T[1]); break;
- case 2: gen_helper_rcrl(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+ case 0:
+ gen_helper_rcrb(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
+ break;
+ case 1:
+ gen_helper_rcrw(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
+ break;
+ case 2:
+ gen_helper_rcrl(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
+ break;
#ifdef TARGET_X86_64
- case 3: gen_helper_rcrq(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+ case 3:
+ gen_helper_rcrq(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
+ break;
#endif
}
} else {
switch (ot) {
- case 0: gen_helper_rclb(cpu_T[0], cpu_T[0], cpu_T[1]); break;
- case 1: gen_helper_rclw(cpu_T[0], cpu_T[0], cpu_T[1]); break;
- case 2: gen_helper_rcll(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+ case 0:
+ gen_helper_rclb(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
+ break;
+ case 1:
+ gen_helper_rclw(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
+ break;
+ case 2:
+ gen_helper_rcll(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
+ break;
#ifdef TARGET_X86_64
- case 3: gen_helper_rclq(cpu_T[0], cpu_T[0], cpu_T[1]); break;
+ case 3:
+ gen_helper_rclq(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
+ break;
#endif
}
}
@@ -1992,7 +2043,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
if (base == 4) {
havesib = 1;
- code = ldub_code(s->pc++);
+ code = cpu_ldub_code(cpu_single_env, s->pc++);
scale = (code >> 6) & 3;
index = ((code >> 3) & 7) | REX_X(s);
base = (code & 7);
@@ -2003,7 +2054,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
case 0:
if ((base & 7) == 5) {
base = -1;
- disp = (int32_t)ldl_code(s->pc);
+ disp = (int32_t)cpu_ldl_code(cpu_single_env, s->pc);
s->pc += 4;
if (CODE64(s) && !havesib) {
disp += s->pc + s->rip_offset;
@@ -2013,11 +2064,11 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
}
break;
case 1:
- disp = (int8_t)ldub_code(s->pc++);
+ disp = (int8_t)cpu_ldub_code(cpu_single_env, s->pc++);
break;
default:
case 2:
- disp = (int32_t)ldl_code(s->pc);
+ disp = (int32_t)cpu_ldl_code(cpu_single_env, s->pc);
s->pc += 4;
break;
}
@@ -2080,7 +2131,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
switch (mod) {
case 0:
if (rm == 6) {
- disp = lduw_code(s->pc);
+ disp = cpu_lduw_code(cpu_single_env, s->pc);
s->pc += 2;
gen_op_movl_A0_im(disp);
rm = 0; /* avoid SS override */
@@ -2090,11 +2141,11 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
}
break;
case 1:
- disp = (int8_t)ldub_code(s->pc++);
+ disp = (int8_t)cpu_ldub_code(cpu_single_env, s->pc++);
break;
default:
case 2:
- disp = lduw_code(s->pc);
+ disp = cpu_lduw_code(cpu_single_env, s->pc);
s->pc += 2;
break;
}
@@ -2164,7 +2215,7 @@ static void gen_nop_modrm(DisasContext *s, int modrm)
base = rm;
if (base == 4) {
- code = ldub_code(s->pc++);
+ code = cpu_ldub_code(cpu_single_env, s->pc++);
base = (code & 7);
}
@@ -2260,16 +2311,16 @@ static inline uint32_t insn_get(DisasContext *s, int ot)
switch(ot) {
case OT_BYTE:
- ret = ldub_code(s->pc);
+ ret = cpu_ldub_code(cpu_single_env, s->pc);
s->pc++;
break;
case OT_WORD:
- ret = lduw_code(s->pc);
+ ret = cpu_lduw_code(cpu_single_env, s->pc);
s->pc += 2;
break;
default:
case OT_LONG:
- ret = ldl_code(s->pc);
+ ret = cpu_ldl_code(cpu_single_env, s->pc);
s->pc += 4;
break;
}
@@ -2392,7 +2443,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(cur_eip);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_load_seg(tcg_const_i32(seg_reg), cpu_tmp2_i32);
+ gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), cpu_tmp2_i32);
/* abort translation because the addseg value may change or
because ss32 may change. For R_SS, translation must always
stop as a special handling must be done to disable hardware
@@ -2421,7 +2472,7 @@ gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start,
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_svm_check_intercept_param(tcg_const_i32(type),
+ gen_helper_svm_check_intercept_param(cpu_env, tcg_const_i32(type),
tcg_const_i64(param));
}
@@ -2629,7 +2680,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
gen_op_st_T0_A0(ot + s->mem_index);
if (level) {
/* XXX: must save state */
- gen_helper_enter64_level(tcg_const_i32(level),
+ gen_helper_enter64_level(cpu_env, tcg_const_i32(level),
tcg_const_i32((ot == OT_QUAD)),
cpu_T[1]);
}
@@ -2654,7 +2705,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
gen_op_st_T0_A0(ot + s->mem_index);
if (level) {
/* XXX: must save state */
- gen_helper_enter_level(tcg_const_i32(level),
+ gen_helper_enter_level(cpu_env, tcg_const_i32(level),
tcg_const_i32(s->dflag),
cpu_T[1]);
}
@@ -2691,7 +2742,7 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(cur_eip);
- gen_helper_debug();
+ gen_helper_debug(cpu_env);
s->is_jmp = DISAS_TB_JUMP;
}
@@ -2702,15 +2753,15 @@ static void gen_eob(DisasContext *s)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
- gen_helper_reset_inhibit_irq();
+ gen_helper_reset_inhibit_irq(cpu_env);
}
if (s->tb->flags & HF_RF_MASK) {
- gen_helper_reset_rf();
+ gen_helper_reset_rf(cpu_env);
}
if (s->singlestep_enabled) {
- gen_helper_debug();
+ gen_helper_debug(cpu_env);
} else if (s->tf) {
- gen_helper_single_step();
+ gen_helper_single_step(cpu_env);
} else {
tcg_gen_exit_tb(0);
}
@@ -2796,13 +2847,16 @@ static inline void gen_op_movq_env_0(int d_offset)
tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset);
}
-typedef void (*SSEFunc_i_p)(TCGv_i32 val, TCGv_ptr reg);
-typedef void (*SSEFunc_l_p)(TCGv_i64 val, TCGv_ptr reg);
-typedef void (*SSEFunc_0_pi)(TCGv_ptr reg, TCGv_i32 val);
-typedef void (*SSEFunc_0_pl)(TCGv_ptr reg, TCGv_i64 val);
-typedef void (*SSEFunc_0_pp)(TCGv_ptr reg_a, TCGv_ptr reg_b);
+typedef void (*SSEFunc_i_ep)(TCGv_i32 val, TCGv_ptr env, TCGv_ptr reg);
+typedef void (*SSEFunc_l_ep)(TCGv_i64 val, TCGv_ptr env, TCGv_ptr reg);
+typedef void (*SSEFunc_0_epi)(TCGv_ptr env, TCGv_ptr reg, TCGv_i32 val);
+typedef void (*SSEFunc_0_epl)(TCGv_ptr env, TCGv_ptr reg, TCGv_i64 val);
+typedef void (*SSEFunc_0_epp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b);
+typedef void (*SSEFunc_0_eppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
+ TCGv_i32 val);
typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val);
-typedef void (*SSEFunc_0_ppt)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv val);
+typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
+ TCGv val);
#define SSE_SPECIAL ((void *)1)
#define SSE_DUMMY ((void *)2)
@@ -2811,7 +2865,7 @@ typedef void (*SSEFunc_0_ppt)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv val);
#define SSE_FOP(x) { gen_helper_ ## x ## ps, gen_helper_ ## x ## pd, \
gen_helper_ ## x ## ss, gen_helper_ ## x ## sd, }
-static const SSEFunc_0_pp sse_op_table1[256][4] = {
+static const SSEFunc_0_epp sse_op_table1[256][4] = {
/* 3DNow! extensions */
[0x0e] = { SSE_DUMMY }, /* femms */
[0x0f] = { SSE_DUMMY }, /* pf... */
@@ -2852,8 +2906,8 @@ static const SSEFunc_0_pp sse_op_table1[256][4] = {
[0x5f] = SSE_FOP(max),
[0xc2] = SSE_FOP(cmpeq),
- [0xc6] = { (SSEFunc_0_pp)gen_helper_shufps,
- (SSEFunc_0_pp)gen_helper_shufpd }, /* XXX: casts */
+ [0xc6] = { (SSEFunc_0_epp)gen_helper_shufps,
+ (SSEFunc_0_epp)gen_helper_shufpd }, /* XXX: casts */
[0x38] = { SSE_SPECIAL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* SSSE3/SSE4 */
[0x3a] = { SSE_SPECIAL, SSE_SPECIAL }, /* SSSE3/SSE4 */
@@ -2875,10 +2929,10 @@ static const SSEFunc_0_pp sse_op_table1[256][4] = {
[0x6d] = { NULL, gen_helper_punpckhqdq_xmm },
[0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */
[0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */
- [0x70] = { (SSEFunc_0_pp)gen_helper_pshufw_mmx,
- (SSEFunc_0_pp)gen_helper_pshufd_xmm,
- (SSEFunc_0_pp)gen_helper_pshufhw_xmm,
- (SSEFunc_0_pp)gen_helper_pshuflw_xmm }, /* XXX: casts */
+ [0x70] = { (SSEFunc_0_epp)gen_helper_pshufw_mmx,
+ (SSEFunc_0_epp)gen_helper_pshufd_xmm,
+ (SSEFunc_0_epp)gen_helper_pshufhw_xmm,
+ (SSEFunc_0_epp)gen_helper_pshuflw_xmm }, /* XXX: casts */
[0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */
[0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */
[0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */
@@ -2933,8 +2987,8 @@ static const SSEFunc_0_pp sse_op_table1[256][4] = {
[0xf4] = MMX_OP2(pmuludq),
[0xf5] = MMX_OP2(pmaddwd),
[0xf6] = MMX_OP2(psadbw),
- [0xf7] = { (SSEFunc_0_pp)gen_helper_maskmov_mmx,
- (SSEFunc_0_pp)gen_helper_maskmov_xmm }, /* XXX: casts */
+ [0xf7] = { (SSEFunc_0_epp)gen_helper_maskmov_mmx,
+ (SSEFunc_0_epp)gen_helper_maskmov_xmm }, /* XXX: casts */
[0xf8] = MMX_OP2(psubb),
[0xf9] = MMX_OP2(psubw),
[0xfa] = MMX_OP2(psubl),
@@ -2944,7 +2998,7 @@ static const SSEFunc_0_pp sse_op_table1[256][4] = {
[0xfe] = MMX_OP2(paddl),
};
-static const SSEFunc_0_pp sse_op_table2[3 * 8][2] = {
+static const SSEFunc_0_epp sse_op_table2[3 * 8][2] = {
[0 + 2] = MMX_OP2(psrlw),
[0 + 4] = MMX_OP2(psraw),
[0 + 6] = MMX_OP2(psllw),
@@ -2957,19 +3011,19 @@ static const SSEFunc_0_pp sse_op_table2[3 * 8][2] = {
[16 + 7] = { NULL, gen_helper_pslldq_xmm },
};
-static const SSEFunc_0_pi sse_op_table3ai[] = {
+static const SSEFunc_0_epi sse_op_table3ai[] = {
gen_helper_cvtsi2ss,
gen_helper_cvtsi2sd
};
#ifdef TARGET_X86_64
-static const SSEFunc_0_pl sse_op_table3aq[] = {
+static const SSEFunc_0_epl sse_op_table3aq[] = {
gen_helper_cvtsq2ss,
gen_helper_cvtsq2sd
};
#endif
-static const SSEFunc_i_p sse_op_table3bi[] = {
+static const SSEFunc_i_ep sse_op_table3bi[] = {
gen_helper_cvttss2si,
gen_helper_cvtss2si,
gen_helper_cvttsd2si,
@@ -2977,7 +3031,7 @@ static const SSEFunc_i_p sse_op_table3bi[] = {
};
#ifdef TARGET_X86_64
-static const SSEFunc_l_p sse_op_table3bq[] = {
+static const SSEFunc_l_ep sse_op_table3bq[] = {
gen_helper_cvttss2sq,
gen_helper_cvtss2sq,
gen_helper_cvttsd2sq,
@@ -2985,7 +3039,7 @@ static const SSEFunc_l_p sse_op_table3bq[] = {
};
#endif
-static const SSEFunc_0_pp sse_op_table4[8][4] = {
+static const SSEFunc_0_epp sse_op_table4[8][4] = {
SSE_FOP(cmpeq),
SSE_FOP(cmplt),
SSE_FOP(cmple),
@@ -2996,7 +3050,7 @@ static const SSEFunc_0_pp sse_op_table4[8][4] = {
SSE_FOP(cmpord),
};
-static const SSEFunc_0_pp sse_op_table5[256] = {
+static const SSEFunc_0_epp sse_op_table5[256] = {
[0x0c] = gen_helper_pi2fw,
[0x0d] = gen_helper_pi2fd,
[0x1c] = gen_helper_pf2iw,
@@ -3023,13 +3077,13 @@ static const SSEFunc_0_pp sse_op_table5[256] = {
[0xbf] = gen_helper_pavgb_mmx /* pavgusb */
};
-struct SSEOpHelper_pp {
- SSEFunc_0_pp op[2];
+struct SSEOpHelper_epp {
+ SSEFunc_0_epp op[2];
uint32_t ext_mask;
};
-struct SSEOpHelper_ppi {
- SSEFunc_0_ppi op[2];
+struct SSEOpHelper_eppi {
+ SSEFunc_0_eppi op[2];
uint32_t ext_mask;
};
@@ -3038,7 +3092,7 @@ struct SSEOpHelper_ppi {
#define SSE42_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE42 }
#define SSE41_SPECIAL { { NULL, SSE_SPECIAL }, CPUID_EXT_SSE41 }
-static const struct SSEOpHelper_pp sse_op_table6[256] = {
+static const struct SSEOpHelper_epp sse_op_table6[256] = {
[0x00] = SSSE3_OP(pshufb),
[0x01] = SSSE3_OP(phaddw),
[0x02] = SSSE3_OP(phaddd),
@@ -3087,7 +3141,7 @@ static const struct SSEOpHelper_pp sse_op_table6[256] = {
[0x41] = SSE41_OP(phminposuw),
};
-static const struct SSEOpHelper_ppi sse_op_table7[256] = {
+static const struct SSEOpHelper_eppi sse_op_table7[256] = {
[0x08] = SSE41_OP(roundps),
[0x09] = SSE41_OP(roundpd),
[0x0a] = SSE41_OP(roundss),
@@ -3116,9 +3170,10 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
{
int b1, op1_offset, op2_offset, is_xmm, val, ot;
int modrm, mod, rm, reg, reg_addr, offset_addr;
- SSEFunc_0_pp sse_fn_pp;
+ SSEFunc_0_epp sse_fn_epp;
+ SSEFunc_0_eppi sse_fn_eppi;
SSEFunc_0_ppi sse_fn_ppi;
- SSEFunc_0_ppt sse_fn_ppt;
+ SSEFunc_0_eppt sse_fn_eppt;
b &= 0xff;
if (s->prefix & PREFIX_DATA)
@@ -3129,8 +3184,8 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
b1 = 3;
else
b1 = 0;
- sse_fn_pp = sse_op_table1[b][b1];
- if (!sse_fn_pp) {
+ sse_fn_epp = sse_op_table1[b][b1];
+ if (!sse_fn_epp) {
goto illegal_op;
}
if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) {
@@ -3160,26 +3215,26 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW))
goto illegal_op;
/* femms */
- gen_helper_emms();
+ gen_helper_emms(cpu_env);
return;
}
if (b == 0x77) {
/* emms */
- gen_helper_emms();
+ gen_helper_emms(cpu_env);
return;
}
/* prepare MMX state (XXX: optimize by storing fptt and fptags in
the static cpu state) */
if (!is_xmm) {
- gen_helper_enter_mmx();
+ gen_helper_enter_mmx(cpu_env);
}
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7);
if (is_xmm)
reg |= rex_r;
mod = (modrm >> 6) & 3;
- if (sse_fn_pp == SSE_SPECIAL) {
+ if (sse_fn_epp == SSE_SPECIAL) {
b |= (b1 << 8);
switch(b) {
case 0x0e7: /* movntq */
@@ -3378,16 +3433,18 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
if (b1 == 1 && reg != 0)
goto illegal_op;
- field_length = ldub_code(s->pc++) & 0x3F;
- bit_index = ldub_code(s->pc++) & 0x3F;
+ field_length = cpu_ldub_code(cpu_single_env, s->pc++) & 0x3F;
+ bit_index = cpu_ldub_code(cpu_single_env, s->pc++) & 0x3F;
tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
offsetof(CPUX86State,xmm_regs[reg]));
if (b1 == 1)
- gen_helper_extrq_i(cpu_ptr0, tcg_const_i32(bit_index),
- tcg_const_i32(field_length));
+ gen_helper_extrq_i(cpu_env, cpu_ptr0,
+ tcg_const_i32(bit_index),
+ tcg_const_i32(field_length));
else
- gen_helper_insertq_i(cpu_ptr0, tcg_const_i32(bit_index),
- tcg_const_i32(field_length));
+ gen_helper_insertq_i(cpu_env, cpu_ptr0,
+ tcg_const_i32(bit_index),
+ tcg_const_i32(field_length));
}
break;
case 0x7e: /* movd ea, mm */
@@ -3502,7 +3559,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
if (b1 >= 2) {
goto illegal_op;
}
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
if (is_xmm) {
gen_op_movl_T0_im(val);
tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
@@ -3516,8 +3573,9 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,mmx_t0.MMX_L(1)));
op1_offset = offsetof(CPUX86State,mmx_t0);
}
- sse_fn_pp = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1];
- if (!sse_fn_pp) {
+ sse_fn_epp = sse_op_table2[((b - 1) & 3) * 8 +
+ (((modrm >> 3)) & 7)][b1];
+ if (!sse_fn_epp) {
goto illegal_op;
}
if (is_xmm) {
@@ -3529,13 +3587,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
}
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op1_offset);
- sse_fn_pp(cpu_ptr0, cpu_ptr1);
+ sse_fn_epp(cpu_env, cpu_ptr0, cpu_ptr1);
break;
case 0x050: /* movmskps */
rm = (modrm & 7) | REX_B(s);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
offsetof(CPUX86State,xmm_regs[rm]));
- gen_helper_movmskps(cpu_tmp2_i32, cpu_ptr0);
+ gen_helper_movmskps(cpu_tmp2_i32, cpu_env, cpu_ptr0);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_mov_reg_T0(OT_LONG, reg);
break;
@@ -3543,13 +3601,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
rm = (modrm & 7) | REX_B(s);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
offsetof(CPUX86State,xmm_regs[rm]));
- gen_helper_movmskpd(cpu_tmp2_i32, cpu_ptr0);
+ gen_helper_movmskpd(cpu_tmp2_i32, cpu_env, cpu_ptr0);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_mov_reg_T0(OT_LONG, reg);
break;
case 0x02a: /* cvtpi2ps */
case 0x12a: /* cvtpi2pd */
- gen_helper_enter_mmx();
+ gen_helper_enter_mmx(cpu_env);
if (mod != 3) {
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
op2_offset = offsetof(CPUX86State,mmx_t0);
@@ -3563,11 +3621,11 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
switch(b >> 8) {
case 0x0:
- gen_helper_cvtpi2ps(cpu_ptr0, cpu_ptr1);
+ gen_helper_cvtpi2ps(cpu_env, cpu_ptr0, cpu_ptr1);
break;
default:
case 0x1:
- gen_helper_cvtpi2pd(cpu_ptr0, cpu_ptr1);
+ gen_helper_cvtpi2pd(cpu_env, cpu_ptr0, cpu_ptr1);
break;
}
break;
@@ -3578,13 +3636,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
if (ot == OT_LONG) {
- SSEFunc_0_pi sse_fn_pi = sse_op_table3ai[(b >> 8) & 1];
+ SSEFunc_0_epi sse_fn_epi = sse_op_table3ai[(b >> 8) & 1];
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- sse_fn_pi(cpu_ptr0, cpu_tmp2_i32);
+ sse_fn_epi(cpu_env, cpu_ptr0, cpu_tmp2_i32);
} else {
#ifdef TARGET_X86_64
- SSEFunc_0_pl sse_fn_pl = sse_op_table3aq[(b >> 8) & 1];
- sse_fn_pl(cpu_ptr0, cpu_T[0]);
+ SSEFunc_0_epl sse_fn_epl = sse_op_table3aq[(b >> 8) & 1];
+ sse_fn_epl(cpu_env, cpu_ptr0, cpu_T[0]);
#else
goto illegal_op;
#endif
@@ -3594,7 +3652,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
case 0x12c: /* cvttpd2pi */
case 0x02d: /* cvtps2pi */
case 0x12d: /* cvtpd2pi */
- gen_helper_enter_mmx();
+ gen_helper_enter_mmx(cpu_env);
if (mod != 3) {
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
op2_offset = offsetof(CPUX86State,xmm_t0);
@@ -3608,16 +3666,16 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
switch(b) {
case 0x02c:
- gen_helper_cvttps2pi(cpu_ptr0, cpu_ptr1);
+ gen_helper_cvttps2pi(cpu_env, cpu_ptr0, cpu_ptr1);
break;
case 0x12c:
- gen_helper_cvttpd2pi(cpu_ptr0, cpu_ptr1);
+ gen_helper_cvttpd2pi(cpu_env, cpu_ptr0, cpu_ptr1);
break;
case 0x02d:
- gen_helper_cvtps2pi(cpu_ptr0, cpu_ptr1);
+ gen_helper_cvtps2pi(cpu_env, cpu_ptr0, cpu_ptr1);
break;
case 0x12d:
- gen_helper_cvtpd2pi(cpu_ptr0, cpu_ptr1);
+ gen_helper_cvtpd2pi(cpu_env, cpu_ptr0, cpu_ptr1);
break;
}
break;
@@ -3641,15 +3699,15 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
}
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset);
if (ot == OT_LONG) {
- SSEFunc_i_p sse_fn_i_p =
+ SSEFunc_i_ep sse_fn_i_ep =
sse_op_table3bi[((b >> 7) & 2) | (b & 1)];
- sse_fn_i_p(cpu_tmp2_i32, cpu_ptr0);
+ sse_fn_i_ep(cpu_tmp2_i32, cpu_env, cpu_ptr0);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
} else {
#ifdef TARGET_X86_64
- SSEFunc_l_p sse_fn_l_p =
+ SSEFunc_l_ep sse_fn_l_ep =
sse_op_table3bq[((b >> 7) & 2) | (b & 1)];
- sse_fn_l_p(cpu_T[0], cpu_ptr0);
+ sse_fn_l_ep(cpu_T[0], cpu_env, cpu_ptr0);
#else
goto illegal_op;
#endif
@@ -3660,7 +3718,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
case 0x1c4:
s->rip_offset = 1;
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
if (b1) {
val &= 7;
tcg_gen_st16_tl(cpu_T[0], cpu_env,
@@ -3676,7 +3734,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
if (mod != 3)
goto illegal_op;
ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
if (b1) {
val &= 7;
rm = (modrm & 7) | REX_B(s);
@@ -3703,14 +3761,14 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
}
break;
case 0x2d6: /* movq2dq */
- gen_helper_enter_mmx();
+ gen_helper_enter_mmx(cpu_env);
rm = (modrm & 7);
gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
offsetof(CPUX86State,fpregs[rm].mmx));
gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
break;
case 0x3d6: /* movdq2q */
- gen_helper_enter_mmx();
+ gen_helper_enter_mmx(cpu_env);
rm = (modrm & 7) | REX_B(s);
gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx),
offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
@@ -3722,11 +3780,11 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
if (b1) {
rm = (modrm & 7) | REX_B(s);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, offsetof(CPUX86State,xmm_regs[rm]));
- gen_helper_pmovmskb_xmm(cpu_tmp2_i32, cpu_ptr0);
+ gen_helper_pmovmskb_xmm(cpu_tmp2_i32, cpu_env, cpu_ptr0);
} else {
rm = (modrm & 7);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, offsetof(CPUX86State,fpregs[rm].mmx));
- gen_helper_pmovmskb_mmx(cpu_tmp2_i32, cpu_ptr0);
+ gen_helper_pmovmskb_mmx(cpu_tmp2_i32, cpu_env, cpu_ptr0);
}
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
reg = ((modrm >> 3) & 7) | rex_r;
@@ -3737,7 +3795,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
goto crc32;
case 0x038:
b = modrm;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
rm = modrm & 7;
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
@@ -3745,8 +3803,8 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
goto illegal_op;
}
- sse_fn_pp = sse_op_table6[b].op[b1];
- if (!sse_fn_pp) {
+ sse_fn_epp = sse_op_table6[b].op[b1];
+ if (!sse_fn_epp) {
goto illegal_op;
}
if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask))
@@ -3797,13 +3855,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
gen_ldq_env_A0(s->mem_index, op2_offset);
}
}
- if (sse_fn_pp == SSE_SPECIAL) {
+ if (sse_fn_epp == SSE_SPECIAL) {
goto illegal_op;
}
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- sse_fn_pp(cpu_ptr0, cpu_ptr1);
+ sse_fn_epp(cpu_env, cpu_ptr0, cpu_ptr1);
if (b == 0x17)
s->cc_op = CC_OP_EFLAGS;
@@ -3811,7 +3869,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
case 0x338: /* crc32 */
crc32:
b = modrm;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
if (b != 0xf0 && b != 0xf1)
@@ -3841,7 +3899,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
case 0x03a:
case 0x13a:
b = modrm;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
rm = modrm & 7;
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
@@ -3849,20 +3907,20 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
goto illegal_op;
}
- sse_fn_ppi = sse_op_table7[b].op[b1];
- if (!sse_fn_ppi) {
+ sse_fn_eppi = sse_op_table7[b].op[b1];
+ if (!sse_fn_eppi) {
goto illegal_op;
}
if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask))
goto illegal_op;
- if (sse_fn_ppi == SSE_SPECIAL) {
+ if (sse_fn_eppi == SSE_SPECIAL) {
ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
rm = (modrm & 7) | REX_B(s);
if (mod != 3)
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
reg = ((modrm >> 3) & 7) | rex_r;
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
switch (b) {
case 0x14: /* pextrb */
tcg_gen_ld8u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,
@@ -4005,7 +4063,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
gen_ldq_env_A0(s->mem_index, op2_offset);
}
}
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
if ((b & 0xfc) == 0x60) { /* pcmpXstrX */
s->cc_op = CC_OP_EFLAGS;
@@ -4017,7 +4075,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- sse_fn_ppi(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
+ sse_fn_eppi(cpu_env, cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
break;
default:
goto illegal_op;
@@ -4071,34 +4129,34 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
case 0x0f: /* 3DNow! data insns */
if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW))
goto illegal_op;
- val = ldub_code(s->pc++);
- sse_fn_pp = sse_op_table5[val];
- if (!sse_fn_pp) {
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
+ sse_fn_epp = sse_op_table5[val];
+ if (!sse_fn_epp) {
goto illegal_op;
}
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- sse_fn_pp(cpu_ptr0, cpu_ptr1);
+ sse_fn_epp(cpu_env, cpu_ptr0, cpu_ptr1);
break;
case 0x70: /* pshufx insn */
case 0xc6: /* pshufx insn */
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
/* XXX: introduce a new table? */
- sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_pp;
+ sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_epp;
sse_fn_ppi(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
break;
case 0xc2:
/* compare insns */
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
if (val >= 8)
goto illegal_op;
- sse_fn_pp = sse_op_table4[val][b1];
+ sse_fn_epp = sse_op_table4[val][b1];
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- sse_fn_pp(cpu_ptr0, cpu_ptr1);
+ sse_fn_epp(cpu_env, cpu_ptr0, cpu_ptr1);
break;
case 0xf7:
/* maskmov : we must prepare A0 */
@@ -4119,13 +4177,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
/* XXX: introduce a new table? */
- sse_fn_ppt = (SSEFunc_0_ppt)sse_fn_pp;
- sse_fn_ppt(cpu_ptr0, cpu_ptr1, cpu_A0);
+ sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp;
+ sse_fn_eppt(cpu_env, cpu_ptr0, cpu_ptr1, cpu_A0);
break;
default:
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- sse_fn_pp(cpu_ptr0, cpu_ptr1);
+ sse_fn_epp(cpu_env, cpu_ptr0, cpu_ptr1);
break;
}
if (b == 0x2e || b == 0x2f) {
@@ -4160,7 +4218,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
#endif
s->rip_offset = 0; /* for relative ip address */
next_byte:
- b = ldub_code(s->pc);
+ b = cpu_ldub_code(cpu_single_env, s->pc);
s->pc++;
/* check prefixes */
#ifdef TARGET_X86_64
@@ -4275,7 +4333,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0x0f:
/**************************/
/* extended op code */
- b = ldub_code(s->pc++) | 0x100;
+ b = cpu_ldub_code(cpu_single_env, s->pc++) | 0x100;
goto reswitch;
/**************************/
@@ -4300,7 +4358,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
switch(f) {
case 0: /* OP Ev, Gv */
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
@@ -4322,7 +4380,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op(s, op, ot, opreg);
break;
case 1: /* OP Gv, Ev */
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
reg = ((modrm >> 3) & 7) | rex_r;
rm = (modrm & 7) | REX_B(s);
@@ -4359,7 +4417,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
op = (modrm >> 3) & 7;
@@ -4408,7 +4466,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
op = (modrm >> 3) & 7;
@@ -4506,7 +4564,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
#ifdef TARGET_X86_64
case OT_QUAD:
- gen_helper_mulq_EAX_T0(cpu_T[0]);
+ gen_helper_mulq_EAX_T0(cpu_env, cpu_T[0]);
s->cc_op = CC_OP_MULQ;
break;
#endif
@@ -4576,7 +4634,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
#ifdef TARGET_X86_64
case OT_QUAD:
- gen_helper_imulq_EAX_T0(cpu_T[0]);
+ gen_helper_imulq_EAX_T0(cpu_env, cpu_T[0]);
s->cc_op = CC_OP_MULQ;
break;
#endif
@@ -4586,21 +4644,21 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
switch(ot) {
case OT_BYTE:
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_divb_AL(cpu_T[0]);
+ gen_helper_divb_AL(cpu_env, cpu_T[0]);
break;
case OT_WORD:
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_divw_AX(cpu_T[0]);
+ gen_helper_divw_AX(cpu_env, cpu_T[0]);
break;
default:
case OT_LONG:
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_divl_EAX(cpu_T[0]);
+ gen_helper_divl_EAX(cpu_env, cpu_T[0]);
break;
#ifdef TARGET_X86_64
case OT_QUAD:
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_divq_EAX(cpu_T[0]);
+ gen_helper_divq_EAX(cpu_env, cpu_T[0]);
break;
#endif
}
@@ -4609,21 +4667,21 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
switch(ot) {
case OT_BYTE:
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_idivb_AL(cpu_T[0]);
+ gen_helper_idivb_AL(cpu_env, cpu_T[0]);
break;
case OT_WORD:
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_idivw_AX(cpu_T[0]);
+ gen_helper_idivw_AX(cpu_env, cpu_T[0]);
break;
default:
case OT_LONG:
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_idivl_EAX(cpu_T[0]);
+ gen_helper_idivl_EAX(cpu_env, cpu_T[0]);
break;
#ifdef TARGET_X86_64
case OT_QUAD:
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_idivq_EAX(cpu_T[0]);
+ gen_helper_idivq_EAX(cpu_env, cpu_T[0]);
break;
#endif
}
@@ -4640,7 +4698,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
op = (modrm >> 3) & 7;
@@ -4701,13 +4759,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_lcall_protected(cpu_tmp2_i32, cpu_T[1],
- tcg_const_i32(dflag),
+ gen_helper_lcall_protected(cpu_env, cpu_tmp2_i32, cpu_T[1],
+ tcg_const_i32(dflag),
tcg_const_i32(s->pc - pc_start));
} else {
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_lcall_real(cpu_tmp2_i32, cpu_T[1],
- tcg_const_i32(dflag),
+ gen_helper_lcall_real(cpu_env, cpu_tmp2_i32, cpu_T[1],
+ tcg_const_i32(dflag),
tcg_const_i32(s->pc - s->cs_base));
}
gen_eob(s);
@@ -4728,7 +4786,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_ljmp_protected(cpu_tmp2_i32, cpu_T[1],
+ gen_helper_ljmp_protected(cpu_env, cpu_tmp2_i32, cpu_T[1],
tcg_const_i32(s->pc - pc_start));
} else {
gen_op_movl_seg_T0_vm(R_CS);
@@ -4752,7 +4810,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
@@ -4817,7 +4875,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0x69: /* imul Gv, Ev, I */
case 0x6b:
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
if (b == 0x69)
s->rip_offset = insn_const_size(ot);
@@ -4836,7 +4894,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
#ifdef TARGET_X86_64
if (ot == OT_QUAD) {
- gen_helper_imulq_T0_T1(cpu_T[0], cpu_T[0], cpu_T[1]);
+ gen_helper_imulq_T0_T1(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]);
} else
#endif
if (ot == OT_LONG) {
@@ -4881,7 +4939,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE;
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
if (mod == 3) {
@@ -4912,7 +4970,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE;
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
t0 = tcg_temp_local_new();
@@ -4960,7 +5018,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
}
break;
case 0x1c7: /* cmpxchg8b */
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
if ((mod == 3) || ((modrm & 0x38) != 0x8))
goto illegal_op;
@@ -4972,7 +5030,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_helper_cmpxchg16b(cpu_A0);
+ gen_helper_cmpxchg16b(cpu_env, cpu_A0);
} else
#endif
{
@@ -4982,7 +5040,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_helper_cmpxchg8b(cpu_A0);
+ gen_helper_cmpxchg8b(cpu_env, cpu_A0);
}
s->cc_op = CC_OP_EFLAGS;
break;
@@ -5034,7 +5092,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
} else {
ot = dflag + OT_WORD;
}
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
gen_pop_T0(s);
if (mod == 3) {
@@ -5053,9 +5111,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0xc8: /* enter */
{
int level;
- val = lduw_code(s->pc);
+ val = cpu_lduw_code(cpu_single_env, s->pc);
s->pc += 2;
- level = ldub_code(s->pc++);
+ level = cpu_ldub_code(cpu_single_env, s->pc++);
gen_enter(s, val, level);
}
break;
@@ -5108,7 +5166,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
/* If several instructions disable interrupts, only the
_first_ does it */
if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_helper_set_inhibit_irq();
+ gen_helper_set_inhibit_irq(cpu_env);
s->tf = 0;
}
if (s->is_jmp) {
@@ -5135,7 +5193,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE;
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
/* generate a generic store */
@@ -5147,7 +5205,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE;
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
if (mod != 3) {
s->rip_offset = insn_const_size(ot);
@@ -5166,14 +5224,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE;
else
ot = OT_WORD + dflag;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
gen_op_mov_reg_T0(ot, reg);
break;
case 0x8e: /* mov seg, Gv */
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = (modrm >> 3) & 7;
if (reg >= 6 || reg == R_CS)
goto illegal_op;
@@ -5184,7 +5242,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
/* If several instructions disable interrupts, only the
_first_ does it */
if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_helper_set_inhibit_irq();
+ gen_helper_set_inhibit_irq(cpu_env);
s->tf = 0;
}
if (s->is_jmp) {
@@ -5193,7 +5251,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
}
break;
case 0x8c: /* mov Gv, seg */
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = (modrm >> 3) & 7;
mod = (modrm >> 6) & 3;
if (reg >= 6)
@@ -5216,7 +5274,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
d_ot = dflag + OT_WORD;
/* ot is the size of source */
ot = (b & 1) + OT_BYTE;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
@@ -5253,7 +5311,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0x8d: /* lea */
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
@@ -5280,7 +5338,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = dflag + OT_WORD;
#ifdef TARGET_X86_64
if (s->aflag == 2) {
- offset_addr = ldq_code(s->pc);
+ offset_addr = cpu_ldq_code(cpu_single_env, s->pc);
s->pc += 8;
gen_op_movq_A0_im(offset_addr);
} else
@@ -5336,7 +5394,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (dflag == 2) {
uint64_t tmp;
/* 64 bit case */
- tmp = ldq_code(s->pc);
+ tmp = cpu_ldq_code(cpu_single_env, s->pc);
s->pc += 8;
reg = (b & 7) | REX_B(s);
gen_movtl_T0_im(tmp);
@@ -5364,7 +5422,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE;
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
if (mod == 3) {
@@ -5407,7 +5465,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
op = R_GS;
do_lxx:
ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
if (mod == 3)
@@ -5439,7 +5497,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
else
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
@@ -5458,7 +5516,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_shift(s, op, ot, opreg, OR_ECX);
} else {
if (shift == 2) {
- shift = ldub_code(s->pc++);
+ shift = cpu_ldub_code(cpu_single_env, s->pc++);
}
gen_shifti(s, op, ot, opreg, shift);
}
@@ -5492,7 +5550,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
shift = 0;
do_shiftd:
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
reg = ((modrm >> 3) & 7) | rex_r;
@@ -5505,7 +5563,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_mov_TN_reg(ot, 1, reg);
if (shift) {
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
tcg_gen_movi_tl(cpu_T3, val);
} else {
tcg_gen_mov_tl(cpu_T3, cpu_regs[R_ECX]);
@@ -5522,7 +5580,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
break;
}
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
rm = modrm & 7;
op = ((b & 7) << 3) | ((modrm >> 3) & 7);
@@ -5542,30 +5600,30 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0:
gen_op_ld_T0_A0(OT_LONG + s->mem_index);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_flds_FT0(cpu_tmp2_i32);
+ gen_helper_flds_FT0(cpu_env, cpu_tmp2_i32);
break;
case 1:
gen_op_ld_T0_A0(OT_LONG + s->mem_index);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_fildl_FT0(cpu_tmp2_i32);
+ gen_helper_fildl_FT0(cpu_env, cpu_tmp2_i32);
break;
case 2:
tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
(s->mem_index >> 2) - 1);
- gen_helper_fldl_FT0(cpu_tmp1_i64);
+ gen_helper_fldl_FT0(cpu_env, cpu_tmp1_i64);
break;
case 3:
default:
gen_op_lds_T0_A0(OT_WORD + s->mem_index);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_fildl_FT0(cpu_tmp2_i32);
+ gen_helper_fildl_FT0(cpu_env, cpu_tmp2_i32);
break;
}
gen_helper_fp_arith_ST0_FT0(op1);
if (op1 == 3) {
/* fcomp needs pop */
- gen_helper_fpop();
+ gen_helper_fpop(cpu_env);
}
}
break;
@@ -5581,23 +5639,23 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0:
gen_op_ld_T0_A0(OT_LONG + s->mem_index);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_flds_ST0(cpu_tmp2_i32);
+ gen_helper_flds_ST0(cpu_env, cpu_tmp2_i32);
break;
case 1:
gen_op_ld_T0_A0(OT_LONG + s->mem_index);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_fildl_ST0(cpu_tmp2_i32);
+ gen_helper_fildl_ST0(cpu_env, cpu_tmp2_i32);
break;
case 2:
tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
(s->mem_index >> 2) - 1);
- gen_helper_fldl_ST0(cpu_tmp1_i64);
+ gen_helper_fldl_ST0(cpu_env, cpu_tmp1_i64);
break;
case 3:
default:
gen_op_lds_T0_A0(OT_WORD + s->mem_index);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_fildl_ST0(cpu_tmp2_i32);
+ gen_helper_fildl_ST0(cpu_env, cpu_tmp2_i32);
break;
}
break;
@@ -5605,50 +5663,50 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
/* XXX: the corresponding CPUID bit must be tested ! */
switch(op >> 4) {
case 1:
- gen_helper_fisttl_ST0(cpu_tmp2_i32);
+ gen_helper_fisttl_ST0(cpu_tmp2_i32, cpu_env);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_st_T0_A0(OT_LONG + s->mem_index);
break;
case 2:
- gen_helper_fisttll_ST0(cpu_tmp1_i64);
+ gen_helper_fisttll_ST0(cpu_tmp1_i64, cpu_env);
tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
(s->mem_index >> 2) - 1);
break;
case 3:
default:
- gen_helper_fistt_ST0(cpu_tmp2_i32);
+ gen_helper_fistt_ST0(cpu_tmp2_i32, cpu_env);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_st_T0_A0(OT_WORD + s->mem_index);
break;
}
- gen_helper_fpop();
+ gen_helper_fpop(cpu_env);
break;
default:
switch(op >> 4) {
case 0:
- gen_helper_fsts_ST0(cpu_tmp2_i32);
+ gen_helper_fsts_ST0(cpu_tmp2_i32, cpu_env);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_st_T0_A0(OT_LONG + s->mem_index);
break;
case 1:
- gen_helper_fistl_ST0(cpu_tmp2_i32);
+ gen_helper_fistl_ST0(cpu_tmp2_i32, cpu_env);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_st_T0_A0(OT_LONG + s->mem_index);
break;
case 2:
- gen_helper_fstl_ST0(cpu_tmp1_i64);
+ gen_helper_fstl_ST0(cpu_tmp1_i64, cpu_env);
tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
(s->mem_index >> 2) - 1);
break;
case 3:
default:
- gen_helper_fist_ST0(cpu_tmp2_i32);
+ gen_helper_fist_ST0(cpu_tmp2_i32, cpu_env);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_st_T0_A0(OT_WORD + s->mem_index);
break;
}
if ((op & 7) == 3)
- gen_helper_fpop();
+ gen_helper_fpop(cpu_env);
break;
}
break;
@@ -5656,22 +5714,21 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fldenv(
- cpu_A0, tcg_const_i32(s->dflag));
+ gen_helper_fldenv(cpu_env, cpu_A0, tcg_const_i32(s->dflag));
break;
case 0x0d: /* fldcw mem */
gen_op_ld_T0_A0(OT_WORD + s->mem_index);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_fldcw(cpu_tmp2_i32);
+ gen_helper_fldcw(cpu_env, cpu_tmp2_i32);
break;
case 0x0e: /* fnstenv mem */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fstenv(cpu_A0, tcg_const_i32(s->dflag));
+ gen_helper_fstenv(cpu_env, cpu_A0, tcg_const_i32(s->dflag));
break;
case 0x0f: /* fnstcw mem */
- gen_helper_fnstcw(cpu_tmp2_i32);
+ gen_helper_fnstcw(cpu_tmp2_i32, cpu_env);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_st_T0_A0(OT_WORD + s->mem_index);
break;
@@ -5679,29 +5736,29 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fldt_ST0(cpu_A0);
+ gen_helper_fldt_ST0(cpu_env, cpu_A0);
break;
case 0x1f: /* fstpt mem */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fstt_ST0(cpu_A0);
- gen_helper_fpop();
+ gen_helper_fstt_ST0(cpu_env, cpu_A0);
+ gen_helper_fpop(cpu_env);
break;
case 0x2c: /* frstor mem */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_frstor(cpu_A0, tcg_const_i32(s->dflag));
+ gen_helper_frstor(cpu_env, cpu_A0, tcg_const_i32(s->dflag));
break;
case 0x2e: /* fnsave mem */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fsave(cpu_A0, tcg_const_i32(s->dflag));
+ gen_helper_fsave(cpu_env, cpu_A0, tcg_const_i32(s->dflag));
break;
case 0x2f: /* fnstsw mem */
- gen_helper_fnstsw(cpu_tmp2_i32);
+ gen_helper_fnstsw(cpu_tmp2_i32, cpu_env);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_st_T0_A0(OT_WORD + s->mem_index);
break;
@@ -5709,25 +5766,25 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fbld_ST0(cpu_A0);
+ gen_helper_fbld_ST0(cpu_env, cpu_A0);
break;
case 0x3e: /* fbstp */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fbst_ST0(cpu_A0);
- gen_helper_fpop();
+ gen_helper_fbst_ST0(cpu_env, cpu_A0);
+ gen_helper_fpop(cpu_env);
break;
case 0x3d: /* fildll */
tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
(s->mem_index >> 2) - 1);
- gen_helper_fildll_ST0(cpu_tmp1_i64);
+ gen_helper_fildll_ST0(cpu_env, cpu_tmp1_i64);
break;
case 0x3f: /* fistpll */
- gen_helper_fistll_ST0(cpu_tmp1_i64);
+ gen_helper_fistll_ST0(cpu_tmp1_i64, cpu_env);
tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
(s->mem_index >> 2) - 1);
- gen_helper_fpop();
+ gen_helper_fpop(cpu_env);
break;
default:
goto illegal_op;
@@ -5738,13 +5795,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
switch(op) {
case 0x08: /* fld sti */
- gen_helper_fpush();
- gen_helper_fmov_ST0_STN(tcg_const_i32((opreg + 1) & 7));
+ gen_helper_fpush(cpu_env);
+ gen_helper_fmov_ST0_STN(cpu_env,
+ tcg_const_i32((opreg + 1) & 7));
break;
case 0x09: /* fxchg sti */
case 0x29: /* fxchg4 sti, undocumented op */
case 0x39: /* fxchg7 sti, undocumented op */
- gen_helper_fxchg_ST0_STN(tcg_const_i32(opreg));
+ gen_helper_fxchg_ST0_STN(cpu_env, tcg_const_i32(opreg));
break;
case 0x0a: /* grp d9/2 */
switch(rm) {
@@ -5753,7 +5811,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fwait();
+ gen_helper_fwait(cpu_env);
break;
default:
goto illegal_op;
@@ -5762,17 +5820,17 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0x0c: /* grp d9/4 */
switch(rm) {
case 0: /* fchs */
- gen_helper_fchs_ST0();
+ gen_helper_fchs_ST0(cpu_env);
break;
case 1: /* fabs */
- gen_helper_fabs_ST0();
+ gen_helper_fabs_ST0(cpu_env);
break;
case 4: /* ftst */
- gen_helper_fldz_FT0();
- gen_helper_fcom_ST0_FT0();
+ gen_helper_fldz_FT0(cpu_env);
+ gen_helper_fcom_ST0_FT0(cpu_env);
break;
case 5: /* fxam */
- gen_helper_fxam_ST0();
+ gen_helper_fxam_ST0(cpu_env);
break;
default:
goto illegal_op;
@@ -5782,32 +5840,32 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
{
switch(rm) {
case 0:
- gen_helper_fpush();
- gen_helper_fld1_ST0();
+ gen_helper_fpush(cpu_env);
+ gen_helper_fld1_ST0(cpu_env);
break;
case 1:
- gen_helper_fpush();
- gen_helper_fldl2t_ST0();
+ gen_helper_fpush(cpu_env);
+ gen_helper_fldl2t_ST0(cpu_env);
break;
case 2:
- gen_helper_fpush();
- gen_helper_fldl2e_ST0();
+ gen_helper_fpush(cpu_env);
+ gen_helper_fldl2e_ST0(cpu_env);
break;
case 3:
- gen_helper_fpush();
- gen_helper_fldpi_ST0();
+ gen_helper_fpush(cpu_env);
+ gen_helper_fldpi_ST0(cpu_env);
break;
case 4:
- gen_helper_fpush();
- gen_helper_fldlg2_ST0();
+ gen_helper_fpush(cpu_env);
+ gen_helper_fldlg2_ST0(cpu_env);
break;
case 5:
- gen_helper_fpush();
- gen_helper_fldln2_ST0();
+ gen_helper_fpush(cpu_env);
+ gen_helper_fldln2_ST0(cpu_env);
break;
case 6:
- gen_helper_fpush();
- gen_helper_fldz_ST0();
+ gen_helper_fpush(cpu_env);
+ gen_helper_fldz_ST0(cpu_env);
break;
default:
goto illegal_op;
@@ -5817,58 +5875,58 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0x0e: /* grp d9/6 */
switch(rm) {
case 0: /* f2xm1 */
- gen_helper_f2xm1();
+ gen_helper_f2xm1(cpu_env);
break;
case 1: /* fyl2x */
- gen_helper_fyl2x();
+ gen_helper_fyl2x(cpu_env);
break;
case 2: /* fptan */
- gen_helper_fptan();
+ gen_helper_fptan(cpu_env);
break;
case 3: /* fpatan */
- gen_helper_fpatan();
+ gen_helper_fpatan(cpu_env);
break;
case 4: /* fxtract */
- gen_helper_fxtract();
+ gen_helper_fxtract(cpu_env);
break;
case 5: /* fprem1 */
- gen_helper_fprem1();
+ gen_helper_fprem1(cpu_env);
break;
case 6: /* fdecstp */
- gen_helper_fdecstp();
+ gen_helper_fdecstp(cpu_env);
break;
default:
case 7: /* fincstp */
- gen_helper_fincstp();
+ gen_helper_fincstp(cpu_env);
break;
}
break;
case 0x0f: /* grp d9/7 */
switch(rm) {
case 0: /* fprem */
- gen_helper_fprem();
+ gen_helper_fprem(cpu_env);
break;
case 1: /* fyl2xp1 */
- gen_helper_fyl2xp1();
+ gen_helper_fyl2xp1(cpu_env);
break;
case 2: /* fsqrt */
- gen_helper_fsqrt();
+ gen_helper_fsqrt(cpu_env);
break;
case 3: /* fsincos */
- gen_helper_fsincos();
+ gen_helper_fsincos(cpu_env);
break;
case 5: /* fscale */
- gen_helper_fscale();
+ gen_helper_fscale(cpu_env);
break;
case 4: /* frndint */
- gen_helper_frndint();
+ gen_helper_frndint(cpu_env);
break;
case 6: /* fsin */
- gen_helper_fsin();
+ gen_helper_fsin(cpu_env);
break;
default:
case 7: /* fcos */
- gen_helper_fcos();
+ gen_helper_fcos(cpu_env);
break;
}
break;
@@ -5882,32 +5940,32 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (op >= 0x20) {
gen_helper_fp_arith_STN_ST0(op1, opreg);
if (op >= 0x30)
- gen_helper_fpop();
+ gen_helper_fpop(cpu_env);
} else {
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
gen_helper_fp_arith_ST0_FT0(op1);
}
}
break;
case 0x02: /* fcom */
case 0x22: /* fcom2, undocumented op */
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
- gen_helper_fcom_ST0_FT0();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fcom_ST0_FT0(cpu_env);
break;
case 0x03: /* fcomp */
case 0x23: /* fcomp3, undocumented op */
case 0x32: /* fcomp5, undocumented op */
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
- gen_helper_fcom_ST0_FT0();
- gen_helper_fpop();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fcom_ST0_FT0(cpu_env);
+ gen_helper_fpop(cpu_env);
break;
case 0x15: /* da/5 */
switch(rm) {
case 1: /* fucompp */
- gen_helper_fmov_FT0_STN(tcg_const_i32(1));
- gen_helper_fucom_ST0_FT0();
- gen_helper_fpop();
- gen_helper_fpop();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(1));
+ gen_helper_fucom_ST0_FT0(cpu_env);
+ gen_helper_fpop(cpu_env);
+ gen_helper_fpop(cpu_env);
break;
default:
goto illegal_op;
@@ -5920,10 +5978,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 1: /* fdisi (287 only, just do nop here) */
break;
case 2: /* fclex */
- gen_helper_fclex();
+ gen_helper_fclex(cpu_env);
break;
case 3: /* fninit */
- gen_helper_fninit();
+ gen_helper_fninit(cpu_env);
break;
case 4: /* fsetpm (287 only, just do nop here) */
break;
@@ -5934,59 +5992,59 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0x1d: /* fucomi */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
- gen_helper_fucomi_ST0_FT0();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fucomi_ST0_FT0(cpu_env);
s->cc_op = CC_OP_EFLAGS;
break;
case 0x1e: /* fcomi */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
- gen_helper_fcomi_ST0_FT0();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fcomi_ST0_FT0(cpu_env);
s->cc_op = CC_OP_EFLAGS;
break;
case 0x28: /* ffree sti */
- gen_helper_ffree_STN(tcg_const_i32(opreg));
+ gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg));
break;
case 0x2a: /* fst sti */
- gen_helper_fmov_STN_ST0(tcg_const_i32(opreg));
+ gen_helper_fmov_STN_ST0(cpu_env, tcg_const_i32(opreg));
break;
case 0x2b: /* fstp sti */
case 0x0b: /* fstp1 sti, undocumented op */
case 0x3a: /* fstp8 sti, undocumented op */
case 0x3b: /* fstp9 sti, undocumented op */
- gen_helper_fmov_STN_ST0(tcg_const_i32(opreg));
- gen_helper_fpop();
+ gen_helper_fmov_STN_ST0(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fpop(cpu_env);
break;
case 0x2c: /* fucom st(i) */
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
- gen_helper_fucom_ST0_FT0();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fucom_ST0_FT0(cpu_env);
break;
case 0x2d: /* fucomp st(i) */
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
- gen_helper_fucom_ST0_FT0();
- gen_helper_fpop();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fucom_ST0_FT0(cpu_env);
+ gen_helper_fpop(cpu_env);
break;
case 0x33: /* de/3 */
switch(rm) {
case 1: /* fcompp */
- gen_helper_fmov_FT0_STN(tcg_const_i32(1));
- gen_helper_fcom_ST0_FT0();
- gen_helper_fpop();
- gen_helper_fpop();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(1));
+ gen_helper_fcom_ST0_FT0(cpu_env);
+ gen_helper_fpop(cpu_env);
+ gen_helper_fpop(cpu_env);
break;
default:
goto illegal_op;
}
break;
case 0x38: /* ffreep sti, undocumented op */
- gen_helper_ffree_STN(tcg_const_i32(opreg));
- gen_helper_fpop();
+ gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fpop(cpu_env);
break;
case 0x3c: /* df/4 */
switch(rm) {
case 0:
- gen_helper_fnstsw(cpu_tmp2_i32);
+ gen_helper_fnstsw(cpu_tmp2_i32, cpu_env);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
gen_op_mov_reg_T0(OT_WORD, R_EAX);
break;
@@ -5997,17 +6055,17 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0x3d: /* fucomip */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
- gen_helper_fucomi_ST0_FT0();
- gen_helper_fpop();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fucomi_ST0_FT0(cpu_env);
+ gen_helper_fpop(cpu_env);
s->cc_op = CC_OP_EFLAGS;
break;
case 0x3e: /* fcomip */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
- gen_helper_fcomi_ST0_FT0();
- gen_helper_fpop();
+ gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
+ gen_helper_fcomi_ST0_FT0(cpu_env);
+ gen_helper_fpop(cpu_env);
s->cc_op = CC_OP_EFLAGS;
break;
case 0x10 ... 0x13: /* fcmovxx */
@@ -6023,7 +6081,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1);
l1 = gen_new_label();
gen_jcc1(s, s->cc_op, op1, l1);
- gen_helper_fmov_ST0_STN(tcg_const_i32(opreg));
+ gen_helper_fmov_ST0_STN(cpu_env, tcg_const_i32(opreg));
gen_set_label(l1);
}
break;
@@ -6153,7 +6211,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE;
else
ot = dflag ? OT_LONG : OT_WORD;
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
gen_op_movl_T0_im(val);
gen_check_io(s, ot, pc_start - s->cs_base,
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
@@ -6173,7 +6231,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE;
else
ot = dflag ? OT_LONG : OT_WORD;
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
gen_op_movl_T0_im(val);
gen_check_io(s, ot, pc_start - s->cs_base,
svm_is_rep(prefixes));
@@ -6235,7 +6293,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
/************************/
/* control */
case 0xc2: /* ret im */
- val = ldsw_code(s->pc);
+ val = cpu_ldsw_code(cpu_single_env, s->pc);
s->pc += 2;
gen_pop_T0(s);
if (CODE64(s) && s->dflag)
@@ -6255,14 +6313,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_eob(s);
break;
case 0xca: /* lret im */
- val = ldsw_code(s->pc);
+ val = cpu_ldsw_code(cpu_single_env, s->pc);
s->pc += 2;
do_lret:
if (s->pe && !s->vm86) {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_lret_protected(tcg_const_i32(s->dflag),
+ gen_helper_lret_protected(cpu_env, tcg_const_i32(s->dflag),
tcg_const_i32(val));
} else {
gen_stack_A0(s);
@@ -6289,20 +6347,20 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
if (!s->pe) {
/* real mode */
- gen_helper_iret_real(tcg_const_i32(s->dflag));
+ gen_helper_iret_real(cpu_env, tcg_const_i32(s->dflag));
s->cc_op = CC_OP_EFLAGS;
} else if (s->vm86) {
if (s->iopl != 3) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
- gen_helper_iret_real(tcg_const_i32(s->dflag));
+ gen_helper_iret_real(cpu_env, tcg_const_i32(s->dflag));
s->cc_op = CC_OP_EFLAGS;
}
} else {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_iret_protected(tcg_const_i32(s->dflag),
+ gen_helper_iret_protected(cpu_env, tcg_const_i32(s->dflag),
tcg_const_i32(s->pc - s->cs_base));
s->cc_op = CC_OP_EFLAGS;
}
@@ -6390,7 +6448,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
case 0x190 ... 0x19f: /* setcc Gv */
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
gen_setcc(s, b);
gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
break;
@@ -6400,7 +6458,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
TCGv t0;
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
t0 = tcg_temp_local_new();
@@ -6440,7 +6498,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
} else {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_read_eflags(cpu_T[0]);
+ gen_helper_read_eflags(cpu_T[0], cpu_env);
gen_push_T0(s);
}
break;
@@ -6452,28 +6510,46 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_pop_T0(s);
if (s->cpl == 0) {
if (s->dflag) {
- gen_helper_write_eflags(cpu_T[0],
- tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK)));
+ gen_helper_write_eflags(cpu_env, cpu_T[0],
+ tcg_const_i32((TF_MASK | AC_MASK |
+ ID_MASK | NT_MASK |
+ IF_MASK |
+ IOPL_MASK)));
} else {
- gen_helper_write_eflags(cpu_T[0],
- tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK) & 0xffff));
+ gen_helper_write_eflags(cpu_env, cpu_T[0],
+ tcg_const_i32((TF_MASK | AC_MASK |
+ ID_MASK | NT_MASK |
+ IF_MASK | IOPL_MASK)
+ & 0xffff));
}
} else {
if (s->cpl <= s->iopl) {
if (s->dflag) {
- gen_helper_write_eflags(cpu_T[0],
- tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK)));
+ gen_helper_write_eflags(cpu_env, cpu_T[0],
+ tcg_const_i32((TF_MASK |
+ AC_MASK |
+ ID_MASK |
+ NT_MASK |
+ IF_MASK)));
} else {
- gen_helper_write_eflags(cpu_T[0],
- tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK) & 0xffff));
+ gen_helper_write_eflags(cpu_env, cpu_T[0],
+ tcg_const_i32((TF_MASK |
+ AC_MASK |
+ ID_MASK |
+ NT_MASK |
+ IF_MASK)
+ & 0xffff));
}
} else {
if (s->dflag) {
- gen_helper_write_eflags(cpu_T[0],
- tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK)));
+ gen_helper_write_eflags(cpu_env, cpu_T[0],
+ tcg_const_i32((TF_MASK | AC_MASK |
+ ID_MASK | NT_MASK)));
} else {
- gen_helper_write_eflags(cpu_T[0],
- tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff));
+ gen_helper_write_eflags(cpu_env, cpu_T[0],
+ tcg_const_i32((TF_MASK | AC_MASK |
+ ID_MASK | NT_MASK)
+ & 0xffff));
}
}
}
@@ -6540,7 +6616,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
/* bit operations */
case 0x1ba: /* bt/bts/btr/btc Gv, im */
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
op = (modrm >> 3) & 7;
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
@@ -6552,7 +6628,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_mov_TN_reg(ot, 0, rm);
}
/* load shift */
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
gen_op_movl_T1_im(val);
if (op < 4)
goto illegal_op;
@@ -6571,7 +6647,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
op = 3;
do_btx:
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
@@ -6632,7 +6708,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
TCGv t0;
ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
gen_ldst_modrm(s,modrm, ot, OR_TMP0, 0);
gen_extu(ot, cpu_T[0]);
@@ -6674,7 +6750,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
goto illegal_op;
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_daa();
+ gen_helper_daa(cpu_env);
s->cc_op = CC_OP_EFLAGS;
break;
case 0x2f: /* das */
@@ -6682,7 +6758,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
goto illegal_op;
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_das();
+ gen_helper_das(cpu_env);
s->cc_op = CC_OP_EFLAGS;
break;
case 0x37: /* aaa */
@@ -6690,7 +6766,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
goto illegal_op;
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_aaa();
+ gen_helper_aaa(cpu_env);
s->cc_op = CC_OP_EFLAGS;
break;
case 0x3f: /* aas */
@@ -6698,25 +6774,25 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
goto illegal_op;
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_helper_aas();
+ gen_helper_aas(cpu_env);
s->cc_op = CC_OP_EFLAGS;
break;
case 0xd4: /* aam */
if (CODE64(s))
goto illegal_op;
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
if (val == 0) {
gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base);
} else {
- gen_helper_aam(tcg_const_i32(val));
+ gen_helper_aam(cpu_env, tcg_const_i32(val));
s->cc_op = CC_OP_LOGICB;
}
break;
case 0xd5: /* aad */
if (CODE64(s))
goto illegal_op;
- val = ldub_code(s->pc++);
- gen_helper_aad(tcg_const_i32(val));
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
+ gen_helper_aad(cpu_env, tcg_const_i32(val));
s->cc_op = CC_OP_LOGICB;
break;
/************************/
@@ -6742,14 +6818,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fwait();
+ gen_helper_fwait(cpu_env);
}
break;
case 0xcc: /* int3 */
gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
break;
case 0xcd: /* int N */
- val = ldub_code(s->pc++);
+ val = cpu_ldub_code(cpu_single_env, s->pc++);
if (s->vm86 && s->iopl != 3) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
@@ -6762,7 +6838,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_into(tcg_const_i32(s->pc - pc_start));
+ gen_helper_into(cpu_env, tcg_const_i32(s->pc - pc_start));
break;
#ifdef WANT_ICEBP
case 0xf1: /* icebp (undocumented, exits to external debugger) */
@@ -6779,13 +6855,13 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 0xfa: /* cli */
if (!s->vm86) {
if (s->cpl <= s->iopl) {
- gen_helper_cli();
+ gen_helper_cli(cpu_env);
} else {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
}
} else {
if (s->iopl == 3) {
- gen_helper_cli();
+ gen_helper_cli(cpu_env);
} else {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
}
@@ -6795,12 +6871,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (!s->vm86) {
if (s->cpl <= s->iopl) {
gen_sti:
- gen_helper_sti();
+ gen_helper_sti(cpu_env);
/* interruptions are enabled only the first insn after sti */
/* If several instructions disable interrupts, only the
_first_ does it */
if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_helper_set_inhibit_irq();
+ gen_helper_set_inhibit_irq(cpu_env);
/* give a chance to handle pending irqs */
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
@@ -6819,7 +6895,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (CODE64(s))
goto illegal_op;
ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = (modrm >> 3) & 7;
mod = (modrm >> 6) & 3;
if (mod == 3)
@@ -6828,10 +6904,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- if (ot == OT_WORD)
- gen_helper_boundw(cpu_A0, cpu_tmp2_i32);
- else
- gen_helper_boundl(cpu_A0, cpu_tmp2_i32);
+ if (ot == OT_WORD) {
+ gen_helper_boundw(cpu_env, cpu_A0, cpu_tmp2_i32);
+ } else {
+ gen_helper_boundl(cpu_env, cpu_A0, cpu_tmp2_i32);
+ }
break;
case 0x1c8 ... 0x1cf: /* bswap reg */
reg = (b & 7) | REX_B(s);
@@ -6919,9 +6996,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
if (b & 2) {
- gen_helper_rdmsr();
+ gen_helper_rdmsr(cpu_env);
} else {
- gen_helper_wrmsr();
+ gen_helper_wrmsr(cpu_env);
}
}
break;
@@ -6931,7 +7008,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_jmp_im(pc_start - s->cs_base);
if (use_icount)
gen_io_start();
- gen_helper_rdtsc();
+ gen_helper_rdtsc(cpu_env);
if (use_icount) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
@@ -6941,7 +7018,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_rdpmc();
+ gen_helper_rdpmc(cpu_env);
break;
case 0x134: /* sysenter */
/* For Intel SYSENTER is valid on 64-bit */
@@ -6952,7 +7029,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
} else {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_sysenter();
+ gen_helper_sysenter(cpu_env);
gen_eob(s);
}
break;
@@ -6965,7 +7042,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
} else {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_sysexit(tcg_const_i32(dflag));
+ gen_helper_sysexit(cpu_env, tcg_const_i32(dflag));
gen_eob(s);
}
break;
@@ -6974,7 +7051,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
/* XXX: is it usable in real mode ? */
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_syscall(tcg_const_i32(s->pc - pc_start));
+ gen_helper_syscall(cpu_env, tcg_const_i32(s->pc - pc_start));
gen_eob(s);
break;
case 0x107: /* sysret */
@@ -6983,7 +7060,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
} else {
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_sysret(tcg_const_i32(s->dflag));
+ gen_helper_sysret(cpu_env, tcg_const_i32(s->dflag));
/* condition codes are modified only in long mode */
if (s->lma)
s->cc_op = CC_OP_EFLAGS;
@@ -6995,7 +7072,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_cpuid();
+ gen_helper_cpuid(cpu_env);
break;
case 0xf4: /* hlt */
if (s->cpl != 0) {
@@ -7004,12 +7081,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_hlt(tcg_const_i32(s->pc - pc_start));
+ gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
s->is_jmp = DISAS_TB_JUMP;
}
break;
case 0x100:
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
switch(op) {
@@ -7033,7 +7110,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_lldt(cpu_tmp2_i32);
+ gen_helper_lldt(cpu_env, cpu_tmp2_i32);
}
break;
case 1: /* str */
@@ -7056,7 +7133,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_ltr(cpu_tmp2_i32);
+ gen_helper_ltr(cpu_env, cpu_tmp2_i32);
}
break;
case 4: /* verr */
@@ -7066,10 +7143,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- if (op == 4)
- gen_helper_verr(cpu_T[0]);
- else
- gen_helper_verw(cpu_T[0]);
+ if (op == 4) {
+ gen_helper_verr(cpu_env, cpu_T[0]);
+ } else {
+ gen_helper_verw(cpu_env, cpu_T[0]);
+ }
s->cc_op = CC_OP_EFLAGS;
break;
default:
@@ -7077,7 +7155,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
}
break;
case 0x101:
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
rm = modrm & 7;
@@ -7116,7 +7194,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_andl_A0_ffff();
}
gen_add_A0_ds_seg(s);
- gen_helper_monitor(cpu_A0);
+ gen_helper_monitor(cpu_env, cpu_A0);
break;
case 1: /* mwait */
if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
@@ -7124,7 +7202,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
goto illegal_op;
gen_update_cc_op(s);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_mwait(tcg_const_i32(s->pc - pc_start));
+ gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start));
gen_eob(s);
break;
default:
@@ -7156,7 +7234,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break;
} else {
- gen_helper_vmrun(tcg_const_i32(s->aflag),
+ gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag),
tcg_const_i32(s->pc - pc_start));
tcg_gen_exit_tb(0);
s->is_jmp = DISAS_TB_JUMP;
@@ -7165,7 +7243,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
case 1: /* VMMCALL */
if (!(s->flags & HF_SVME_MASK))
goto illegal_op;
- gen_helper_vmmcall();
+ gen_helper_vmmcall(cpu_env);
break;
case 2: /* VMLOAD */
if (!(s->flags & HF_SVME_MASK) || !s->pe)
@@ -7174,7 +7252,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break;
} else {
- gen_helper_vmload(tcg_const_i32(s->aflag));
+ gen_helper_vmload(cpu_env, tcg_const_i32(s->aflag));
}
break;
case 3: /* VMSAVE */
@@ -7184,7 +7262,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break;
} else {
- gen_helper_vmsave(tcg_const_i32(s->aflag));
+ gen_helper_vmsave(cpu_env, tcg_const_i32(s->aflag));
}
break;
case 4: /* STGI */
@@ -7196,7 +7274,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break;
} else {
- gen_helper_stgi();
+ gen_helper_stgi(cpu_env);
}
break;
case 5: /* CLGI */
@@ -7206,7 +7284,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break;
} else {
- gen_helper_clgi();
+ gen_helper_clgi(cpu_env);
}
break;
case 6: /* SKINIT */
@@ -7214,7 +7292,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
!(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) ||
!s->pe)
goto illegal_op;
- gen_helper_skinit();
+ gen_helper_skinit(cpu_env);
break;
case 7: /* INVLPGA */
if (!(s->flags & HF_SVME_MASK) || !s->pe)
@@ -7223,7 +7301,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break;
} else {
- gen_helper_invlpga(tcg_const_i32(s->aflag));
+ gen_helper_invlpga(cpu_env, tcg_const_i32(s->aflag));
}
break;
default:
@@ -7264,7 +7342,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
} else {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
- gen_helper_lmsw(cpu_T[0]);
+ gen_helper_lmsw(cpu_env, cpu_T[0]);
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
}
@@ -7278,7 +7356,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_helper_invlpg(cpu_A0);
+ gen_helper_invlpg(cpu_env, cpu_A0);
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
}
@@ -7313,7 +7391,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_jmp_im(pc_start - s->cs_base);
if (use_icount)
gen_io_start();
- gen_helper_rdtscp();
+ gen_helper_rdtscp(cpu_env);
if (use_icount) {
gen_io_end();
gen_jmp(s, s->pc - s->cs_base);
@@ -7344,7 +7422,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
/* d_ot is the size of destination */
d_ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
@@ -7376,7 +7454,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
t1 = tcg_temp_local_new();
t2 = tcg_temp_local_new();
ot = OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = (modrm >> 3) & 7;
mod = (modrm >> 6) & 3;
rm = modrm & 7;
@@ -7424,16 +7502,17 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (!s->pe || s->vm86)
goto illegal_op;
ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7) | rex_r;
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
t0 = tcg_temp_local_new();
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- if (b == 0x102)
- gen_helper_lar(t0, cpu_T[0]);
- else
- gen_helper_lsl(t0, cpu_T[0]);
+ if (b == 0x102) {
+ gen_helper_lar(t0, cpu_env, cpu_T[0]);
+ } else {
+ gen_helper_lsl(t0, cpu_env, cpu_T[0]);
+ }
tcg_gen_andi_tl(cpu_tmp0, cpu_cc_src, CC_Z);
label1 = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1);
@@ -7444,7 +7523,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
}
break;
case 0x118:
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
switch(op) {
@@ -7463,7 +7542,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
}
break;
case 0x119 ... 0x11f: /* nop (multi byte) */
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
gen_nop_modrm(s, modrm);
break;
case 0x120: /* mov reg, crN */
@@ -7471,9 +7550,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
- modrm = ldub_code(s->pc++);
- if ((modrm & 0xc0) != 0xc0)
- goto illegal_op;
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
+ /* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
+ * AMD documentation (24594.pdf) and testing of
+ * intel 386 and 486 processors all show that the mod bits
+ * are assumed to be 1's, regardless of actual values.
+ */
rm = (modrm & 7) | REX_B(s);
reg = ((modrm >> 3) & 7) | rex_r;
if (CODE64(s))
@@ -7495,11 +7577,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_jmp_im(pc_start - s->cs_base);
if (b & 2) {
gen_op_mov_TN_reg(ot, 0, rm);
- gen_helper_write_crN(tcg_const_i32(reg), cpu_T[0]);
+ gen_helper_write_crN(cpu_env, tcg_const_i32(reg),
+ cpu_T[0]);
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
} else {
- gen_helper_read_crN(cpu_T[0], tcg_const_i32(reg));
+ gen_helper_read_crN(cpu_T[0], cpu_env, tcg_const_i32(reg));
gen_op_mov_reg_T0(ot, rm);
}
break;
@@ -7513,9 +7596,12 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
- modrm = ldub_code(s->pc++);
- if ((modrm & 0xc0) != 0xc0)
- goto illegal_op;
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
+ /* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
+ * AMD documentation (24594.pdf) and testing of
+ * intel 386 and 486 processors all show that the mod bits
+ * are assumed to be 1's, regardless of actual values.
+ */
rm = (modrm & 7) | REX_B(s);
reg = ((modrm >> 3) & 7) | rex_r;
if (CODE64(s))
@@ -7528,7 +7614,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (b & 2) {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg);
gen_op_mov_TN_reg(ot, 0, rm);
- gen_helper_movl_drN_T0(tcg_const_i32(reg), cpu_T[0]);
+ gen_helper_movl_drN_T0(cpu_env, tcg_const_i32(reg), cpu_T[0]);
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
} else {
@@ -7543,7 +7629,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
- gen_helper_clts();
+ gen_helper_clts(cpu_env);
/* abort block because static cpu state changed */
gen_jmp_im(s->pc - s->cs_base);
gen_eob(s);
@@ -7554,7 +7640,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (!(s->cpuid_features & CPUID_SSE2))
goto illegal_op;
ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
@@ -7563,7 +7649,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_ldst_modrm(s, modrm, ot, reg, 1);
break;
case 0x1ae:
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
switch(op) {
@@ -7579,7 +7665,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fxsave(cpu_A0, tcg_const_i32((s->dflag == 2)));
+ gen_helper_fxsave(cpu_env, cpu_A0, tcg_const_i32((s->dflag == 2)));
break;
case 1: /* fxrstor */
if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
@@ -7593,7 +7679,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base);
- gen_helper_fxrstor(cpu_A0, tcg_const_i32((s->dflag == 2)));
+ gen_helper_fxrstor(cpu_env, cpu_A0,
+ tcg_const_i32((s->dflag == 2)));
break;
case 2: /* ldmxcsr */
case 3: /* stmxcsr */
@@ -7608,7 +7695,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (op == 2) {
gen_op_ld_T0_A0(OT_LONG + s->mem_index);
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- gen_helper_ldmxcsr(cpu_tmp2_i32);
+ gen_helper_ldmxcsr(cpu_env, cpu_tmp2_i32);
} else {
tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr));
gen_op_st_T0_A0(OT_LONG + s->mem_index);
@@ -7637,7 +7724,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
}
break;
case 0x10d: /* 3DNow! prefetch(w) */
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
@@ -7650,7 +7737,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
goto illegal_op;
gen_update_cc_op(s);
gen_jmp_im(s->pc - s->cs_base);
- gen_helper_rsm();
+ gen_helper_rsm(cpu_env);
gen_eob(s);
break;
case 0x1b8: /* SSE4.2 popcnt */
@@ -7660,7 +7747,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (!(s->cpuid_ext_features & CPUID_EXT_POPCNT))
goto illegal_op;
- modrm = ldub_code(s->pc++);
+ modrm = cpu_ldub_code(cpu_single_env, s->pc++);
reg = ((modrm >> 3) & 7);
if (s->prefix & PREFIX_DATA)
@@ -7671,7 +7758,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_QUAD;
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
- gen_helper_popcnt(cpu_T[0], cpu_T[0], tcg_const_i32(ot));
+ gen_helper_popcnt(cpu_T[0], cpu_env, cpu_T[0], tcg_const_i32(ot));
gen_op_mov_reg_T0(ot, reg);
s->cc_op = CC_OP_EFLAGS;
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 66037ac..e5bc93e 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -192,115 +192,98 @@ static inline uint64_t get_HILO (void)
return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
}
-static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
+static inline target_ulong set_HIT0_LO(uint64_t HILO)
{
+ target_ulong tmp;
env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
- arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+ tmp = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+ return tmp;
}
-static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
+static inline target_ulong set_HI_LOT0(uint64_t HILO)
{
- arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+ target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+ return tmp;
}
/* Multiplication variants of the vr54xx. */
target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0(0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
}
target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0(0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
}
target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0((int64_t)get_HILO() + (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
}
target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO((int64_t)get_HILO() + (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
}
target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0((uint64_t)get_HILO() + (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
}
target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO((uint64_t)get_HILO() + (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
}
target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0((int64_t)get_HILO() - (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
}
target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO((int64_t)get_HILO() - (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
}
target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0((uint64_t)get_HILO() - (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
}
target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO((uint64_t)get_HILO() - (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
}
target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
-
- return arg1;
+ return set_HIT0_LO((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
}
target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-
- return arg1;
+ return set_HIT0_LO((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
}
target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO(0 - (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
}
target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO(0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
}
#ifdef TARGET_MIPS64
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 47daf85..b293419 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -5933,6 +5933,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt,
{
const char *opn = "ldst";
+ check_cp0_enabled(ctx);
switch (opc) {
case OPC_MFC0:
if (rt == 0) {
@@ -6805,7 +6806,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i32 fp1 = tcg_temp_new_i32();
gen_load_fpr32(fp0, fs);
- gen_load_fpr32(fp1, fd);
+ gen_load_fpr32(fp1, ft);
gen_helper_float_recip2_s(fp0, fp0, fp1);
tcg_temp_free_i32(fp1);
gen_store_fpr32(fp0, fd);
@@ -6900,7 +6901,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
gen_load_fpr32(fp32_0, fs);
gen_load_fpr32(fp32_1, ft);
- tcg_gen_concat_i32_i64(fp64, fp32_0, fp32_1);
+ tcg_gen_concat_i32_i64(fp64, fp32_1, fp32_0);
tcg_temp_free_i32(fp32_1);
tcg_temp_free_i32(fp32_0);
gen_store_fpr64(ctx, fp64, fd);
@@ -7543,7 +7544,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i64 fp1 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, fs);
- gen_load_fpr64(ctx, fp1, fd);
+ gen_load_fpr64(ctx, fp1, ft);
gen_helper_float_recip2_ps(fp0, fp0, fp1);
tcg_temp_free_i64(fp1);
gen_store_fpr64(ctx, fp0, fd);
@@ -7742,8 +7743,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
} else if (index == 0) {
gen_load_gpr(t0, base);
} else {
- gen_load_gpr(t0, index);
- gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
+ gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[index]);
}
/* Don't do NOP if destination is zero: we must perform the actual
memory access. */
@@ -8112,7 +8112,11 @@ gen_rdhwr (CPUMIPSState *env, DisasContext *ctx, int rt, int rd)
{
TCGv t0;
+#if !defined(CONFIG_USER_ONLY)
+ /* The Linux kernel will emulate rdhwr if it's not supported natively.
+ Therefore only check the ISA in system mode. */
check_insn(env, ctx, ISA_MIPS32R2);
+#endif
t0 = tcg_temp_new();
switch (rd) {
@@ -10027,7 +10031,7 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
const char *opn = "ldst_pair";
TCGv t0, t1;
- if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31 || rd == base) {
+ if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31) {
generate_exception(ctx, EXCP_RI);
return;
}
@@ -10039,6 +10043,10 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
switch (opc) {
case LWP:
+ if (rd == base) {
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
save_cpu_state(ctx, 0);
op_ld_lw(t1, t0, ctx);
gen_store_gpr(t1, rd);
@@ -10060,6 +10068,10 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
break;
#ifdef TARGET_MIPS64
case LDP:
+ if (rd == base) {
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
save_cpu_state(ctx, 0);
op_ld_ld(t1, t0, ctx);
gen_store_gpr(t1, rd);
@@ -10118,6 +10130,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
#ifndef CONFIG_USER_ONLY
case MFC0:
case MFC0 + 32:
+ check_cp0_enabled(ctx);
if (rt == 0) {
/* Treat as NOP. */
break;
@@ -10126,6 +10139,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
break;
case MTC0:
case MTC0 + 32:
+ check_cp0_enabled(ctx);
{
TCGv t0 = tcg_temp_new();
@@ -10222,10 +10236,12 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
case 0x05:
switch (minor) {
case RDPGPR:
+ check_cp0_enabled(ctx);
check_insn(env, ctx, ISA_MIPS32R2);
gen_load_srsgpr(rt, rs);
break;
case WRPGPR:
+ check_cp0_enabled(ctx);
check_insn(env, ctx, ISA_MIPS32R2);
gen_store_srsgpr(rt, rs);
break;
@@ -10266,6 +10282,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
case 0x1d:
switch (minor) {
case DI:
+ check_cp0_enabled(ctx);
{
TCGv t0 = tcg_temp_new();
@@ -10278,6 +10295,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
}
break;
case EI:
+ check_cp0_enabled(ctx);
{
TCGv t0 = tcg_temp_new();
@@ -10758,6 +10776,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
minor = (ctx->opcode >> 12) & 0xf;
switch (minor) {
case CACHE:
+ check_cp0_enabled(ctx);
/* Treat as no-op. */
break;
case LWC2:
@@ -12208,6 +12227,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
gen_st_cond(ctx, op, rt, rs, imm);
break;
case OPC_CACHE:
+ check_cp0_enabled(ctx);
check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
/* Treat as NOP. */
break;
@@ -12768,8 +12788,9 @@ void cpu_state_reset(CPUMIPSState *env)
#if defined(CONFIG_USER_ONLY)
env->hflags = MIPS_HFLAG_UM;
- /* Enable access to the SYNCI_Step register. */
- env->CP0_HWREna |= (1 << 1);
+ /* Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
+ hardware registers. */
+ env->CP0_HWREna |= 0x0000000F;
if (env->CP0_Config1 & (1 << CP0C1_FP)) {
env->hflags |= MIPS_HFLAG_FPU;
}
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 829e180..a31d278 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -766,7 +766,7 @@ int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run)
dprintf("handle PAPR hypercall\n");
run->papr_hcall.ret = spapr_hypercall(env, run->papr_hcall.nr,
run->papr_hcall.args);
- ret = 1;
+ ret = 0;
break;
#endif
default:
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 91eb7a0..ac915cc 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6530,7 +6530,7 @@ static void glue(gen_, name)(DisasContext *ctx) \
ra = gen_avr_ptr(rA(ctx->opcode)); \
rb = gen_avr_ptr(rB(ctx->opcode)); \
rd = gen_avr_ptr(rD(ctx->opcode)); \
- gen_helper_##name(rd, cpu_env, ra, rb); \
+ gen_helper_##name(cpu_env, rd, ra, rb); \
tcg_temp_free_ptr(ra); \
tcg_temp_free_ptr(rb); \
tcg_temp_free_ptr(rd); \
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 5742229..fba2b42 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -27,6 +27,7 @@
#include "gdbstub.h"
#include <kvm.h>
#include "kvm_ppc.h"
+#include "arch_init.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@@ -10345,6 +10346,31 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
}
}
+CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
+{
+ CpuDefinitionInfoList *cpu_list = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
+ CpuDefinitionInfoList *entry;
+ CpuDefinitionInfo *info;
+
+ if (!ppc_cpu_usable(&ppc_defs[i])) {
+ continue;
+ }
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(ppc_defs[i].name);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = cpu_list;
+ cpu_list = entry;
+ }
+
+ return cpu_list;
+}
+
/* CPUClass::reset() */
static void ppc_cpu_reset(CPUState *s)
{
diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs
index 262747f..80be3bb 100644
--- a/target-s390x/Makefile.objs
+++ b/target-s390x/Makefile.objs
@@ -1,4 +1,4 @@
-obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index c30ac3a..18ac6e3 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -320,6 +320,9 @@ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
void s390_add_running_cpu(CPUS390XState *env);
unsigned s390_del_running_cpu(CPUS390XState *env);
+/* service interrupts are floating therefore we must not pass an cpustate */
+void s390_sclp_extint(uint32_t parm);
+
/* from s390-virtio-bus */
extern const target_phys_addr_t virtio_size;
diff --git a/target-s390x/interrupt.c b/target-s390x/interrupt.c
new file mode 100644
index 0000000..c1b034f
--- /dev/null
+++ b/target-s390x/interrupt.c
@@ -0,0 +1,29 @@
+/*
+ * QEMU S/390 Interrupt support
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * 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 "cpu.h"
+#include "kvm.h"
+
+#if !defined(CONFIG_USER_ONLY)
+/* service interrupts are floating therefore we must not pass an cpustate */
+void s390_sclp_extint(uint32_t parm)
+{
+ S390CPU *dummy_cpu = s390_cpu_addr2state(0);
+ CPUS390XState *env = &dummy_cpu->env;
+
+ if (kvm_enabled()) {
+#ifdef CONFIG_KVM
+ kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE, parm, 0, 1);
+#endif
+ } else {
+ env->psw.addr += 4;
+ cpu_inject_ext(env, EXT_SERVICE, parm, 0);
+ }
+}
+#endif
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 47008c2..07edf93 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -273,9 +273,10 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run,
code = env->regs[(ipbh0 & 0xf0) >> 4];
r = sclp_service_call(env, sccb, code);
- if (r) {
- setcc(env, 3);
+ if (r < 0) {
+ enter_pgmcheck(env, -r);
}
+ setcc(env, r);
return 0;
}
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 7b72473..abc35dd 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -19,6 +19,8 @@
*/
#include "cpu.h"
+#include "memory.h"
+#include "cputlb.h"
#include "dyngen-exec.h"
#include "host-utils.h"
#include "helper.h"
@@ -2360,12 +2362,9 @@ static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
}
}
-static void ext_interrupt(CPUS390XState *env, int type, uint32_t param,
- uint64_t param64)
-{
- cpu_inject_ext(env, type, param, param64);
-}
-
+/*
+ * ret < 0 indicates program check, ret = 0,1,2,3 -> cc
+ */
int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
{
int r = 0;
@@ -2375,10 +2374,12 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
#endif
+ /* basic checks */
+ if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) {
+ return -PGM_ADDRESSING;
+ }
if (sccb & ~0x7ffffff8ul) {
- fprintf(stderr, "KVM: invalid sccb address 0x%x\n", sccb);
- r = -1;
- goto out;
+ return -PGM_SPECIFICATION;
}
switch(code) {
@@ -2391,36 +2392,30 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
stb_phys(sccb + SCP_INCREMENT, 1 << shift);
stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
- if (kvm_enabled()) {
-#ifdef CONFIG_KVM
- kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
- sccb & ~3, 0, 1);
-#endif
- } else {
- env->psw.addr += 4;
- ext_interrupt(env, EXT_SERVICE, sccb & ~3, 0);
- }
+ s390_sclp_extint(sccb & ~3);
break;
default:
#ifdef DEBUG_HELPER
printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
#endif
- r = -1;
+ r = 3;
break;
}
-out:
return r;
}
/* SCLP service call */
uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
{
- if (sclp_service_call(env, r1, r2)) {
- return 3;
- }
+ int r;
- return 0;
+ r = sclp_service_call(env, r1, r2);
+ if (r < 0) {
+ program_interrupt(env, -r, 4);
+ return 0;
+ }
+ return r;
}
/* DIAG */
diff --git a/target-unicore32/Makefile.objs b/target-unicore32/Makefile.objs
index 2e0e093..777f01f 100644
--- a/target-unicore32/Makefile.objs
+++ b/target-unicore32/Makefile.objs
@@ -1,4 +1,6 @@
obj-y += translate.o op_helper.o helper.o cpu.o
-obj-$(CONFIG_SOFTMMU) += machine.o
+obj-y += ucf64_helper.o
+
+obj-$(CONFIG_SOFTMMU) += machine.o softmmu.o
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index de63f58..3425bbe 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -1,7 +1,7 @@
/*
* QEMU UniCore32 CPU
*
- * Copyright (c) 2010-2011 GUAN Xue-tao
+ * Copyright (c) 2010-2012 Guan Xuetao
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This program is free software; you can redistribute it and/or modify
@@ -32,13 +32,16 @@ static void unicore_ii_cpu_initfn(Object *obj)
UniCore32CPU *cpu = UNICORE32_CPU(obj);
CPUUniCore32State *env = &cpu->env;
- env->cp0.c0_cpuid = 0x40010863;
+ env->cp0.c0_cpuid = 0x4d000863;
+ env->cp0.c0_cachetype = 0x0d152152;
+ env->cp0.c1_sys = 0x2000;
+ env->cp0.c2_base = 0x0;
+ env->cp0.c3_faultstatus = 0x0;
+ env->cp0.c4_faultaddr = 0x0;
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
set_feature(env, UC32_HWCAP_CMOV);
set_feature(env, UC32_HWCAP_UCF64);
- env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
- env->cp0.c0_cachetype = 0x1dd20d2;
- env->cp0.c1_sys = 0x00090078;
}
static void uc32_any_cpu_initfn(Object *obj)
@@ -47,6 +50,7 @@ static void uc32_any_cpu_initfn(Object *obj)
CPUUniCore32State *env = &cpu->env;
env->cp0.c0_cpuid = 0xffffffff;
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
set_feature(env, UC32_HWCAP_CMOV);
set_feature(env, UC32_HWCAP_UCF64);
@@ -65,8 +69,13 @@ static void uc32_cpu_initfn(Object *obj)
cpu_exec_init(env);
env->cpu_model_str = object_get_typename(obj);
+#ifdef CONFIG_USER_ONLY
env->uncached_asr = ASR_MODE_USER;
env->regs[31] = 0;
+#else
+ env->uncached_asr = ASR_MODE_PRIV;
+ env->regs[31] = 0x03000000;
+#endif
tlb_flush(env, 1);
}
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 81c14ff..06508a1 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -1,15 +1,15 @@
/*
* UniCore32 virtual CPU header
*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation, or (at your option) any
* later version. See the COPYING file in the top-level directory.
*/
-#ifndef __CPU_UC32_H__
-#define __CPU_UC32_H__
+#ifndef QEMU_UNICORE32_CPU_H
+#define QEMU_UNICORE32_CPU_H
#define TARGET_LONG_BITS 32
#define TARGET_PAGE_BITS 12
@@ -89,8 +89,10 @@ typedef struct CPUUniCore32State {
#define ASR_NZCV (ASR_N | ASR_Z | ASR_C | ASR_V)
#define ASR_RESERVED (~(ASR_M | ASR_I | ASR_NZCV))
-#define UC32_EXCP_PRIV (ASR_MODE_PRIV)
-#define UC32_EXCP_TRAP (ASR_MODE_TRAP)
+#define UC32_EXCP_PRIV (1)
+#define UC32_EXCP_ITRAP (2)
+#define UC32_EXCP_DTRAP (3)
+#define UC32_EXCP_INTR (4)
/* Return the current ASR value. */
target_ulong cpu_asr_read(CPUUniCore32State *env1);
@@ -120,10 +122,6 @@ void cpu_asr_write(CPUUniCore32State *env1, target_ulong val, target_ulong mask)
#define UC32_HWCAP_CMOV 4 /* 1 << 2 */
#define UC32_HWCAP_UCF64 8 /* 1 << 3 */
-#define UC32_CPUID(env) (env->cp0.c0_cpuid)
-#define UC32_CPUID_UCV2 0x40010863
-#define UC32_CPUID_ANY 0xffffffff
-
#define cpu_init uc32_cpu_init
#define cpu_exec uc32_cpu_exec
#define cpu_signal_handler uc32_cpu_signal_handler
@@ -189,4 +187,4 @@ static inline bool cpu_has_work(CPUUniCore32State *env)
(CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
}
-#endif /* __CPU_UC32_H__ */
+#endif /* QEMU_UNICORE32_CPU_H */
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 9fe4a37..a9e226b 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,6 +13,15 @@
#include "gdbstub.h"
#include "helper.h"
#include "host-utils.h"
+#include "console.h"
+
+#undef DEBUG_UC32
+
+#ifdef DEBUG_UC32
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
{
@@ -45,389 +54,203 @@ uint32_t HELPER(clz)(uint32_t x)
return clz32(x);
}
-void do_interrupt(CPUUniCore32State *env)
-{
- env->exception_index = -1;
-}
-
-int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address, int rw,
- int mmu_idx)
-{
- env->exception_index = UC32_EXCP_TRAP;
- env->cp0.c4_faultaddr = address;
- return 1;
-}
-
-/* These should probably raise undefined insn exceptions. */
-void HELPER(set_cp)(CPUUniCore32State *env, uint32_t insn, uint32_t val)
-{
- int op1 = (insn >> 8) & 0xf;
- cpu_abort(env, "cp%i insn %08x\n", op1, insn);
- return;
-}
-
-uint32_t HELPER(get_cp)(CPUUniCore32State *env, uint32_t insn)
-{
- int op1 = (insn >> 8) & 0xf;
- cpu_abort(env, "cp%i insn %08x\n", op1, insn);
- return 0;
-}
-
-void HELPER(set_cp0)(CPUUniCore32State *env, uint32_t insn, uint32_t val)
-{
- cpu_abort(env, "cp0 insn %08x\n", insn);
-}
-
-uint32_t HELPER(get_cp0)(CPUUniCore32State *env, uint32_t insn)
-{
- cpu_abort(env, "cp0 insn %08x\n", insn);
- return 0;
-}
-
-void switch_mode(CPUUniCore32State *env, int mode)
-{
- if (mode != ASR_MODE_USER) {
- cpu_abort(env, "Tried to switch out of user mode\n");
- }
-}
-
-void HELPER(set_r29_banked)(CPUUniCore32State *env, uint32_t mode, uint32_t val)
-{
- cpu_abort(env, "banked r29 write\n");
-}
-
-uint32_t HELPER(get_r29_banked)(CPUUniCore32State *env, uint32_t mode)
-{
- cpu_abort(env, "banked r29 read\n");
- return 0;
-}
-
-/* UniCore-F64 support. We follow the convention used for F64 instrunctions:
- Single precition routines have a "s" suffix, double precision a
- "d" suffix. */
-
-/* Convert host exception flags to f64 form. */
-static inline int ucf64_exceptbits_from_host(int host_bits)
-{
- int target_bits = 0;
-
- if (host_bits & float_flag_invalid) {
- target_bits |= UCF64_FPSCR_FLAG_INVALID;
- }
- if (host_bits & float_flag_divbyzero) {
- target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
- }
- if (host_bits & float_flag_overflow) {
- target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
- }
- if (host_bits & float_flag_underflow) {
- target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
- }
- if (host_bits & float_flag_inexact) {
- target_bits |= UCF64_FPSCR_FLAG_INEXACT;
- }
- return target_bits;
-}
-
-uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env)
-{
- int i;
- uint32_t fpscr;
-
- fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
- i = get_float_exception_flags(&env->ucf64.fp_status);
- fpscr |= ucf64_exceptbits_from_host(i);
- return fpscr;
-}
-
-/* Convert ucf64 exception flags to target form. */
-static inline int ucf64_exceptbits_to_host(int target_bits)
-{
- int host_bits = 0;
-
- if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
- host_bits |= float_flag_invalid;
- }
- if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
- host_bits |= float_flag_divbyzero;
- }
- if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
- host_bits |= float_flag_overflow;
- }
- if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
- host_bits |= float_flag_underflow;
- }
- if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
- host_bits |= float_flag_inexact;
- }
- return host_bits;
-}
-
-void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val)
-{
- int i;
- uint32_t changed;
-
- changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
-
- changed ^= val;
- if (changed & (UCF64_FPSCR_RND_MASK)) {
- i = UCF64_FPSCR_RND(val);
- switch (i) {
- case 0:
- i = float_round_nearest_even;
- break;
- case 1:
- i = float_round_to_zero;
- break;
- case 2:
- i = float_round_up;
- break;
- case 3:
- i = float_round_down;
- break;
- default: /* 100 and 101 not implement */
- cpu_abort(env, "Unsupported UniCore-F64 round mode");
- }
- set_float_rounding_mode(i, &env->ucf64.fp_status);
- }
-
- i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
- set_float_exception_flags(i, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_add(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_add(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_sub(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_sub(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_mul(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_mul(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_div(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_div(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_negs)(float32 a)
-{
- return float32_chs(a);
-}
-
-float64 HELPER(ucf64_negd)(float64 a)
-{
- return float64_chs(a);
-}
-
-float32 HELPER(ucf64_abss)(float32 a)
-{
- return float32_abs(a);
-}
-
-float64 HELPER(ucf64_absd)(float64 a)
-{
- return float64_abs(a);
-}
-
-/* XXX: check quiet/signaling case */
-void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUUniCore32State *env)
-{
- int flag;
- flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
- env->CF = 0;
- switch (c & 0x7) {
- case 0: /* F */
- break;
- case 1: /* UN */
- if (flag == 2) {
- env->CF = 1;
+#ifndef CONFIG_USER_ONLY
+void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg,
+ uint32_t cop)
+{
+ /*
+ * movc pp.nn, rn, #imm9
+ * rn: UCOP_REG_D
+ * nn: UCOP_REG_N
+ * 1: sys control reg.
+ * 2: page table base reg.
+ * 3: data fault status reg.
+ * 4: insn fault status reg.
+ * 5: cache op. reg.
+ * 6: tlb op. reg.
+ * imm9: split UCOP_IMM10 with bit5 is 0
+ */
+ switch (creg) {
+ case 1:
+ if (cop != 0) {
+ goto unrecognized;
}
+ env->cp0.c1_sys = val;
break;
- case 2: /* EQ */
- if (flag == 0) {
- env->CF = 1;
+ case 2:
+ if (cop != 0) {
+ goto unrecognized;
}
+ env->cp0.c2_base = val;
break;
- case 3: /* UEQ */
- if ((flag == 0) || (flag == 2)) {
- env->CF = 1;
+ case 3:
+ if (cop != 0) {
+ goto unrecognized;
}
+ env->cp0.c3_faultstatus = val;
break;
- case 4: /* OLT */
- if (flag == -1) {
- env->CF = 1;
+ case 4:
+ if (cop != 0) {
+ goto unrecognized;
}
+ env->cp0.c4_faultaddr = val;
break;
- case 5: /* ULT */
- if ((flag == -1) || (flag == 2)) {
- env->CF = 1;
+ case 5:
+ switch (cop) {
+ case 28:
+ DPRINTF("Invalidate Entire I&D cache\n");
+ return;
+ case 20:
+ DPRINTF("Invalidate Entire Icache\n");
+ return;
+ case 12:
+ DPRINTF("Invalidate Entire Dcache\n");
+ return;
+ case 10:
+ DPRINTF("Clean Entire Dcache\n");
+ return;
+ case 14:
+ DPRINTF("Flush Entire Dcache\n");
+ return;
+ case 13:
+ DPRINTF("Invalidate Dcache line\n");
+ return;
+ case 11:
+ DPRINTF("Clean Dcache line\n");
+ return;
+ case 15:
+ DPRINTF("Flush Dcache line\n");
+ return;
}
break;
- case 6: /* OLE */
- if ((flag == -1) || (flag == 0)) {
- env->CF = 1;
- }
- break;
- case 7: /* ULE */
- if (flag != 1) {
- env->CF = 1;
+ case 6:
+ if ((cop <= 6) && (cop >= 2)) {
+ /* invalid all tlb */
+ tlb_flush(env, 1);
+ return;
}
break;
+ default:
+ goto unrecognized;
}
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
- | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
-}
-
-void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUUniCore32State *env)
-{
- int flag;
- flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
- env->CF = 0;
- switch (c & 0x7) {
- case 0: /* F */
- break;
- case 1: /* UN */
- if (flag == 2) {
- env->CF = 1;
- }
- break;
- case 2: /* EQ */
- if (flag == 0) {
- env->CF = 1;
- }
- break;
- case 3: /* UEQ */
- if ((flag == 0) || (flag == 2)) {
- env->CF = 1;
+ return;
+unrecognized:
+ DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n",
+ creg, cop);
+}
+
+uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop)
+{
+ /*
+ * movc rd, pp.nn, #imm9
+ * rd: UCOP_REG_D
+ * nn: UCOP_REG_N
+ * 0: cpuid and cachetype
+ * 1: sys control reg.
+ * 2: page table base reg.
+ * 3: data fault status reg.
+ * 4: insn fault status reg.
+ * imm9: split UCOP_IMM10 with bit5 is 0
+ */
+ switch (creg) {
+ case 0:
+ switch (cop) {
+ case 0:
+ return env->cp0.c0_cpuid;
+ case 1:
+ return env->cp0.c0_cachetype;
}
break;
- case 4: /* OLT */
- if (flag == -1) {
- env->CF = 1;
+ case 1:
+ if (cop == 0) {
+ return env->cp0.c1_sys;
}
break;
- case 5: /* ULT */
- if ((flag == -1) || (flag == 2)) {
- env->CF = 1;
+ case 2:
+ if (cop == 0) {
+ return env->cp0.c2_base;
}
break;
- case 6: /* OLE */
- if ((flag == -1) || (flag == 0)) {
- env->CF = 1;
+ case 3:
+ if (cop == 0) {
+ return env->cp0.c3_faultstatus;
}
break;
- case 7: /* ULE */
- if (flag != 1) {
- env->CF = 1;
+ case 4:
+ if (cop == 0) {
+ return env->cp0.c4_faultaddr;
}
break;
}
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
- | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
-}
-
-/* Helper routines to perform bitwise copies between float and int. */
-static inline float32 ucf64_itos(uint32_t i)
-{
- union {
- uint32_t i;
- float32 s;
- } v;
-
- v.i = i;
- return v.s;
-}
-
-static inline uint32_t ucf64_stoi(float32 s)
-{
- union {
- uint32_t i;
- float32 s;
- } v;
-
- v.s = s;
- return v.i;
-}
-
-static inline float64 ucf64_itod(uint64_t i)
-{
- union {
- uint64_t i;
- float64 d;
- } v;
-
- v.i = i;
- return v.d;
+ DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n",
+ creg, cop);
+ return 0;
}
-static inline uint64_t ucf64_dtoi(float64 d)
+#ifdef CONFIG_CURSES
+/*
+ * FIXME:
+ * 1. curses windows will be blank when switching back
+ * 2. backspace is not handled yet
+ */
+static void putc_on_screen(unsigned char ch)
{
- union {
- uint64_t i;
- float64 d;
- } v;
+ static WINDOW *localwin;
+ static int init;
- v.d = d;
- return v.i;
-}
+ if (!init) {
+ /* Assume 80 * 30 screen to minimize the implementation */
+ localwin = newwin(30, 80, 0, 0);
+ scrollok(localwin, TRUE);
+ init = TRUE;
+ }
-/* Integer to float conversion. */
-float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env)
-{
- return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
-}
+ if (isprint(ch)) {
+ wprintw(localwin, "%c", ch);
+ } else {
+ switch (ch) {
+ case '\n':
+ wprintw(localwin, "%c", ch);
+ break;
+ case '\r':
+ /* If '\r' is put before '\n', the curses window will destroy the
+ * last print line. And meanwhile, '\n' implifies '\r' inside. */
+ break;
+ default: /* Not handled, so just print it hex code */
+ wprintw(localwin, "-- 0x%x --", ch);
+ }
+ }
-float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env)
-{
- return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
+ wrefresh(localwin);
}
+#else
+#define putc_on_screen(c) do { } while (0)
+#endif
-/* Float to integer conversion. */
-float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env)
+void helper_cp1_putc(target_ulong x)
{
- return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
+ putc_on_screen((unsigned char)x); /* Output to screen */
+ DPRINTF("%c", x); /* Output to stdout */
}
+#endif
-float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env)
+#ifdef CONFIG_USER_ONLY
+void switch_mode(CPUUniCore32State *env, int mode)
{
- return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
+ if (mode != ASR_MODE_USER) {
+ cpu_abort(env, "Tried to switch out of user mode\n");
+ }
}
-/* floating point conversion */
-float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env)
+void do_interrupt(CPUUniCore32State *env)
{
- return float32_to_float64(x, &env->ucf64.fp_status);
+ cpu_abort(env, "NO interrupt in user mode\n");
}
-float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env)
+int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
+ int access_type, int mmu_idx)
{
- return float64_to_float32(x, &env->ucf64.fp_status);
+ cpu_abort(env, "NO mmu fault in user mode\n");
+ return 1;
}
+#endif
diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h
index 5a3b8a4..305318a 100644
--- a/target-unicore32/helper.h
+++ b/target-unicore32/helper.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -8,6 +8,12 @@
*/
#include "def-helper.h"
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(cp0_set, void, env, i32, i32, i32)
+DEF_HELPER_3(cp0_get, i32, env, i32, i32)
+DEF_HELPER_1(cp1_putc, void, i32)
+#endif
+
DEF_HELPER_1(clz, i32, i32)
DEF_HELPER_1(clo, i32, i32)
@@ -16,12 +22,6 @@ DEF_HELPER_1(exception, void, i32)
DEF_HELPER_2(asr_write, void, i32, i32)
DEF_HELPER_0(asr_read, i32)
-DEF_HELPER_3(set_cp0, void, env, i32, i32)
-DEF_HELPER_2(get_cp0, i32, env, i32)
-
-DEF_HELPER_3(set_cp, void, env, i32, i32)
-DEF_HELPER_2(get_cp, i32, env, i32)
-
DEF_HELPER_1(get_user_reg, i32, i32)
DEF_HELPER_2(set_user_reg, void, i32, i32)
@@ -38,9 +38,6 @@ DEF_HELPER_2(shr_cc, i32, i32, i32)
DEF_HELPER_2(sar_cc, i32, i32, i32)
DEF_HELPER_2(ror_cc, i32, i32, i32)
-DEF_HELPER_2(get_r29_banked, i32, env, i32)
-DEF_HELPER_3(set_r29_banked, void, env, i32, i32)
-
DEF_HELPER_1(ucf64_get_fpscr, i32, env)
DEF_HELPER_2(ucf64_set_fpscr, void, env, i32)
diff --git a/target-unicore32/machine.c b/target-unicore32/machine.c
new file mode 100644
index 0000000..60b2ec1
--- /dev/null
+++ b/target-unicore32/machine.c
@@ -0,0 +1,23 @@
+/*
+ * Generic machine functions for UniCore32 ISA
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/hw.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+ hw_error("%s not supported yet.\n", __func__);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ hw_error("%s not supported yet.\n", __func__);
+
+ return 0;
+}
diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c
index b954c30..c63789d 100644
--- a/target-unicore32/op_helper.c
+++ b/target-unicore32/op_helper.c
@@ -1,7 +1,7 @@
/*
* UniCore32 helper routines
*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -248,3 +248,45 @@ uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
return ((uint32_t)x >> shift) | (x << (32 - shift));
}
}
+
+#ifndef CONFIG_USER_ONLY
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+void tlb_fill(CPUUniCore32State *env1, target_ulong addr, int is_write,
+ int mmu_idx, uintptr_t retaddr)
+{
+ TranslationBlock *tb;
+ CPUUniCore32State *saved_env;
+ unsigned long pc;
+ int ret;
+
+ saved_env = env;
+ env = env1;
+ ret = uc32_cpu_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ if (unlikely(ret)) {
+ if (retaddr) {
+ /* now we have a real cpu fault */
+ pc = (unsigned long)retaddr;
+ tb = tb_find_pc(pc);
+ if (tb) {/* the PC is inside the translated code.
+ It means that we have a virtual CPU fault */
+ cpu_restore_state(tb, env, pc);
+ }
+ }
+ cpu_loop_exit(env);
+ }
+ env = saved_env;
+}
+#endif
diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c
new file mode 100644
index 0000000..373f94b
--- /dev/null
+++ b/target-unicore32/softmmu.c
@@ -0,0 +1,267 @@
+/*
+ * Softmmu related functions
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#ifdef CONFIG_USER_ONLY
+#error This file only exist under softmmu circumstance
+#endif
+
+#include <cpu.h>
+
+#undef DEBUG_UC32
+
+#ifdef DEBUG_UC32
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define SUPERPAGE_SIZE (1 << 22)
+#define UC32_PAGETABLE_READ (1 << 8)
+#define UC32_PAGETABLE_WRITE (1 << 7)
+#define UC32_PAGETABLE_EXEC (1 << 6)
+#define UC32_PAGETABLE_EXIST (1 << 2)
+#define PAGETABLE_TYPE(x) ((x) & 3)
+
+
+/* Map CPU modes onto saved register banks. */
+static inline int bank_number(int mode)
+{
+ switch (mode) {
+ case ASR_MODE_USER:
+ case ASR_MODE_SUSR:
+ return 0;
+ case ASR_MODE_PRIV:
+ return 1;
+ case ASR_MODE_TRAP:
+ return 2;
+ case ASR_MODE_EXTN:
+ return 3;
+ case ASR_MODE_INTR:
+ return 4;
+ }
+ cpu_abort(cpu_single_env, "Bad mode %x\n", mode);
+ return -1;
+}
+
+void switch_mode(CPUUniCore32State *env, int mode)
+{
+ int old_mode;
+ int i;
+
+ old_mode = env->uncached_asr & ASR_M;
+ if (mode == old_mode) {
+ return;
+ }
+
+ i = bank_number(old_mode);
+ env->banked_r29[i] = env->regs[29];
+ env->banked_r30[i] = env->regs[30];
+ env->banked_bsr[i] = env->bsr;
+
+ i = bank_number(mode);
+ env->regs[29] = env->banked_r29[i];
+ env->regs[30] = env->banked_r30[i];
+ env->bsr = env->banked_bsr[i];
+}
+
+/* Handle a CPU exception. */
+void do_interrupt(CPUUniCore32State *env)
+{
+ uint32_t addr;
+ int new_mode;
+
+ switch (env->exception_index) {
+ case UC32_EXCP_PRIV:
+ new_mode = ASR_MODE_PRIV;
+ addr = 0x08;
+ break;
+ case UC32_EXCP_ITRAP:
+ DPRINTF("itrap happened at %x\n", env->regs[31]);
+ new_mode = ASR_MODE_TRAP;
+ addr = 0x0c;
+ break;
+ case UC32_EXCP_DTRAP:
+ DPRINTF("dtrap happened at %x\n", env->regs[31]);
+ new_mode = ASR_MODE_TRAP;
+ addr = 0x10;
+ break;
+ case UC32_EXCP_INTR:
+ new_mode = ASR_MODE_INTR;
+ addr = 0x18;
+ break;
+ default:
+ cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+ return;
+ }
+ /* High vectors. */
+ if (env->cp0.c1_sys & (1 << 13)) {
+ addr += 0xffff0000;
+ }
+
+ switch_mode(env, new_mode);
+ env->bsr = cpu_asr_read(env);
+ env->uncached_asr = (env->uncached_asr & ~ASR_M) | new_mode;
+ env->uncached_asr |= ASR_I;
+ /* The PC already points to the proper instruction. */
+ env->regs[30] = env->regs[31];
+ env->regs[31] = addr;
+ env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+static int get_phys_addr_ucv2(CPUUniCore32State *env, uint32_t address,
+ int access_type, int is_user, uint32_t *phys_ptr, int *prot,
+ target_ulong *page_size)
+{
+ int code;
+ uint32_t table;
+ uint32_t desc;
+ uint32_t phys_addr;
+
+ /* Pagetable walk. */
+ /* Lookup l1 descriptor. */
+ table = env->cp0.c2_base & 0xfffff000;
+ table |= (address >> 20) & 0xffc;
+ desc = ldl_phys(table);
+ code = 0;
+ switch (PAGETABLE_TYPE(desc)) {
+ case 3:
+ /* Superpage */
+ if (!(desc & UC32_PAGETABLE_EXIST)) {
+ code = 0x0b; /* superpage miss */
+ goto do_fault;
+ }
+ phys_addr = (desc & 0xffc00000) | (address & 0x003fffff);
+ *page_size = SUPERPAGE_SIZE;
+ break;
+ case 0:
+ /* Lookup l2 entry. */
+ if (is_user) {
+ DPRINTF("PGD address %x, desc %x\n", table, desc);
+ }
+ if (!(desc & UC32_PAGETABLE_EXIST)) {
+ code = 0x05; /* second pagetable miss */
+ goto do_fault;
+ }
+ table = (desc & 0xfffff000) | ((address >> 10) & 0xffc);
+ desc = ldl_phys(table);
+ /* 4k page. */
+ if (is_user) {
+ DPRINTF("PTE address %x, desc %x\n", table, desc);
+ }
+ if (!(desc & UC32_PAGETABLE_EXIST)) {
+ code = 0x08; /* page miss */
+ goto do_fault;
+ }
+ switch (PAGETABLE_TYPE(desc)) {
+ case 0:
+ phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+ *page_size = TARGET_PAGE_SIZE;
+ break;
+ default:
+ cpu_abort(env, "wrong page type!");
+ }
+ break;
+ default:
+ cpu_abort(env, "wrong page type!");
+ }
+
+ *phys_ptr = phys_addr;
+ *prot = 0;
+ /* Check access permissions. */
+ if (desc & UC32_PAGETABLE_READ) {
+ *prot |= PAGE_READ;
+ } else {
+ if (is_user && (access_type == 0)) {
+ code = 0x11; /* access unreadable area */
+ goto do_fault;
+ }
+ }
+
+ if (desc & UC32_PAGETABLE_WRITE) {
+ *prot |= PAGE_WRITE;
+ } else {
+ if (is_user && (access_type == 1)) {
+ code = 0x12; /* access unwritable area */
+ goto do_fault;
+ }
+ }
+
+ if (desc & UC32_PAGETABLE_EXEC) {
+ *prot |= PAGE_EXEC;
+ } else {
+ if (is_user && (access_type == 2)) {
+ code = 0x13; /* access unexecutable area */
+ goto do_fault;
+ }
+ }
+
+do_fault:
+ return code;
+}
+
+int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
+ int access_type, int mmu_idx)
+{
+ uint32_t phys_addr;
+ target_ulong page_size;
+ int prot;
+ int ret, is_user;
+
+ ret = 1;
+ is_user = mmu_idx == MMU_USER_IDX;
+
+ if ((env->cp0.c1_sys & 1) == 0) {
+ /* MMU disabled. */
+ phys_addr = address;
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ page_size = TARGET_PAGE_SIZE;
+ ret = 0;
+ } else {
+ if ((address & (1 << 31)) || (is_user)) {
+ ret = get_phys_addr_ucv2(env, address, access_type, is_user,
+ &phys_addr, &prot, &page_size);
+ if (is_user) {
+ DPRINTF("user space access: ret %x, address %x, "
+ "access_type %x, phys_addr %x, prot %x\n",
+ ret, address, access_type, phys_addr, prot);
+ }
+ } else {
+ /*IO memory */
+ phys_addr = address | (1 << 31);
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ page_size = TARGET_PAGE_SIZE;
+ ret = 0;
+ }
+ }
+
+ if (ret == 0) {
+ /* Map a single page. */
+ phys_addr &= TARGET_PAGE_MASK;
+ address &= TARGET_PAGE_MASK;
+ tlb_set_page(env, address, phys_addr, prot, mmu_idx, page_size);
+ return 0;
+ }
+
+ env->cp0.c3_faultstatus = ret;
+ env->cp0.c4_faultaddr = address;
+ if (access_type == 2) {
+ env->exception_index = UC32_EXCP_ITRAP;
+ } else {
+ env->exception_index = UC32_EXCP_DTRAP;
+ }
+ return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUUniCore32State *env,
+ target_ulong addr)
+{
+ cpu_abort(env, "%s not supported yet\n", __func__);
+ return addr;
+}
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index 9793d14..188bf8c 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -1,7 +1,7 @@
/*
* UniCore32 translation
*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -33,9 +33,16 @@ typedef struct DisasContext {
int condlabel;
struct TranslationBlock *tb;
int singlestep_enabled;
+#ifndef CONFIG_USER_ONLY
+ int user;
+#endif
} DisasContext;
-#define IS_USER(s) 1
+#ifndef CONFIG_USER_ONLY
+#define IS_USER(s) (s->user)
+#else
+#define IS_USER(s) 1
+#endif
/* These instructions trap after executing, so defer them until after the
conditional executions state has been updated. */
@@ -176,6 +183,73 @@ static void store_reg(DisasContext *s, int reg, TCGv var)
"Illegal UniCore32 instruction %x at line %d!", \
insn, __LINE__)
+#ifndef CONFIG_USER_ONLY
+static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s,
+ uint32_t insn)
+{
+ TCGv tmp, tmp2, tmp3;
+ if ((insn & 0xfe000000) == 0xe0000000) {
+ tmp2 = new_tmp();
+ tmp3 = new_tmp();
+ tcg_gen_movi_i32(tmp2, UCOP_REG_N);
+ tcg_gen_movi_i32(tmp3, UCOP_IMM10);
+ if (UCOP_SET_L) {
+ tmp = new_tmp();
+ gen_helper_cp0_get(tmp, cpu_env, tmp2, tmp3);
+ store_reg(s, UCOP_REG_D, tmp);
+ } else {
+ tmp = load_reg(s, UCOP_REG_D);
+ gen_helper_cp0_set(cpu_env, tmp, tmp2, tmp3);
+ dead_tmp(tmp);
+ }
+ dead_tmp(tmp2);
+ dead_tmp(tmp3);
+ return;
+ }
+ ILLEGAL;
+}
+
+static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s,
+ uint32_t insn)
+{
+ TCGv tmp;
+
+ if ((insn & 0xff003fff) == 0xe1000400) {
+ /*
+ * movc rd, pp.nn, #imm9
+ * rd: UCOP_REG_D
+ * nn: UCOP_REG_N (must be 0)
+ * imm9: 0
+ */
+ if (UCOP_REG_N == 0) {
+ tmp = new_tmp();
+ tcg_gen_movi_i32(tmp, 0);
+ store_reg(s, UCOP_REG_D, tmp);
+ return;
+ } else {
+ ILLEGAL;
+ }
+ }
+ if ((insn & 0xff003fff) == 0xe0000401) {
+ /*
+ * movc pp.nn, rn, #imm9
+ * rn: UCOP_REG_D
+ * nn: UCOP_REG_N (must be 1)
+ * imm9: 1
+ */
+ if (UCOP_REG_N == 1) {
+ tmp = load_reg(s, UCOP_REG_D);
+ gen_helper_cp1_putc(tmp);
+ dead_tmp(tmp);
+ return;
+ } else {
+ ILLEGAL;
+ }
+ }
+ ILLEGAL;
+}
+#endif
+
static inline void gen_set_asr(TCGv var, uint32_t mask)
{
TCGv tmp_mask = tcg_const_i32(mask);
@@ -1124,9 +1198,18 @@ static void gen_exception_return(DisasContext *s, TCGv pc)
s->is_jmp = DISAS_UPDATE;
}
-static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
+static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s,
+ uint32_t insn)
{
switch (UCOP_CPNUM) {
+#ifndef CONFIG_USER_ONLY
+ case 0:
+ disas_cp0_insn(env, s, insn);
+ break;
+ case 1:
+ disas_ocd_insn(env, s, insn);
+ break;
+#endif
case 2:
disas_ucf64_insn(env, s, insn);
break;
@@ -1478,12 +1561,12 @@ static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
/* load/store I_offset and R_offset */
static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
{
- unsigned int i;
+ unsigned int mmu_idx;
TCGv tmp;
TCGv tmp2;
tmp2 = load_reg(s, UCOP_REG_N);
- i = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
+ mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
/* immediate */
if (UCOP_SET_P) {
@@ -1493,17 +1576,17 @@ static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
if (UCOP_SET_L) {
/* load */
if (UCOP_SET_B) {
- tmp = gen_ld8u(tmp2, i);
+ tmp = gen_ld8u(tmp2, mmu_idx);
} else {
- tmp = gen_ld32(tmp2, i);
+ tmp = gen_ld32(tmp2, mmu_idx);
}
} else {
/* store */
tmp = load_reg(s, UCOP_REG_D);
if (UCOP_SET_B) {
- gen_st8(tmp, tmp2, i);
+ gen_st8(tmp, tmp2, mmu_idx);
} else {
- gen_st32(tmp, tmp2, i);
+ gen_st32(tmp, tmp2, mmu_idx);
}
}
if (!UCOP_SET_P) {
@@ -1606,7 +1689,7 @@ static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
/* load/store multiple words */
static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
{
- unsigned int val, i;
+ unsigned int val, i, mmu_idx;
int j, n, reg, user, loaded_base;
TCGv tmp;
TCGv tmp2;
@@ -1627,6 +1710,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
}
}
+ mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
addr = load_reg(s, UCOP_REG_N);
/* compute total size */
@@ -1671,7 +1755,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
}
if (UCOP_SET(i)) {
if (UCOP_SET_L) { /* load */
- tmp = gen_ld32(addr, IS_USER(s));
+ tmp = gen_ld32(addr, mmu_idx);
if (reg == 31) {
gen_bx(s, tmp);
} else if (user) {
@@ -1699,7 +1783,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
} else {
tmp = load_reg(s, reg);
}
- gen_st32(tmp, addr, IS_USER(s));
+ gen_st32(tmp, addr, mmu_idx);
}
j++;
/* no need to add after the last transfer */
@@ -1888,6 +1972,14 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env,
max_insns = CF_COUNT_MASK;
}
+#ifndef CONFIG_USER_ONLY
+ if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) {
+ dc->user = 1;
+ } else {
+ dc->user = 0;
+ }
+#endif
+
gen_icount_start();
do {
if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
@@ -2046,12 +2138,12 @@ static const char *cpu_mode_names[16] = {
"UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR"
};
-#define UCF64_DUMP_STATE
-void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprintf,
- int flags)
+#undef UCF64_DUMP_STATE
+#ifdef UCF64_DUMP_STATE
+static void cpu_dump_state_ucf64(CPUUniCore32State *env, FILE *f,
+ fprintf_function cpu_fprintf, int flags)
{
int i;
-#ifdef UCF64_DUMP_STATE
union {
uint32_t i;
float s;
@@ -2063,7 +2155,28 @@ void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprint
float64 f64;
double d;
} d0;
+
+ for (i = 0; i < 16; i++) {
+ d.d = env->ucf64.regs[i];
+ s0.i = d.l.lower;
+ s1.i = d.l.upper;
+ d0.f64 = d.d;
+ cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)",
+ i * 2, (int)s0.i, s0.s,
+ i * 2 + 1, (int)s1.i, s1.s);
+ cpu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n",
+ i, (uint64_t)d0.f64, d0.d);
+ }
+ cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
+}
+#else
+#define cpu_dump_state_ucf64(env, file, pr, flags) do { } while (0)
#endif
+
+void cpu_dump_state(CPUUniCore32State *env, FILE *f,
+ fprintf_function cpu_fprintf, int flags)
+{
+ int i;
uint32_t psr;
for (i = 0; i < 32; i++) {
@@ -2083,19 +2196,7 @@ void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprint
psr & (1 << 28) ? 'V' : '-',
cpu_mode_names[psr & 0xf]);
-#ifdef UCF64_DUMP_STATE
- for (i = 0; i < 16; i++) {
- d.d = env->ucf64.regs[i];
- s0.i = d.l.lower;
- s1.i = d.l.upper;
- d0.f64 = d.d;
- cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%" PRIx64 "(%8g)\n",
- i * 2, (int)s0.i, s0.s,
- i * 2 + 1, (int)s1.i, s1.s,
- i, (uint64_t)d0.f64, d0.d);
- }
- cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
-#endif
+ cpu_dump_state_ucf64(env, f, cpu_fprintf, flags);
}
void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb, int pc_pos)
diff --git a/target-unicore32/ucf64_helper.c b/target-unicore32/ucf64_helper.c
new file mode 100644
index 0000000..a516edd
--- /dev/null
+++ b/target-unicore32/ucf64_helper.c
@@ -0,0 +1,345 @@
+/*
+ * UniCore-F64 simulation helpers for QEMU.
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "cpu.h"
+#include "helper.h"
+
+/*
+ * The convention used for UniCore-F64 instructions:
+ * Single precition routines have a "s" suffix
+ * Double precision routines have a "d" suffix.
+ */
+
+/* Convert host exception flags to f64 form. */
+static inline int ucf64_exceptbits_from_host(int host_bits)
+{
+ int target_bits = 0;
+
+ if (host_bits & float_flag_invalid) {
+ target_bits |= UCF64_FPSCR_FLAG_INVALID;
+ }
+ if (host_bits & float_flag_divbyzero) {
+ target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
+ }
+ if (host_bits & float_flag_overflow) {
+ target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
+ }
+ if (host_bits & float_flag_underflow) {
+ target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
+ }
+ if (host_bits & float_flag_inexact) {
+ target_bits |= UCF64_FPSCR_FLAG_INEXACT;
+ }
+ return target_bits;
+}
+
+uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env)
+{
+ int i;
+ uint32_t fpscr;
+
+ fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
+ i = get_float_exception_flags(&env->ucf64.fp_status);
+ fpscr |= ucf64_exceptbits_from_host(i);
+ return fpscr;
+}
+
+/* Convert ucf64 exception flags to target form. */
+static inline int ucf64_exceptbits_to_host(int target_bits)
+{
+ int host_bits = 0;
+
+ if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
+ host_bits |= float_flag_invalid;
+ }
+ if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
+ host_bits |= float_flag_divbyzero;
+ }
+ if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
+ host_bits |= float_flag_overflow;
+ }
+ if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
+ host_bits |= float_flag_underflow;
+ }
+ if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
+ host_bits |= float_flag_inexact;
+ }
+ return host_bits;
+}
+
+void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val)
+{
+ int i;
+ uint32_t changed;
+
+ changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
+
+ changed ^= val;
+ if (changed & (UCF64_FPSCR_RND_MASK)) {
+ i = UCF64_FPSCR_RND(val);
+ switch (i) {
+ case 0:
+ i = float_round_nearest_even;
+ break;
+ case 1:
+ i = float_round_to_zero;
+ break;
+ case 2:
+ i = float_round_up;
+ break;
+ case 3:
+ i = float_round_down;
+ break;
+ default: /* 100 and 101 not implement */
+ cpu_abort(env, "Unsupported UniCore-F64 round mode");
+ }
+ set_float_rounding_mode(i, &env->ucf64.fp_status);
+ }
+
+ i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
+ set_float_exception_flags(i, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env)
+{
+ return float32_add(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+ return float64_add(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env)
+{
+ return float32_sub(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+ return float64_sub(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env)
+{
+ return float32_mul(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env)
+{
+ return float64_mul(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env)
+{
+ return float32_div(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+ return float64_div(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_negs)(float32 a)
+{
+ return float32_chs(a);
+}
+
+float64 HELPER(ucf64_negd)(float64 a)
+{
+ return float64_chs(a);
+}
+
+float32 HELPER(ucf64_abss)(float32 a)
+{
+ return float32_abs(a);
+}
+
+float64 HELPER(ucf64_absd)(float64 a)
+{
+ return float64_abs(a);
+}
+
+void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c,
+ CPUUniCore32State *env)
+{
+ int flag;
+ flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
+ env->CF = 0;
+ switch (c & 0x7) {
+ case 0: /* F */
+ break;
+ case 1: /* UN */
+ if (flag == 2) {
+ env->CF = 1;
+ }
+ break;
+ case 2: /* EQ */
+ if (flag == 0) {
+ env->CF = 1;
+ }
+ break;
+ case 3: /* UEQ */
+ if ((flag == 0) || (flag == 2)) {
+ env->CF = 1;
+ }
+ break;
+ case 4: /* OLT */
+ if (flag == -1) {
+ env->CF = 1;
+ }
+ break;
+ case 5: /* ULT */
+ if ((flag == -1) || (flag == 2)) {
+ env->CF = 1;
+ }
+ break;
+ case 6: /* OLE */
+ if ((flag == -1) || (flag == 0)) {
+ env->CF = 1;
+ }
+ break;
+ case 7: /* ULE */
+ if (flag != 1) {
+ env->CF = 1;
+ }
+ break;
+ }
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+ | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c,
+ CPUUniCore32State *env)
+{
+ int flag;
+ flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
+ env->CF = 0;
+ switch (c & 0x7) {
+ case 0: /* F */
+ break;
+ case 1: /* UN */
+ if (flag == 2) {
+ env->CF = 1;
+ }
+ break;
+ case 2: /* EQ */
+ if (flag == 0) {
+ env->CF = 1;
+ }
+ break;
+ case 3: /* UEQ */
+ if ((flag == 0) || (flag == 2)) {
+ env->CF = 1;
+ }
+ break;
+ case 4: /* OLT */
+ if (flag == -1) {
+ env->CF = 1;
+ }
+ break;
+ case 5: /* ULT */
+ if ((flag == -1) || (flag == 2)) {
+ env->CF = 1;
+ }
+ break;
+ case 6: /* OLE */
+ if ((flag == -1) || (flag == 0)) {
+ env->CF = 1;
+ }
+ break;
+ case 7: /* ULE */
+ if (flag != 1) {
+ env->CF = 1;
+ }
+ break;
+ }
+ env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+ | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+/* Helper routines to perform bitwise copies between float and int. */
+static inline float32 ucf64_itos(uint32_t i)
+{
+ union {
+ uint32_t i;
+ float32 s;
+ } v;
+
+ v.i = i;
+ return v.s;
+}
+
+static inline uint32_t ucf64_stoi(float32 s)
+{
+ union {
+ uint32_t i;
+ float32 s;
+ } v;
+
+ v.s = s;
+ return v.i;
+}
+
+static inline float64 ucf64_itod(uint64_t i)
+{
+ union {
+ uint64_t i;
+ float64 d;
+ } v;
+
+ v.i = i;
+ return v.d;
+}
+
+static inline uint64_t ucf64_dtoi(float64 d)
+{
+ union {
+ uint64_t i;
+ float64 d;
+ } v;
+
+ v.d = d;
+ return v.i;
+}
+
+/* Integer to float conversion. */
+float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env)
+{
+ return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env)
+{
+ return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+/* Float to integer conversion. */
+float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env)
+{
+ return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
+}
+
+float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env)
+{
+ return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
+}
+
+/* floating point conversion */
+float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env)
+{
+ return float32_to_float64(x, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env)
+{
+ return float64_to_float32(x, &env->ucf64.fp_status);
+}
diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c
index 1c8a19e..6d001c2 100644
--- a/target-xtensa/xtensa-semi.c
+++ b/target-xtensa/xtensa-semi.c
@@ -218,6 +218,8 @@ void HELPER(simcall)(CPUXtensaState *env)
default:
qemu_log("%s(%d): not implemented\n", __func__, regs[2]);
+ regs[2] = -1;
+ regs[3] = ENOSYS;
break;
}
}
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 4d59a63..cf0ca3d 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -176,6 +176,13 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
so don't use these. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* If we're passing env to the helper as r0 and need a regpair
+ * for the address then r2 will be overwritten as we're setting
+ * up the args to the helper.
+ */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+#endif
#endif
break;
case 'L':
@@ -197,6 +204,12 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
use these. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#if defined(CONFIG_SOFTMMU) && \
+ defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* Avoid clashes with registers being used for helper args */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+#endif
break;
/* qemu_st64 data_reg2 */
case 'S':
@@ -210,6 +223,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
#ifdef CONFIG_SOFTMMU
/* r2 is still needed to load data_reg, so don't use it. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+#if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* Avoid clashes with registers being used for helper args */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+#endif
#endif
break;
@@ -388,6 +405,14 @@ static inline void tcg_out_dat_reg(TCGContext *s,
(rn << 16) | (rd << 12) | shift | rm);
}
+static inline void tcg_out_mov_reg(TCGContext *s, int cond, int rd, int rm)
+{
+ /* Simple reg-reg move, optimising out the 'do nothing' case */
+ if (rd != rm) {
+ tcg_out_dat_reg(s, cond, ARITH_MOV, rd, 0, rm, SHIFT_IMM_LSL(0));
+ }
+}
+
static inline void tcg_out_dat_reg2(TCGContext *s,
int cond, int opc0, int opc1, int rd0, int rd1,
int rn0, int rn1, int rm0, int rm1, int shift)
@@ -966,6 +991,90 @@ static void *qemu_st_helpers[4] = {
__stq_mmu,
};
#endif
+
+/* Helper routines for marshalling helper function arguments into
+ * the correct registers and stack.
+ * argreg is where we want to put this argument, arg is the argument itself.
+ * Return value is the updated argreg ready for the next call.
+ * Note that argreg 0..3 is real registers, 4+ on stack.
+ * When we reach the first stacked argument, we allocate space for it
+ * and the following stacked arguments using "str r8, [sp, #-0x10]!".
+ * Following arguments are filled in with "str r8, [sp, #0xNN]".
+ * For more than 4 stacked arguments we'd need to know how much
+ * space to allocate when we pushed the first stacked argument.
+ * We don't need this, so don't implement it (and will assert if you try it.)
+ *
+ * We provide routines for arguments which are: immediate, 32 bit
+ * value in register, 16 and 8 bit values in register (which must be zero
+ * extended before use) and 64 bit value in a lo:hi register pair.
+ */
+#define DEFINE_TCG_OUT_ARG(NAME, ARGPARAM) \
+ static TCGReg NAME(TCGContext *s, TCGReg argreg, ARGPARAM) \
+ { \
+ if (argreg < 4) { \
+ TCG_OUT_ARG_GET_ARG(argreg); \
+ } else if (argreg == 4) { \
+ TCG_OUT_ARG_GET_ARG(TCG_REG_R8); \
+ tcg_out32(s, (COND_AL << 28) | 0x052d8010); \
+ } else { \
+ assert(argreg < 8); \
+ TCG_OUT_ARG_GET_ARG(TCG_REG_R8); \
+ tcg_out32(s, (COND_AL << 28) | 0x058d8000 | (argreg - 4) * 4); \
+ } \
+ return argreg + 1; \
+ }
+
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_dat_imm(s, COND_AL, ARITH_MOV, A, 0, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_imm32, uint32_t arg)
+#undef TCG_OUT_ARG_GET_ARG
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_ext8u(s, COND_AL, A, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_reg8, TCGReg arg)
+#undef TCG_OUT_ARG_GET_ARG
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_ext16u(s, COND_AL, A, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_reg16, TCGReg arg)
+#undef TCG_OUT_ARG_GET_ARG
+
+/* We don't use the macro for this one to avoid an unnecessary reg-reg
+ * move when storing to the stack.
+ */
+static TCGReg tcg_out_arg_reg32(TCGContext *s, TCGReg argreg, TCGReg arg)
+{
+ if (argreg < 4) {
+ tcg_out_mov_reg(s, COND_AL, argreg, arg);
+ } else if (argreg == 4) {
+ /* str arg, [sp, #-0x10]! */
+ tcg_out32(s, (COND_AL << 28) | 0x052d0010 | (arg << 12));
+ } else {
+ assert(argreg < 8);
+ /* str arg, [sp, #0xNN] */
+ tcg_out32(s, (COND_AL << 28) | 0x058d0000 |
+ (arg << 12) | (argreg - 4) * 4);
+ }
+ return argreg + 1;
+}
+
+static inline TCGReg tcg_out_arg_reg64(TCGContext *s, TCGReg argreg,
+ TCGReg arglo, TCGReg arghi)
+{
+ /* 64 bit arguments must go in even/odd register pairs
+ * and in 8-aligned stack slots.
+ */
+ if (argreg & 1) {
+ argreg++;
+ }
+ argreg = tcg_out_arg_reg32(s, argreg, arglo);
+ argreg = tcg_out_arg_reg32(s, argreg, arghi);
+ return argreg;
+}
+
+static inline void tcg_out_arg_stacktidy(TCGContext *s, TCGReg argreg)
+{
+ /* Output any necessary post-call cleanup of the stack */
+ if (argreg > 4) {
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
+ }
+}
+
#endif
#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
@@ -975,6 +1084,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
int addr_reg, data_reg, data_reg2, bswap;
#ifdef CONFIG_SOFTMMU
int mem_index, s_bits;
+ TCGReg argreg;
# if TARGET_LONG_BITS == 64
int addr_reg2;
# endif
@@ -1088,31 +1198,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
tcg_out_b_noaddr(s, COND_EQ);
/* TODO: move this code to where the constants pool will be */
- if (addr_reg != TCG_REG_R0) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
- }
-# if TARGET_LONG_BITS == 32
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R1, 0, mem_index);
-# else
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
-# endif
+ /* Note that this code relies on the constraints we set in arm_op_defs[]
+ * to ensure that later arguments are not passed to us in registers we
+ * trash by moving the earlier arguments into them.
+ */
+ argreg = TCG_REG_R0;
#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 bit */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[2], 0,
- tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[1], 0,
- tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));
-
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[0], 0, TCG_AREG0,
- SHIFT_IMM_LSL(0));
+ argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
#endif
+#if TARGET_LONG_BITS == 64
+ argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2);
+#else
+ argreg = tcg_out_arg_reg32(s, argreg, addr_reg);
+#endif
+ argreg = tcg_out_arg_imm32(s, argreg, mem_index);
tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
+ tcg_out_arg_stacktidy(s, argreg);
switch (opc) {
case 0 | 4:
@@ -1211,6 +1312,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
int addr_reg, data_reg, data_reg2, bswap;
#ifdef CONFIG_SOFTMMU
int mem_index, s_bits;
+ TCGReg argreg;
# if TARGET_LONG_BITS == 64
int addr_reg2;
# endif
@@ -1314,89 +1416,38 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
tcg_out_b_noaddr(s, COND_EQ);
/* TODO: move this code to where the constants pool will be */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
-# if TARGET_LONG_BITS == 32
- switch (opc) {
- case 0:
- tcg_out_ext8u(s, COND_AL, TCG_REG_R1, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 1:
- tcg_out_ext16u(s, COND_AL, TCG_REG_R1, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 2:
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, data_reg, SHIFT_IMM_LSL(0));
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 3:
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
- tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- if (data_reg2 != TCG_REG_R3) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
- }
- break;
- }
-# else
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
+ /* Note that this code relies on the constraints we set in arm_op_defs[]
+ * to ensure that later arguments are not passed to us in registers we
+ * trash by moving the earlier arguments into them.
+ */
+ argreg = TCG_REG_R0;
+#ifdef CONFIG_TCG_PASS_AREG0
+ argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
+#endif
+#if TARGET_LONG_BITS == 64
+ argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2);
+#else
+ argreg = tcg_out_arg_reg32(s, argreg, addr_reg);
+#endif
+
switch (opc) {
case 0:
- tcg_out_ext8u(s, COND_AL, TCG_REG_R2, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg8(s, argreg, data_reg);
break;
case 1:
- tcg_out_ext16u(s, COND_AL, TCG_REG_R2, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg16(s, argreg, data_reg);
break;
case 2:
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg32(s, argreg, data_reg);
break;
case 3:
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
- tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- if (data_reg2 != TCG_REG_R3) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
- }
+ argreg = tcg_out_arg_reg64(s, argreg, data_reg, data_reg2);
break;
}
-# endif
-
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 bit */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[3], 0,
- tcg_target_call_iarg_regs[2], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[2], 0,
- tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[1], 0,
- tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[0], 0, TCG_AREG0,
- SHIFT_IMM_LSL(0));
-#endif
+ argreg = tcg_out_arg_imm32(s, argreg, mem_index);
tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]);
- if (opc == 3)
- tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
+ tcg_out_arg_stacktidy(s, argreg);
reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
#else /* !CONFIG_SOFTMMU */
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index e02dacc..dc588db 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -107,7 +107,7 @@ enum {
};
static const int tcg_target_reg_alloc_order[] = {
- TCG_REG_R34,
+ TCG_REG_R33,
TCG_REG_R35,
TCG_REG_R36,
TCG_REG_R37,
@@ -1532,12 +1532,13 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
}
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
+ tcg_out_bundle(s, mII,
+ tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58,
+ mem_index, TCG_REG_R0),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R57, 0, TCG_REG_R56),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R56, 0, TCG_AREG0));
#endif
if (!bswap || s_bits == 0) {
tcg_out_bundle(s, miB,
@@ -1659,15 +1660,21 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
- tcg_target_call_iarg_regs[2]);
- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
-#endif
+ tcg_out_bundle(s, mII,
+ tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R59,
+ mem_index, TCG_REG_R0),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R58, 0, TCG_REG_R57),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R57, 0, TCG_REG_R56));
+ tcg_out_bundle(s, miB,
+ tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
+ data_reg, TCG_REG_R3),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R56, 0, TCG_AREG0),
+ tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+ TCG_REG_B0, TCG_REG_B6));
+#else
tcg_out_bundle(s, miB,
tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
data_reg, TCG_REG_R3),
@@ -1675,6 +1682,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
mem_index, TCG_REG_R0),
tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
TCG_REG_B0, TCG_REG_B6));
+#endif
}
#else /* !CONFIG_SOFTMMU */
@@ -2314,13 +2322,13 @@ static void tcg_target_qemu_prologue(TCGContext *s)
s->code_ptr += 16; /* skip GP */
/* prologue */
- tcg_out_bundle(s, mII,
+ tcg_out_bundle(s, miI,
tcg_opc_m34(TCG_REG_P0, OPC_ALLOC_M34,
- TCG_REG_R33, 32, 24, 0),
+ TCG_REG_R34, 32, 24, 0),
+ tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+ TCG_AREG0, 0, TCG_REG_R32),
tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
- TCG_REG_B6, TCG_REG_R33, 0),
- tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
- TCG_REG_R32, TCG_REG_B0));
+ TCG_REG_B6, TCG_REG_R33, 0));
/* ??? If GUEST_BASE < 0x200000, we could load the register via
an ADDL in the M slot of the next bundle. */
@@ -2335,9 +2343,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_bundle(s, miB,
tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
- TCG_AREG0, 0, TCG_REG_R32),
- tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
TCG_REG_R12, -frame_size, TCG_REG_R12),
+ tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
+ TCG_REG_R32, TCG_REG_B0),
tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6));
/* epilogue */
@@ -2351,7 +2359,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_bundle(s, miB,
tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
tcg_opc_i26(TCG_REG_P0, OPC_MOV_I_I26,
- TCG_REG_PFS, TCG_REG_R33),
+ TCG_REG_PFS, TCG_REG_R34),
tcg_opc_b4 (TCG_REG_P0, OPC_BR_RET_SPTK_MANY_B4,
TCG_REG_B0));
}
@@ -2403,7 +2411,7 @@ static void tcg_target_init(TCGContext *s)
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R12); /* stack pointer */
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); /* thread pointer */
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R32); /* return address */
- tcg_regset_set_reg(s->reserved_regs, TCG_REG_R33); /* PFS */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R34); /* PFS */
/* The following 3 are not in use, are call-saved, but *not* saved
by the prologue. Therefore we cannot use them without modifying
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 393ba07..1006e28 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -217,6 +217,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
tcg_regset_set(ct->u.regs, 0xffffffff);
#if defined(CONFIG_SOFTMMU)
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+# if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+# endif
#endif
break;
case 'S': /* qemu_st constraint */
@@ -224,10 +227,14 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
tcg_regset_set(ct->u.regs, 0xffffffff);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
#if defined(CONFIG_SOFTMMU)
-# if TARGET_LONG_BITS == 64
+# if (defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 32) || \
+ (!defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 64)
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
# endif
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+# if defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 64
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A3);
+# endif
#endif
break;
case 'I':
@@ -382,7 +389,10 @@ static inline void tcg_out_nop(TCGContext *s)
static inline void tcg_out_mov(TCGContext *s, TCGType type,
TCGReg ret, TCGReg arg)
{
- tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+ /* Simple reg-reg move, optimising out the 'do nothing' case */
+ if (ret != arg) {
+ tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+ }
}
static inline void tcg_out_movi(TCGContext *s, TCGType type,
@@ -503,6 +513,67 @@ static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
}
}
+/* Helper routines for marshalling helper function arguments into
+ * the correct registers and stack.
+ * arg_num is where we want to put this argument, and is updated to be ready
+ * for the next call. arg is the argument itself. Note that arg_num 0..3 is
+ * real registers, 4+ on stack.
+ *
+ * We provide routines for arguments which are: immediate, 32 bit
+ * value in register, 16 and 8 bit values in register (which must be zero
+ * extended before use) and 64 bit value in a lo:hi register pair.
+ */
+#define DEFINE_TCG_OUT_CALL_IARG(NAME, ARGPARAM) \
+ static inline void NAME(TCGContext *s, int *arg_num, ARGPARAM) \
+ { \
+ if (*arg_num < 4) { \
+ DEFINE_TCG_OUT_CALL_IARG_GET_ARG(tcg_target_call_iarg_regs[*arg_num]); \
+ } else { \
+ DEFINE_TCG_OUT_CALL_IARG_GET_ARG(TCG_REG_AT); \
+ tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 4 * (*arg_num)); \
+ } \
+ (*arg_num)++; \
+}
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_opc_imm(s, OPC_ANDI, A, arg, 0xff);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg8, TCGReg arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_opc_imm(s, OPC_ANDI, A, arg, 0xffff);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg16, TCGReg arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_movi(s, TCG_TYPE_I32, A, arg);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_imm32, uint32_t arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+
+/* We don't use the macro for this one to avoid an unnecessary reg-reg
+ move when storing to the stack. */
+static inline void tcg_out_call_iarg_reg32(TCGContext *s, int *arg_num,
+ TCGReg arg)
+{
+ if (*arg_num < 4) {
+ tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[*arg_num], arg);
+ } else {
+ tcg_out_st(s, TCG_TYPE_I32, arg, TCG_REG_SP, 4 * (*arg_num));
+ }
+ (*arg_num)++;
+}
+
+static inline void tcg_out_call_iarg_reg64(TCGContext *s, int *arg_num,
+ TCGReg arg_low, TCGReg arg_high)
+{
+ (*arg_num) = (*arg_num + 1) & ~1;
+
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+ tcg_out_call_iarg_reg32(s, arg_num, arg_high);
+ tcg_out_call_iarg_reg32(s, arg_num, arg_low);
+#else
+ tcg_out_call_iarg_reg32(s, arg_num, arg_low);
+ tcg_out_call_iarg_reg32(s, arg_num, arg_high);
+#endif
+}
+
static void tcg_out_brcond(TCGContext *s, TCGCond cond, int arg1,
int arg2, int label_index)
{
@@ -792,18 +863,18 @@ static void *qemu_st_helpers[4] = {
static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
int opc)
{
- int addr_regl, addr_reg1, addr_meml;
+ int addr_regl, addr_meml;
int data_regl, data_regh, data_reg1, data_reg2;
int mem_index, s_bits;
#if defined(CONFIG_SOFTMMU)
void *label1_ptr, *label2_ptr;
- int sp_args;
+ int arg_num;
#endif
#if TARGET_LONG_BITS == 64
# if defined(CONFIG_SOFTMMU)
uint8_t *label3_ptr;
# endif
- int addr_regh, addr_reg2, addr_memh;
+ int addr_regh, addr_memh;
#endif
data_regl = *args++;
if (opc == 3)
@@ -831,18 +902,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
}
#if TARGET_LONG_BITS == 64
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
- addr_reg1 = addr_regh;
- addr_reg2 = addr_regl;
addr_memh = 0;
addr_meml = 4;
# else
- addr_reg1 = addr_regl;
- addr_reg2 = addr_regh;
addr_memh = 4;
addr_meml = 0;
# endif
#else
- addr_reg1 = addr_regl;
addr_meml = 0;
#endif
@@ -875,22 +941,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
# endif
/* slow path */
- sp_args = TCG_REG_A0;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+ arg_num = 0;
+# ifdef CONFIG_TCG_PASS_AREG0
+ tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0);
+# endif
# if TARGET_LONG_BITS == 64
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh);
+# else
+ tcg_out_call_iarg_reg32(s, &arg_num, addr_regl);
# endif
- tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index);
+ tcg_out_call_iarg_imm32(s, &arg_num, mem_index);
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
-#endif
tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
tcg_out_nop(s);
@@ -991,18 +1052,18 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
int opc)
{
- int addr_regl, addr_reg1, addr_meml;
+ int addr_regl, addr_meml;
int data_regl, data_regh, data_reg1, data_reg2;
int mem_index, s_bits;
#if defined(CONFIG_SOFTMMU)
uint8_t *label1_ptr, *label2_ptr;
- int sp_args;
+ int arg_num;
#endif
#if TARGET_LONG_BITS == 64
# if defined(CONFIG_SOFTMMU)
uint8_t *label3_ptr;
# endif
- int addr_regh, addr_reg2, addr_memh;
+ int addr_regh, addr_memh;
#endif
data_regl = *args++;
@@ -1024,18 +1085,13 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
#if TARGET_LONG_BITS == 64
addr_regh = *args++;
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
- addr_reg1 = addr_regh;
- addr_reg2 = addr_regl;
addr_memh = 0;
addr_meml = 4;
# else
- addr_reg1 = addr_regl;
- addr_reg2 = addr_regh;
addr_memh = 4;
addr_meml = 0;
# endif
#else
- addr_reg1 = addr_regl;
addr_meml = 0;
#endif
mem_index = *args;
@@ -1070,49 +1126,33 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
# endif
/* slow path */
- sp_args = TCG_REG_A0;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+ arg_num = 0;
+# ifdef CONFIG_TCG_PASS_AREG0
+ tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0);
+# endif
# if TARGET_LONG_BITS == 64
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh);
+# else
+ tcg_out_call_iarg_reg32(s, &arg_num, addr_regl);
# endif
switch(opc) {
case 0:
- tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff);
+ tcg_out_call_iarg_reg8(s, &arg_num, data_regl);
break;
case 1:
- tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff);
+ tcg_out_call_iarg_reg16(s, &arg_num, data_regl);
break;
case 2:
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
+ tcg_out_call_iarg_reg32(s, &arg_num, data_regl);
break;
case 3:
- sp_args = (sp_args + 1) & ~1;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, data_regl, data_regh);
break;
default:
tcg_abort();
}
- if (sp_args > TCG_REG_A3) {
- /* Push mem_index on the stack */
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index);
- tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16);
- } else {
- tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index);
- }
-
+ tcg_out_call_iarg_imm32(s, &arg_num, mem_index);
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]);
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
- tcg_target_call_iarg_regs[2]);
- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
-#endif
tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
tcg_out_nop(s);
diff --git a/tests/Makefile b/tests/Makefile
index f3f4159..26a67ce 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -81,7 +81,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
-qtest-obj-y = tests/libqtest.o $(oslib-obj-y)
+qtest-obj-y = tests/libqtest.o $(oslib-obj-y) $(tools-obj-y)
$(check-qtest-y): $(qtest-obj-y)
.PHONY: check-help
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 526e25e..3b896f5 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -466,6 +466,58 @@ static void simple_dict(void)
}
}
+/*
+ * this generates json of the form:
+ * a(0,m) = [0, 1, ..., m-1]
+ * a(n,m) = {
+ * 'key0': a(0,m),
+ * 'key1': a(1,m),
+ * ...
+ * 'key(n-1)': a(n-1,m)
+ * }
+ */
+static void gen_test_json(GString *gstr, int nest_level_max,
+ int elem_count)
+{
+ int i;
+
+ g_assert(gstr);
+ if (nest_level_max == 0) {
+ g_string_append(gstr, "[");
+ for (i = 0; i < elem_count; i++) {
+ g_string_append_printf(gstr, "%d", i);
+ if (i < elem_count - 1) {
+ g_string_append_printf(gstr, ", ");
+ }
+ }
+ g_string_append(gstr, "]");
+ return;
+ }
+
+ g_string_append(gstr, "{");
+ for (i = 0; i < nest_level_max; i++) {
+ g_string_append_printf(gstr, "'key%d': ", i);
+ gen_test_json(gstr, i, elem_count);
+ if (i < nest_level_max - 1) {
+ g_string_append(gstr, ",");
+ }
+ }
+ g_string_append(gstr, "}");
+}
+
+static void large_dict(void)
+{
+ GString *gstr = g_string_new("");
+ QObject *obj;
+
+ gen_test_json(gstr, 10, 100);
+ obj = qobject_from_json(gstr->str);
+ g_assert(obj != NULL);
+
+ qobject_decref(obj);
+ g_string_free(gstr, true);
+}
+
static void simple_list(void)
{
int i;
@@ -706,6 +758,7 @@ int main(int argc, char **argv)
g_test_add_func("/literals/keyword", keyword_literal);
g_test_add_func("/dicts/simple_dict", simple_dict);
+ g_test_add_func("/dicts/large_dict", large_dict);
g_test_add_func("/lists/simple_list", simple_list);
g_test_add_func("/whitespace/simple_whitespace", simple_whitespace);
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index cc671dd..55b16f8 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -125,6 +125,39 @@ class TestSingleDrive(ImageStreamingTestCase):
result = self.vm.qmp('block-stream', device='nonexistent')
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
+
+class TestSmallerBackingFile(ImageStreamingTestCase):
+ backing_len = 1 * 1024 * 1024 # MB
+ image_len = 2 * backing_len
+
+ def setUp(self):
+ self.create_image(backing_img, self.backing_len)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len))
+ self.vm = iotests.VM().add_drive(test_img)
+ self.vm.launch()
+
+ # If this hangs, then you are missing a fix to complete streaming when the
+ # end of the backing file is reached.
+ def test_stream(self):
+ self.assert_no_active_streams()
+
+ result = self.vm.qmp('block-stream', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ completed = False
+ while not completed:
+ for event in self.vm.get_qmp_events(wait=True):
+ if event['event'] == 'BLOCK_JOB_COMPLETED':
+ self.assert_qmp(event, 'data/type', 'stream')
+ self.assert_qmp(event, 'data/device', 'drive0')
+ self.assert_qmp(event, 'data/offset', self.image_len)
+ self.assert_qmp(event, 'data/len', self.image_len)
+ completed = True
+
+ self.assert_no_active_streams()
+ self.vm.shutdown()
+
+
class TestStreamStop(ImageStreamingTestCase):
image_len = 8 * 1024 * 1024 * 1024 # GB
@@ -225,8 +258,7 @@ class TestSetSpeed(ImageStreamingTestCase):
self.assert_no_active_streams()
result = self.vm.qmp('block-stream', device='drive0', speed=-1)
- self.assert_qmp(result, 'error/class', 'InvalidParameter')
- self.assert_qmp(result, 'error/data/name', 'speed')
+ self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_no_active_streams()
@@ -234,8 +266,7 @@ class TestSetSpeed(ImageStreamingTestCase):
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
- self.assert_qmp(result, 'error/class', 'InvalidParameter')
- self.assert_qmp(result, 'error/data/name', 'speed')
+ self.assert_qmp(result, 'error/class', 'GenericError')
self.cancel_and_wait()
diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out
index 3f8a935..2f7d390 100644
--- a/tests/qemu-iotests/030.out
+++ b/tests/qemu-iotests/030.out
@@ -1,5 +1,5 @@
-......
+.......
----------------------------------------------------------------------
-Ran 6 tests
+Ran 7 tests
OK
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index a749fcf..c5ae806 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -44,6 +44,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
_supported_os Linux
+_unsupported_qemu_io_options --nocache
size=128M
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
index 155a05e..cb510d6 100644
--- a/tests/qemu-iotests/039.out
+++ b/tests/qemu-iotests/039.out
@@ -26,6 +26,12 @@ incompatible_features 0x1
== Repairing the image file must succeed ==
ERROR OFLAG_COPIED: offset=8000000000050000 refcount=0
Repairing cluster 5 refcount=0 reference=1
+The following inconsistencies were found and repaired:
+
+ 0 leaked clusters
+ 1 corruptions
+
+Double checking the fixed image now...
No errors were found on the image.
incompatible_features 0x0
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 7782808..d534e94 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -105,16 +105,16 @@ _make_test_img()
# XXX(hch): have global image options?
$QEMU_IMG create -f $IMGFMT $extra_img_options $TEST_IMG $image_size | \
- sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" | \
- sed -e "s#$TEST_DIR#TEST_DIR#g" | \
- sed -e "s#$IMGFMT#IMGFMT#g" | \
- sed -e "s# encryption=off##g" | \
- sed -e "s# cluster_size=[0-9]\\+##g" | \
- sed -e "s# table_size=[0-9]\\+##g" | \
- sed -e "s# compat='[^']*'##g" | \
- sed -e "s# compat6=\\(on\\|off\\)##g" | \
- sed -e "s# static=\\(on\\|off\\)##g" | \
- sed -e "s# lazy_refcounts=\\(on\\|off\\)##g"
+ sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
+ -e "s#$TEST_DIR#TEST_DIR#g" \
+ -e "s#$IMGFMT#IMGFMT#g" \
+ -e "s# encryption=off##g" \
+ -e "s# cluster_size=[0-9]\\+##g" \
+ -e "s# table_size=[0-9]\\+##g" \
+ -e "s# compat='[^']*'##g" \
+ -e "s# compat6=\\(on\\|off\\)##g" \
+ -e "s# static=\\(on\\|off\\)##g" \
+ -e "s# lazy_refcounts=\\(on\\|off\\)##g"
}
_cleanup_test_img()
@@ -297,6 +297,20 @@ _supported_os()
_notrun "not suitable for this OS: $HOSTOS"
}
+_unsupported_qemu_io_options()
+{
+ for bad_opt
+ do
+ for opt in $QEMU_IO_OPTIONS
+ do
+ if [ "$bad_opt" = "$opt" ]
+ then
+ _notrun "not suitable for qemu-io option: $bad_opt"
+ fi
+ done
+ done
+}
+
# this test requires that a specified command (executable) exists
#
_require_command()
diff --git a/trace-events b/trace-events
index 6b12f83..04b0723 100644
--- a/trace-events
+++ b/trace-events
@@ -970,3 +970,11 @@ qxl_render_blit_guest_primary_initialized(void) ""
qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]"
qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d"
qxl_render_update_area_done(void *cookie) "%p"
+
+# hw/spapr_pci.c
+spapr_pci_msi(const char *msg, uint32_t n, uint32_t ca) "%s (device#%d, cfg=%x)"
+spapr_pci_msi_setup(const char *name, unsigned vector, uint64_t addr) "dev\"%s\" vector %u, addr=%"PRIx64
+spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %u"
+spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u"
+spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
+spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
diff --git a/trace/simple.c b/trace/simple.c
index b700ea3..d83681b 100644
--- a/trace/simple.c
+++ b/trace/simple.c
@@ -55,7 +55,7 @@ static unsigned int trace_idx;
static unsigned int writeout_idx;
static uint64_t dropped_events;
static FILE *trace_fp;
-static char *trace_file_name = NULL;
+static char *trace_file_name;
/* * Trace buffer entry */
typedef struct {
@@ -70,7 +70,7 @@ typedef struct {
uint64_t header_event_id; /* HEADER_EVENT_ID */
uint64_t header_magic; /* HEADER_MAGIC */
uint64_t header_version; /* HEADER_VERSION */
-} TraceRecordHeader;
+} TraceLogHeader;
static void read_from_buffer(unsigned int idx, void *dataptr, size_t size);
@@ -231,13 +231,11 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi
}
idx = old_idx % TRACE_BUF_LEN;
- /* To check later if threshold crossed */
- rec->next_tbuf_idx = new_idx % TRACE_BUF_LEN;
rec_off = idx;
- rec_off = write_to_buffer(rec_off, (uint8_t*)&event, sizeof(event));
- rec_off = write_to_buffer(rec_off, (uint8_t*)&timestamp_ns, sizeof(timestamp_ns));
- rec_off = write_to_buffer(rec_off, (uint8_t*)&rec_len, sizeof(rec_len));
+ rec_off = write_to_buffer(rec_off, &event, sizeof(event));
+ rec_off = write_to_buffer(rec_off, &timestamp_ns, sizeof(timestamp_ns));
+ rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len));
rec->tbuf_idx = idx;
rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN;
@@ -271,12 +269,11 @@ static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size
void trace_record_finish(TraceBufferRecord *rec)
{
- uint8_t temp_rec[sizeof(TraceRecord)];
- TraceRecord *record = (TraceRecord *) temp_rec;
- read_from_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
+ TraceRecord record;
+ read_from_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord));
smp_wmb(); /* write barrier before marking as valid */
- record->event |= TRACE_RECORD_VALID;
- write_to_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
+ record.event |= TRACE_RECORD_VALID;
+ write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord));
if ((trace_idx - writeout_idx) > TRACE_BUF_FLUSH_THRESHOLD) {
flush_trace_file(false);
@@ -295,7 +292,7 @@ void st_set_trace_file_enabled(bool enable)
flush_trace_file(true);
if (enable) {
- static const TraceRecordHeader header = {
+ static const TraceLogHeader header = {
.header_event_id = HEADER_EVENT_ID,
.header_magic = HEADER_MAGIC,
/* Older log readers will check for version at next location */
@@ -332,18 +329,12 @@ bool st_set_trace_file(const char *file)
{
st_set_trace_file_enabled(false);
- free(trace_file_name);
+ g_free(trace_file_name);
if (!file) {
- if (asprintf(&trace_file_name, CONFIG_TRACE_FILE, getpid()) < 0) {
- trace_file_name = NULL;
- return false;
- }
+ trace_file_name = g_strdup_printf(CONFIG_TRACE_FILE, getpid());
} else {
- if (asprintf(&trace_file_name, "%s", file) < 0) {
- trace_file_name = NULL;
- return false;
- }
+ trace_file_name = g_strdup_printf("%s", file);
}
st_set_trace_file_enabled(true);
diff --git a/trace/simple.h b/trace/simple.h
index 7e521c1..2ab96a8 100644
--- a/trace/simple.h
+++ b/trace/simple.h
@@ -29,7 +29,6 @@ void st_flush_trace_buffer(void);
typedef struct {
unsigned int tbuf_idx;
- unsigned int next_tbuf_idx;
unsigned int rec_off;
} TraceBufferRecord;
diff --git a/ui/vnc.c b/ui/vnc.c
index 312ad7f..385e345 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3061,7 +3061,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
if (strncmp(display, "unix:", 5) == 0)
vs->lsock = unix_connect(display+5);
else
- vs->lsock = inet_connect(display, true, NULL);
+ vs->lsock = inet_connect(display, true, NULL, NULL);
if (-1 == vs->lsock) {
g_free(vs->display);
vs->display = NULL;
diff --git a/vl.c b/vl.c
index a4a520f..7c577fa 100644
--- a/vl.c
+++ b/vl.c
@@ -63,6 +63,11 @@
#include <linux/ppdev.h>
#include <linux/parport.h>
#endif
+
+#ifdef CONFIG_SECCOMP
+#include "qemu-seccomp.h"
+#endif
+
#ifdef __sun__
#include <sys/stat.h>
#include <sys/ethernet.h>
@@ -293,6 +298,11 @@ static struct {
{ .driver = "qxl-vga", .flag = &default_vga },
};
+const char *qemu_get_vm_name(void)
+{
+ return qemu_name;
+}
+
static void res_free(void)
{
if (boot_splash_filedata != NULL) {
@@ -760,6 +770,26 @@ static int bt_parse(const char *opt)
return 1;
}
+static int parse_sandbox(QemuOpts *opts, void *opaque)
+{
+ /* FIXME: change this to true for 1.3 */
+ if (qemu_opt_get_bool(opts, "enable", false)) {
+#ifdef CONFIG_SECCOMP
+ if (seccomp_start() < 0) {
+ qerror_report(ERROR_CLASS_GENERIC_ERROR,
+ "failed to install seccomp syscall filter in the kernel");
+ return -1;
+ }
+#else
+ qerror_report(ERROR_CLASS_GENERIC_ERROR,
+ "sandboxing request but seccomp is not compiled into this build");
+ return -1;
+#endif
+ }
+
+ return 0;
+}
+
/***********************************************************/
/* QEMU Block devices */
@@ -1208,6 +1238,37 @@ QEMUMachine *find_default_machine(void)
return NULL;
}
+MachineInfoList *qmp_query_machines(Error **errp)
+{
+ MachineInfoList *mach_list = NULL;
+ QEMUMachine *m;
+
+ for (m = first_machine; m; m = m->next) {
+ MachineInfoList *entry;
+ MachineInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+ if (m->is_default) {
+ info->has_is_default = true;
+ info->is_default = true;
+ }
+
+ if (m->alias) {
+ info->has_alias = true;
+ info->alias = g_strdup(m->alias);
+ }
+
+ info->name = g_strdup(m->name);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = mach_list;
+ mach_list = entry;
+ }
+
+ return mach_list;
+}
+
/***********************************************************/
/* main execution loop */
@@ -1293,6 +1354,7 @@ static pid_t shutdown_pid;
static int powerdown_requested;
static int debug_requested;
static int suspend_requested;
+static int wakeup_requested;
static NotifierList suspend_notifiers =
NOTIFIER_LIST_INITIALIZER(suspend_notifiers);
static NotifierList wakeup_notifiers =
@@ -1347,6 +1409,13 @@ static int qemu_suspend_requested(void)
return r;
}
+static int qemu_wakeup_requested(void)
+{
+ int r = wakeup_requested;
+ wakeup_requested = 0;
+ return r;
+}
+
int qemu_powerdown_requested(void)
{
int r = powerdown_requested;
@@ -1395,7 +1464,7 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
}
}
-void qemu_system_reset(bool report)
+void qemu_devices_reset(void)
{
QEMUResetEntry *re, *nre;
@@ -1403,6 +1472,15 @@ void qemu_system_reset(bool report)
QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
re->func(re->opaque);
}
+}
+
+void qemu_system_reset(bool report)
+{
+ if (current_machine && current_machine->reset) {
+ current_machine->reset();
+ } else {
+ qemu_devices_reset();
+ }
if (report) {
monitor_protocol_event(QEVENT_RESET, NULL);
}
@@ -1452,9 +1530,8 @@ void qemu_system_wakeup_request(WakeupReason reason)
return;
}
runstate_set(RUN_STATE_RUNNING);
- monitor_protocol_event(QEVENT_WAKEUP, NULL);
notifier_list_notify(&wakeup_notifiers, &reason);
- reset_requested = 1;
+ wakeup_requested = 1;
qemu_notify_event();
}
@@ -1534,6 +1611,13 @@ static bool main_loop_should_exit(void)
runstate_set(RUN_STATE_PAUSED);
}
}
+ if (qemu_wakeup_requested()) {
+ pause_all_vcpus();
+ cpu_synchronize_all_states();
+ qemu_system_reset(VMRESET_SILENT);
+ resume_all_vcpus();
+ monitor_protocol_event(QEVENT_WAKEUP, NULL);
+ }
if (qemu_powerdown_requested()) {
monitor_protocol_event(QEVENT_POWERDOWN, NULL);
qemu_irq_raise(qemu_system_powerdown);
@@ -2651,6 +2735,7 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_m: {
int64_t value;
+ uint64_t sz;
char *end;
value = strtosz(optarg, &end);
@@ -2658,12 +2743,12 @@ int main(int argc, char **argv, char **envp)
fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
exit(1);
}
-
- if (value != (uint64_t)(ram_addr_t)value) {
+ sz = QEMU_ALIGN_UP((uint64_t)value, 8192);
+ ram_size = sz;
+ if (ram_size != sz) {
fprintf(stderr, "qemu: ram size too large\n");
exit(1);
}
- ram_size = value;
break;
}
case QEMU_OPTION_mempath:
@@ -3197,6 +3282,12 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_qtest_log:
qtest_log = optarg;
break;
+ case QEMU_OPTION_sandbox:
+ opts = qemu_opts_parse(qemu_find_opts("sandbox"), optarg, 1);
+ if (!opts) {
+ exit(0);
+ }
+ break;
default:
os_parse_cmd_args(popt->index, optarg);
}
@@ -3204,6 +3295,15 @@ int main(int argc, char **argv, char **envp)
}
loc_set_none();
+ if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
+ exit(1);
+ }
+
+ if (machine == NULL) {
+ fprintf(stderr, "No machine found.\n");
+ exit(1);
+ }
+
if (machine->hw_version) {
qemu_set_version(machine->hw_version);
}
@@ -3246,11 +3346,6 @@ int main(int argc, char **argv, char **envp)
data_dir = CONFIG_QEMU_DATADIR;
}
- if (machine == NULL) {
- fprintf(stderr, "No machine found.\n");
- exit(1);
- }
-
/*
* Default to max_cpus = smp_cpus, in case the user doesn't
* specify a max_cpus value.
diff --git a/xen-all.c b/xen-all.c
index 61def2e..f76b051 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -712,7 +712,8 @@ static void cpu_ioreq_pio(ioreq_t *req)
for (i = 0; i < req->count; i++) {
tmp = do_inp(req->addr, req->size);
- cpu_physical_memory_write(req->data + (sign * i * req->size),
+ cpu_physical_memory_write(
+ req->data + (sign * i * (int64_t)req->size),
(uint8_t *) &tmp, req->size);
}
}
@@ -723,7 +724,8 @@ static void cpu_ioreq_pio(ioreq_t *req)
for (i = 0; i < req->count; i++) {
uint32_t tmp = 0;
- cpu_physical_memory_read(req->data + (sign * i * req->size),
+ cpu_physical_memory_read(
+ req->data + (sign * i * (int64_t)req->size),
(uint8_t*) &tmp, req->size);
do_outp(req->addr, req->size, tmp);
}
@@ -740,12 +742,14 @@ static void cpu_ioreq_move(ioreq_t *req)
if (!req->data_is_ptr) {
if (req->dir == IOREQ_READ) {
for (i = 0; i < req->count; i++) {
- cpu_physical_memory_read(req->addr + (sign * i * req->size),
+ cpu_physical_memory_read(
+ req->addr + (sign * i * (int64_t)req->size),
(uint8_t *) &req->data, req->size);
}
} else if (req->dir == IOREQ_WRITE) {
for (i = 0; i < req->count; i++) {
- cpu_physical_memory_write(req->addr + (sign * i * req->size),
+ cpu_physical_memory_write(
+ req->addr + (sign * i * (int64_t)req->size),
(uint8_t *) &req->data, req->size);
}
}
@@ -754,16 +758,20 @@ static void cpu_ioreq_move(ioreq_t *req)
if (req->dir == IOREQ_READ) {
for (i = 0; i < req->count; i++) {
- cpu_physical_memory_read(req->addr + (sign * i * req->size),
+ cpu_physical_memory_read(
+ req->addr + (sign * i * (int64_t)req->size),
(uint8_t*) &tmp, req->size);
- cpu_physical_memory_write(req->data + (sign * i * req->size),
+ cpu_physical_memory_write(
+ req->data + (sign * i * (int64_t)req->size),
(uint8_t*) &tmp, req->size);
}
} else if (req->dir == IOREQ_WRITE) {
for (i = 0; i < req->count; i++) {
- cpu_physical_memory_read(req->data + (sign * i * req->size),
+ cpu_physical_memory_read(
+ req->data + (sign * i * (int64_t)req->size),
(uint8_t*) &tmp, req->size);
- cpu_physical_memory_write(req->addr + (sign * i * req->size),
+ cpu_physical_memory_write(
+ req->addr + (sign * i * (int64_t)req->size),
(uint8_t*) &tmp, req->size);
}
}
diff --git a/xen-mapcache.c b/xen-mapcache.c
index 59ba085..9cd6db3 100644
--- a/xen-mapcache.c
+++ b/xen-mapcache.c
@@ -320,10 +320,6 @@ void xen_invalidate_map_cache_entry(uint8_t *buffer)
target_phys_addr_t size;
int found = 0;
- if (mapcache->last_address_vaddr == buffer) {
- mapcache->last_address_index = -1;
- }
-
QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
if (reventry->vaddr_req == buffer) {
paddr_index = reventry->paddr_index;
@@ -342,6 +338,11 @@ void xen_invalidate_map_cache_entry(uint8_t *buffer)
QTAILQ_REMOVE(&mapcache->locked_entries, reventry, next);
g_free(reventry);
+ if (mapcache->last_address_index == paddr_index) {
+ mapcache->last_address_index = -1;
+ mapcache->last_address_vaddr = NULL;
+ }
+
entry = &mapcache->entry[paddr_index % mapcache->nr_buckets];
while (entry && (entry->paddr_index != paddr_index || entry->size != size)) {
pentry = entry;