diff options
445 files changed, 14000 insertions, 9385 deletions
diff --git a/.gitignore b/.gitignore index 0e3816918c..5fea65dc14 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ fsdev/virtfs-proxy-helper.pod *.tp *.vr *.d +!scripts/qemu-guest-agent/fsfreeze-hook.d *.o *.lo *.la diff --git a/MAINTAINERS b/MAINTAINERS index cf39e5a00a..35c260d549 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -98,6 +98,7 @@ S: Maintained F: target-ppc/ S390 +M: Richard Henderson <rth@twiddle.net> M: Alexander Graf <agraf@suse.de> S: Maintained F: target-s390x/ @@ -396,6 +397,7 @@ L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc_prep.c F: hw/prep_pci.[hc] +F: hw/pc87312.[hc] sPAPR M: David Gibson <david@gibson.dropbear.id.au> @@ -104,6 +104,14 @@ defconfig: -include config-all-devices.mak -include config-all-disas.mak +ifneq ($(wildcard config-host.mak),) +include $(SRC_PATH)/Makefile.objs +include $(SRC_PATH)/tests/Makefile +endif +ifeq ($(CONFIG_SMARTCARD_NSS),y) +include $(SRC_PATH)/libcacard/Makefile +endif + all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all config-host.h: config-host.h-timestamp @@ -116,12 +124,6 @@ SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) subdir-%: $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,) -ifneq ($(wildcard config-host.mak),) -include $(SRC_PATH)/Makefile.objs -endif - -subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o - subdir-pixman: pixman/Makefile $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,) @@ -131,11 +133,11 @@ pixman/Makefile: $(SRC_PATH)/pixman/configure $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) -$(SUBDIR_RULES): libqemustub.a +$(SUBDIR_RULES): libqemuutil.a libqemustub.a -$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) +$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(common-obj-y) $(extra-obj-y) -$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(user-obj-y) +$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(user-obj-y) ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) romsubdir-%: @@ -153,39 +155,22 @@ version.o: $(SRC_PATH)/version.rc config-host.h version-obj-$(CONFIG_WIN32) += version.o ###################################################################### -# Build library with stubs +# Build libraries libqemustub.a: $(stub-obj-y) - -###################################################################### -# Support building shared library libcacard - -.PHONY: libcacard.la install-libcacard -libcacard.la: $(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,) - -install-libcacard: libcacard.la - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,) +libqemuutil.a: $(util-obj-y) ###################################################################### qemu-img.o: qemu-img-cmds.h -tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ - main-loop.o iohandler.o error.o -tools-obj-$(CONFIG_POSIX) += compatfd.o - -qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemustub.a -qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemustub.a -qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemustub.a +qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a +qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a +qemu-io$(EXESUF): qemu-io.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o -vscclient$(EXESUF): LIBS += $(libcacard_libs) -vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o libqemustub.a - $(call 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): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o libqemuutil.a libqemustub.a fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx @@ -196,10 +181,6 @@ qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated gen-out-type = $(subst .,-,$(suffix $@)) -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 :\ @@ -225,15 +206,16 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemustub.a +qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) 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 - find . -name '*.[od]' -exec rm -f {} + + find . -name '*.[od]' -type f -exec rm -f {} + rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ + rm -f *.la rm -Rf .libs rm -f qemu-img-cmds.h @# May not be present in GENERATED_HEADERS @@ -280,6 +262,7 @@ bepo ifdef INSTALL_BLOBS BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \ +acpi-dsdt.aml q35-acpi-dsdt.aml \ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ diff --git a/Makefile.objs b/Makefile.objs index a3eab4b410..d465a72030 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -1,60 +1,31 @@ ####################################################################### -# Stub library, linked in tools +# Common libraries for tools and emulators stub-obj-y = stubs/ +util-obj-y = util/ qobject/ qapi/ trace/ ####################################################################### -# Target-independent parts used in system and user emulation -universal-obj-y = -universal-obj-y += qemu-log.o - -####################################################################### -# QObject -qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o -qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o -qobject-obj-y += qerror.o error.o qemu-error.o - -universal-obj-y += $(qobject-obj-y) - -####################################################################### -# QOM -qom-obj-y = qom/ - -universal-obj-y += $(qom-obj-y) - -####################################################################### -# oslib-obj-y is code depending on the OS (win32 vs posix) -oslib-obj-y = osdep.o cutils.o qemu-timer-common.o -oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o -oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o +# block-obj-y is code used by both qemu system emulation and qemu-img -####################################################################### -# coroutines -coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o -coroutine-obj-y += qemu-coroutine-sleep.o +block-obj-y = async.o thread-pool.o +block-obj-y += nbd.o block.o blockjob.o +block-obj-y += main-loop.o iohandler.o qemu-timer.o +block-obj-$(CONFIG_POSIX) += aio-posix.o +block-obj-$(CONFIG_WIN32) += aio-win32.o +block-obj-y += block/ +block-obj-y += qapi-types.o qapi-visit.o -# If you change this logic, please also check tests/Makefile +block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o +block-obj-y += qemu-coroutine-sleep.o ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) -coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o +block-obj-$(CONFIG_POSIX) += coroutine-ucontext.o else ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y) -coroutine-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o +block-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o else -coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o +block-obj-$(CONFIG_POSIX) += coroutine-gthread.o endif endif -coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o - -####################################################################### -# block-obj-y is code used by both qemu system emulation and qemu-img - -block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o -block-obj-y += nbd.o block.o blockjob.o aes.o qemu-config.o -block-obj-y += thread-pool.o qemu-progress.o qemu-sockets.o uri.o notify.o -block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y) -block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o -block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o -block-obj-y += block/ -block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o +block-obj-$(CONFIG_WIN32) += coroutine-win32.o ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. @@ -69,25 +40,19 @@ endif common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ -common-obj-y += qom/ common-obj-y += readline.o -common-obj-y += $(oslib-obj-y) common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o common-obj-$(CONFIG_LINUX) += fsdev/ extra-obj-$(CONFIG_LINUX) += fsdev/ -common-obj-y += tcg-runtime.o host-utils.o main-loop.o -common-obj-y += migration.o migration-tcp.o common-obj-y += migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o -common-obj-y += block-migration.o iohandler.o -common-obj-y += bitmap.o bitops.o +common-obj-y += block-migration.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 common-obj-$(CONFIG_SPICE) += spice-qemu-char.o @@ -99,9 +64,6 @@ common-obj-y += ui/ common-obj-y += bt-host.o bt-vhci.o common-obj-y += dma-helpers.o -common-obj-y += acl.o -common-obj-$(CONFIG_POSIX) += compatfd.o -common-obj-y += qemu-timer.o qemu-timer-common.o common-obj-y += qtest.o common-obj-y += vl.o @@ -116,30 +78,6 @@ common-obj-y += qemu-seccomp.o endif ###################################################################### -# libuser - -user-obj-y = -user-obj-y += envlist.o path.o -user-obj-y += tcg-runtime.o host-utils.o -user-obj-y += cache-utils.o -user-obj-y += module.o -user-obj-y += qemu-user.o -user-obj-y += qom/ - -###################################################################### -# disassemblers -# NOTE: the disassembler code is only needed for debugging - -universal-obj-y += disas/ - -###################################################################### -# trace - -trace-obj-y += trace/ - -universal-obj-y += $(trace-obj-y) - -###################################################################### # smartcard libcacard-y += libcacard/cac.o libcacard/event.o @@ -153,19 +91,24 @@ 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 -universal-obj-y += $(qapi-obj-y) +####################################################################### +# Target-independent parts used in system and user emulation +universal-obj-y = +universal-obj-y += qemu-log.o +universal-obj-y += tcg-runtime.o +universal-obj-y += hw/ +universal-obj-y += qom/ +universal-obj-y += disas/ ###################################################################### # guest agent -qga-obj-y = qga/ module.o qemu-tool.o -qga-obj-$(CONFIG_POSIX) += qemu-sockets.o qemu-option.o +# FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed +# by libqemuutil.a. These should be moved to a separate .json schema. +qga-obj-y = qga/ qapi-types.o qapi-visit.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) @@ -175,13 +118,10 @@ QEMU_CFLAGS+=$(GLIB_CFLAGS) nested-vars += \ stub-obj-y \ + util-obj-y \ qga-obj-y \ - qom-obj-y \ - qapi-obj-y \ block-obj-y \ - user-obj-y \ common-obj-y \ universal-obj-y \ - extra-obj-y \ - trace-obj-y + extra-obj-y dummy := $(call unnest-vars) diff --git a/Makefile.target b/Makefile.target index 5bfa496080..eb84b1f8e3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -54,7 +54,7 @@ $(QEMU_PROG).stp: $(SRC_PATH)/trace-events --binary=$(bindir)/$(QEMU_PROG) \ --target-arch=$(TARGET_ARCH) \ --target-type=$(TARGET_TYPE) \ - < $< > $@," GEN $(QEMU_PROG).stp") + < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp") else stap: endif @@ -83,7 +83,7 @@ ifdef CONFIG_LINUX_USER QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user obj-y += linux-user/ -obj-y += gdbstub.o thunk.o user-exec.o $(oslib-obj-y) +obj-y += gdbstub.o thunk.o user-exec.o endif #CONFIG_LINUX_USER @@ -95,7 +95,7 @@ ifdef CONFIG_BSD_USER QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH) obj-y += bsd-user/ -obj-y += gdbstub.o user-exec.o $(oslib-obj-y) +obj-y += gdbstub.o user-exec.o endif #CONFIG_BSD_USER @@ -146,21 +146,16 @@ include $(SRC_PATH)/Makefile.objs all-obj-y = $(obj-y) all-obj-y += $(addprefix ../, $(universal-obj-y)) - -ifdef CONFIG_SOFTMMU -all-obj-y += $(addprefix ../, $(common-obj-y)) -else -all-obj-y += $(addprefix ../, $(user-obj-y)) -endif #CONFIG_LINUX_USER +all-obj-$(CONFIG_SOFTMMU) += $(addprefix ../, $(common-obj-y)) ifdef QEMU_PROGW # The linker builds a windows executable. Make also a console executable. -$(QEMU_PROGW): $(all-obj-y) ../libqemustub.a +$(QEMU_PROGW): $(all-obj-y) ../libqemuutil.a ../libqemustub.a $(call LINK,$^) $(QEMU_PROG): $(QEMU_PROGW) $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)") else -$(QEMU_PROG): $(all-obj-y) ../libqemustub.a +$(QEMU_PROG): $(all-obj-y) ../libqemuutil.a ../libqemustub.a $(call LINK,$^) endif diff --git a/backends/rng-egd.c b/backends/rng-egd.c index fd41b53188..5e012e9e30 100644 --- a/backends/rng-egd.c +++ b/backends/rng-egd.c @@ -207,7 +207,7 @@ static void rng_egd_class_init(ObjectClass *klass, void *data) rbc->opened = rng_egd_opened; } -static TypeInfo rng_egd_info = { +static const TypeInfo rng_egd_info = { .name = TYPE_RNG_EGD, .parent = TYPE_RNG_BACKEND, .instance_size = sizeof(RngEgd), diff --git a/backends/rng-random.c b/backends/rng-random.c index d479ce8c56..0d1108811d 100644 --- a/backends/rng-random.c +++ b/backends/rng-random.c @@ -144,7 +144,7 @@ static void rng_random_class_init(ObjectClass *klass, void *data) rbc->opened = rng_random_opened; } -static TypeInfo rng_random_info = { +static const TypeInfo rng_random_info = { .name = TYPE_RNG_RANDOM, .parent = TYPE_RNG_BACKEND, .instance_size = sizeof(RndRandom), diff --git a/backends/rng.c b/backends/rng.c index 48a5840cd5..3d3389802e 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -76,7 +76,7 @@ static void rng_backend_init(Object *obj) NULL); } -static TypeInfo rng_backend_info = { +static const TypeInfo rng_backend_info = { .name = TYPE_RNG_BACKEND, .parent = TYPE_OBJECT, .instance_size = sizeof(RngBackend), @@ -3338,11 +3338,7 @@ char *get_human_readable_size(char *buf, int buf_size, int64_t size) char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) { char buf1[128], date_buf[128], clock_buf[128]; -#ifdef _WIN32 - struct tm *ptm; -#else struct tm tm; -#endif time_t ti; int64_t secs; @@ -3352,15 +3348,9 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); } else { ti = sn->date_sec; -#ifdef _WIN32 - ptm = localtime(&ti); - strftime(date_buf, sizeof(date_buf), - "%Y-%m-%d %H:%M:%S", ptm); -#else localtime_r(&ti, &tm); strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm); -#endif secs = sn->vm_clock_nsec / 1000000000; snprintf(clock_buf, sizeof(clock_buf), "%02d:%02d:%02d.%03d", diff --git a/block/iscsi.c b/block/iscsi.c index 041ee07de3..f08cf9663b 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -980,9 +980,36 @@ static BlockDriver bdrv_iscsi = { #endif }; +static QemuOptsList qemu_iscsi_opts = { + .name = "iscsi", + .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), + .desc = { + { + .name = "user", + .type = QEMU_OPT_STRING, + .help = "username for CHAP authentication to target", + },{ + .name = "password", + .type = QEMU_OPT_STRING, + .help = "password for CHAP authentication to target", + },{ + .name = "header-digest", + .type = QEMU_OPT_STRING, + .help = "HeaderDigest setting. " + "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", + },{ + .name = "initiator-name", + .type = QEMU_OPT_STRING, + .help = "Initiator iqn name to use when connecting", + }, + { /* end of list */ } + }, +}; + static void iscsi_block_init(void) { bdrv_register(&bdrv_iscsi); + qemu_add_opts(&qemu_iscsi_opts); } block_init(iscsi_block_init); diff --git a/block/vvfat.c b/block/vvfat.c index 83706ce556..06e6654824 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -529,13 +529,9 @@ static inline uint8_t fat_chksum(const direntry_t* entry) /* if return_time==0, this returns the fat_date, else the fat_time */ static uint16_t fat_datetime(time_t time,int return_time) { struct tm* t; -#ifdef _WIN32 - t=localtime(&time); /* this is not thread safe */ -#else struct tm t1; t = &t1; localtime_r(&time,t); -#endif if(return_time) return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11)); return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9)); diff --git a/blockdev.c b/blockdev.c index d724e2dc5b..9126587c45 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1427,3 +1427,121 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) bdrv_iterate(do_qmp_query_block_jobs_one, &prev); return dummy.next; } + +QemuOptsList qemu_drive_opts = { + .name = "drive", + .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head), + .desc = { + { + .name = "bus", + .type = QEMU_OPT_NUMBER, + .help = "bus number", + },{ + .name = "unit", + .type = QEMU_OPT_NUMBER, + .help = "unit number (i.e. lun for scsi)", + },{ + .name = "if", + .type = QEMU_OPT_STRING, + .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)", + },{ + .name = "index", + .type = QEMU_OPT_NUMBER, + .help = "index number", + },{ + .name = "cyls", + .type = QEMU_OPT_NUMBER, + .help = "number of cylinders (ide disk geometry)", + },{ + .name = "heads", + .type = QEMU_OPT_NUMBER, + .help = "number of heads (ide disk geometry)", + },{ + .name = "secs", + .type = QEMU_OPT_NUMBER, + .help = "number of sectors (ide disk geometry)", + },{ + .name = "trans", + .type = QEMU_OPT_STRING, + .help = "chs translation (auto, lba. none)", + },{ + .name = "media", + .type = QEMU_OPT_STRING, + .help = "media type (disk, cdrom)", + },{ + .name = "snapshot", + .type = QEMU_OPT_BOOL, + .help = "enable/disable snapshot mode", + },{ + .name = "file", + .type = QEMU_OPT_STRING, + .help = "disk image", + },{ + .name = "cache", + .type = QEMU_OPT_STRING, + .help = "host cache usage (none, writeback, writethrough, " + "directsync, unsafe)", + },{ + .name = "aio", + .type = QEMU_OPT_STRING, + .help = "host AIO implementation (threads, native)", + },{ + .name = "format", + .type = QEMU_OPT_STRING, + .help = "disk format (raw, qcow2, ...)", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "disk serial number", + },{ + .name = "rerror", + .type = QEMU_OPT_STRING, + .help = "read error action", + },{ + .name = "werror", + .type = QEMU_OPT_STRING, + .help = "write error action", + },{ + .name = "addr", + .type = QEMU_OPT_STRING, + .help = "pci address (virtio only)", + },{ + .name = "readonly", + .type = QEMU_OPT_BOOL, + .help = "open drive file as read-only", + },{ + .name = "iops", + .type = QEMU_OPT_NUMBER, + .help = "limit total I/O operations per second", + },{ + .name = "iops_rd", + .type = QEMU_OPT_NUMBER, + .help = "limit read operations per second", + },{ + .name = "iops_wr", + .type = QEMU_OPT_NUMBER, + .help = "limit write operations per second", + },{ + .name = "bps", + .type = QEMU_OPT_NUMBER, + .help = "limit total bytes per second", + },{ + .name = "bps_rd", + .type = QEMU_OPT_NUMBER, + .help = "limit read bytes per second", + },{ + .name = "bps_wr", + .type = QEMU_OPT_NUMBER, + .help = "limit write bytes per second", + },{ + .name = "copy-on-read", + .type = QEMU_OPT_BOOL, + .help = "copy read data from backing file into image file", + },{ + .name = "boot", + .type = QEMU_OPT_BOOL, + .help = "(deprecated, ignored)", + }, + { /* end of list */ } + }, +}; @@ -214,7 +214,6 @@ trace_backend="nop" trace_file="trace" spice="" rbd="" -smartcard="" smartcard_nss="" usb_redir="" opengl="" @@ -264,6 +263,8 @@ else fi ar="${AR-${cross_prefix}ar}" +as="${AS-${cross_prefix}as}" +cpp="${CPP-$cc -E}" objcopy="${OBJCOPY-${cross_prefix}objcopy}" ld="${LD-${cross_prefix}ld}" libtool="${LIBTOOL-${cross_prefix}libtool}" @@ -859,10 +860,6 @@ for opt do ;; --enable-xfsctl) xfs="yes" ;; - --disable-smartcard) smartcard="no" - ;; - --enable-smartcard) smartcard="yes" - ;; --disable-smartcard-nss) smartcard_nss="no" ;; --enable-smartcard-nss) smartcard_nss="yes" @@ -1126,8 +1123,6 @@ echo " --enable-spice enable spice" echo " --enable-rbd enable building the rados block device (rbd)" echo " --disable-libiscsi disable iscsi support" echo " --enable-libiscsi enable iscsi support" -echo " --disable-smartcard disable smartcard support" -echo " --enable-smartcard enable smartcard support" echo " --disable-smartcard-nss disable smartcard nss support" echo " --enable-smartcard-nss enable smartcard nss support" echo " --disable-usb-redir disable usb network redirection support" @@ -2705,7 +2700,7 @@ if compile_prog "" "" ; then byteswap_h=yes fi -# Search for bswap_32 function +# Search for bswap32 function bswap_h=no cat > $TMPC << EOF #include <sys/endian.h> @@ -2811,47 +2806,42 @@ EOF fi # check for libcacard for smartcard support -if test "$smartcard" != "no" ; then - smartcard="yes" - smartcard_cflags="" - # TODO - what's the minimal nss version we support? - if test "$smartcard_nss" != "no"; then - cat > $TMPC << EOF +smartcard_cflags="" +# TODO - what's the minimal nss version we support? +if test "$smartcard_nss" != "no"; then + cat > $TMPC << EOF #include <pk11pub.h> int main(void) { PK11_FreeSlot(0); return 0; } EOF - smartcard_includes="-I\$(SRC_PATH)/libcacard" - libcacard_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs" - libcacard_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags" - test_cflags="$libcacard_cflags" - # The header files in nss < 3.13.3 have a bug which causes them to - # emit a warning. If we're going to compile QEMU with -Werror, then - # test that the headers don't have this bug. Otherwise we would pass - # the configure test but fail to compile QEMU later. - if test "$werror" = "yes"; then - test_cflags="-Werror $test_cflags" - fi - if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \ - compile_prog "$test_cflags" "$libcacard_libs"; then - smartcard_nss="yes" - QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags" - QEMU_INCLUDES="$QEMU_INCLUDES $smartcard_includes" - libs_softmmu="$libcacard_libs $libs_softmmu" - else - if test "$smartcard_nss" = "yes"; then - feature_not_found "nss" - fi - smartcard_nss="no" + smartcard_includes="-I\$(SRC_PATH)/libcacard" + libcacard_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs" + libcacard_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags" + test_cflags="$libcacard_cflags" + # The header files in nss < 3.13.3 have a bug which causes them to + # emit a warning. If we're going to compile QEMU with -Werror, then + # test that the headers don't have this bug. Otherwise we would pass + # the configure test but fail to compile QEMU later. + if test "$werror" = "yes"; then + test_cflags="-Werror $test_cflags" + fi + if test -n "$libtool" && + $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \ + compile_prog "$test_cflags" "$libcacard_libs"; then + smartcard_nss="yes" + QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags" + QEMU_INCLUDES="$QEMU_INCLUDES $smartcard_includes" + libs_softmmu="$libcacard_libs $libs_softmmu" + else + if test "$smartcard_nss" = "yes"; then + feature_not_found "nss" fi + smartcard_nss="no" fi fi -if test "$smartcard" = "no" ; then - smartcard_nss="no" -fi # check for usbredirparser for usb network redirection support if test "$usb_redir" != "no" ; then - if $pkg_config --atleast-version=0.5.3 libusbredirparser-0.5 >/dev/null 2>&1 ; then + if $pkg_config --atleast-version=0.6 libusbredirparser-0.5 >/dev/null 2>&1 ; then usb_redir="yes" usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null) usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null) @@ -3076,7 +3066,7 @@ int main(void) { } EOF if compile_prog "-Werror" "" ; then - pragma_disable_unused_but_set=yes + pragma_diagnostic_available=yes fi ######################################## @@ -3201,9 +3191,6 @@ if test "$softmmu" = yes ; then tools="qemu-ga\$(EXESUF) $tools" fi fi - if test "$smartcard_nss" = "yes" ; then - tools="vscclient\$(EXESUF) $tools" - fi fi # Mac OS X ships with a broken assembler @@ -3592,10 +3579,6 @@ if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak fi -if test "$smartcard" = "yes" ; then - echo "CONFIG_SMARTCARD=y" >> $config_host_mak -fi - if test "$smartcard_nss" = "yes" ; then echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak echo "libcacard_libs=$libcacard_libs" >> $config_host_mak @@ -3646,8 +3629,8 @@ if test "$linux_magic_h" = "yes" ; then echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak fi -if test "$pragma_disable_unused_but_set" = "yes" ; then - echo "CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET=y" >> $config_host_mak +if test "$pragma_diagnostic_available" = "yes" ; then + echo "CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE=y" >> $config_host_mak fi if test "$valgrind_h" = "yes" ; then @@ -3719,13 +3702,21 @@ echo "MAKE=$make" >> $config_host_mak echo "INSTALL=$install" >> $config_host_mak echo "INSTALL_DIR=$install -d -m 0755" >> $config_host_mak echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak -echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak +if test -n "$libtool"; then + echo "INSTALL_PROG=\$(LIBTOOL) --mode=install $install -c -m 0755" >> $config_host_mak + echo "INSTALL_LIB=\$(LIBTOOL) --mode=install $install -c -m 0644" >> $config_host_mak +else + echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak + echo "INSTALL_LIB=$install -c -m 0644" >> $config_host_mak +fi 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 "AS=$as" >> $config_host_mak +echo "CPP=$cpp" >> $config_host_mak echo "OBJCOPY=$objcopy" >> $config_host_mak echo "LD=$ld" >> $config_host_mak echo "WINDRES=$windres" >> $config_host_mak @@ -4045,9 +4036,6 @@ fi if test "$target_softmmu" = "yes" ; then echo "CONFIG_SOFTMMU=y" >> $config_target_mak echo "LIBS+=$libs_softmmu $target_libs_softmmu" >> $config_target_mak - if test "$smartcard_nss" = "yes" ; then - echo "subdir-$target: subdir-libcacard" >> $config_host_mak - fi case "$target_arch2" in i386|x86_64) echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak @@ -4248,10 +4236,9 @@ DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32" DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas" DIRS="$DIRS roms/seabios roms/vgabios" DIRS="$DIRS qapi-generated" -DIRS="$DIRS libcacard libcacard/libcacard libcacard/trace" FILES="Makefile tests/tcg/Makefile qdict-test-data.txt" FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" -FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile" +FILES="$FILES tests/tcg/lm32/Makefile" FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" @@ -4277,9 +4264,10 @@ for rom in seabios vgabios ; do config_mak=roms/$rom/config.mak echo "# Automatically generated by configure - do not modify" > $config_mak echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak + echo "AS=$as" >> $config_mak echo "CC=$cc" >> $config_mak echo "BCC=bcc" >> $config_mak - echo "CPP=${cross_prefix}cpp" >> $config_mak + echo "CPP=$cpp" >> $config_mak echo "OBJCOPY=objcopy" >> $config_mak echo "IASL=iasl" >> $config_mak echo "LD=$ld" >> $config_mak diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index 2ed703a3ed..a9c30e9df4 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -200,7 +200,7 @@ Coroutine *qemu_coroutine_new(void) } #ifdef CONFIG_VALGRIND_H -#ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE /* Work around an unused variable in the valgrind.h macro... */ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif @@ -208,7 +208,7 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co) { VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id); } -#ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE #pragma GCC diagnostic error "-Wunused-but-set-variable" #endif #endif diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index d0fde7b93d..1f4a1cff61 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -8,6 +8,7 @@ CONFIG_M48T59=y CONFIG_VGA=y CONFIG_VGA_PCI=y CONFIG_SERIAL=y +CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCKBD=y CONFIG_FDC=y @@ -16,6 +17,7 @@ CONFIG_I82374=y CONFIG_OPENPIC=y CONFIG_PREP_PCI=y CONFIG_I82378=y +CONFIG_PC87312=y CONFIG_MACIO=y CONFIG_PCSPK=y CONFIG_CUDA=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index e4265b4978..5ff406caa5 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -8,13 +8,18 @@ CONFIG_M48T59=y CONFIG_VGA=y CONFIG_VGA_PCI=y CONFIG_SERIAL=y +CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCKBD=y CONFIG_FDC=y CONFIG_DMA=y +CONFIG_I82374=y CONFIG_OPENPIC=y CONFIG_PREP_PCI=y +CONFIG_I82378=y +CONFIG_PC87312=y CONFIG_MACIO=y +CONFIG_PCSPK=y CONFIG_CUDA=y CONFIG_ADB=y CONFIG_MAC_NVRAM=y diff --git a/disas/s390.c b/disas/s390.c index 0859dfa19f..25499ba419 100644 --- a/disas/s390.c +++ b/disas/s390.c @@ -589,6 +589,16 @@ static const struct s390_operand s390_operands[] = { 4, 32, S390_OPERAND_CCODE }, #define I8_32 46 /* 8 bit signed value starting at 32 */ { 8, 32, S390_OPERAND_SIGNED }, +#define U8_24 47 /* 8 bit unsigned value starting at 24 */ + { 8, 24, 0 }, +#define U8_32 48 /* 8 bit unsigned value starting at 32 */ + { 8, 32, 0 }, +#define I16_32 49 + { 16, 32, S390_OPERAND_SIGNED }, +#define M4_16 50 /* 4-bit condition-code starting at 12 */ + { 4, 16, S390_OPERAND_CCODE }, +#define I8_16 51 + { 8, 16, S390_OPERAND_SIGNED }, /* QEMU-END */ }; @@ -663,7 +673,9 @@ static const struct s390_operand s390_operands[] = This is just a workaround for existing code e.g. glibc. */ #define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 } /* efpc, sfpc */ #define INSTR_RRF_F0FF 4, { F_16,F_24,F_28,0,0,0 } /* e.g. madbr */ -#define INSTR_RRF_F0FF2 4, { F_24,F_16,F_28,0,0,0 } /* e.g. cpsdr */ +/* QEMU-MOD */ +#define INSTR_RRF_F0FF2 4, { F_24,F_28,F_16,0,0,0 } /* e.g. cpsdr */ +/* QEMU-END */ #define INSTR_RRF_F0FR 4, { F_24,F_16,R_28,0,0,0 } /* e.g. iedtr */ #define INSTR_RRF_FUFF 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. didbr */ #define INSTR_RRF_RURR 4, { R_24,R_28,R_16,U4_20,0,0 } /* e.g. .insn */ @@ -801,11 +813,35 @@ static const struct s390_operand s390_operands[] = #define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } /* QEMU-ADD: */ -#define INSTR_RIE_MRRP 6, { M4_32,R_8,R_12,J16_16,0,0 } /* e.g. crj */ +#define INSTR_RIE_MRRP 6, { M4_32, R_8, R_12, J16_16, 0, 0 } /* e.g. crj */ #define MASK_RIE_MRRP { 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff } -#define INSTR_RIE_MRIP 6, { M4_12,R_8,I8_32,J16_16,0,0 } /* e.g. cij */ +#define INSTR_RIE_MRIP 6, { M4_12, R_8, I8_32, J16_16, 0, 0 } /* e.g. cij */ #define MASK_RIE_MRIP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RIE_RRIII 6, { R_8, R_12, U8_16, U8_24, U8_32, 0 } /* risbg */ +#define MASK_RIE_RRIII { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_MRI 6, { M4_32, R_8, I16_16, 0, 0, 0 } /* e.g. cit */ +#define MASK_RIE_MRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_MRU 6, { M4_32, R_8, U16_16, 0, 0, 0 } /* e.g. clfit */ +#define MASK_RIE_MRU { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_RRI 6, { R_8, R_12, I16_16, 0, 0, 0 } +#define MASK_RIE_RRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RXY_URRD 6, { U8_8, D20_20, X_12, B_16, 0, 0 } +#define MASK_RXY_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_SIL_DRI 6, { D_20, B_16, I16_32, 0, 0, 0 } +#define MASK_SIL_DRI { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } + +#define INSTR_RSY_MRRD 6, { M4_12, R_8, D20_20, B_16, 0, 0 } +#define MASK_SRY_MRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RRF_MRR 6, { M4_16, R_24, R_28, 0, 0, 0 } +#define MASK_RRF_MRR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } + +#define INSTR_SIY_DRI 6, { D20_20, B_16, I8_16, 0, 0, 0 } +#define MASK_SIY_DRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } /* QEMU-END */ /* The opcode formats table (blueprints for .insn pseudo mnemonic). */ @@ -926,6 +962,30 @@ static const struct s390_opcode s390_opcodes[] = { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, +/* QEMU-ADD: */ + { "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "risbg", OP48(0xec0000000055LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "risbhg", OP48(0xec000000005dLL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "risblg", OP48(0xec0000000051LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rnsbg", OP48(0xec0000000054LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rosbg", OP48(0xec0000000056LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rxsbg", OP48(0xec0000000057LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "cit", OP48(0xec0000000072LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6}, + { "cgit", OP48(0xec0000000070LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6}, + { "clfit", OP48(0xec0000000073LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6}, + { "clgit", OP48(0xec0000000071LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6}, + { "ahik", OP48(0xec00000000d8LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "aghik", OP48(0xec00000000d9LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "alhsik", OP48(0xec00000000daLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "alghsik", OP48(0xec00000000dbLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, +/* QEMU-END */ { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0}, { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, @@ -985,6 +1045,20 @@ static const struct s390_opcode s390_opcodes[] = { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, +/* QEMU-ADD: */ + { "loc", OP48(0xeb00000000f2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "locg", OP48(0xeb00000000e2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "stoc", OP48(0xeb00000000f3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "stocg", OP48(0xeb00000000e3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "srak", OP48(0xeb00000000dcLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "slak", OP48(0xeb00000000ddLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "srlk", OP48(0xeb00000000deLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "sllk", OP48(0xeb00000000dfLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "asi", OP48(0xeb000000006aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "alsi", OP48(0xeb000000006eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "agsi", OP48(0xeb000000007aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "algsi", OP48(0xeb000000007eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, +/* QEMU-END */ { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0}, { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, @@ -993,6 +1067,17 @@ static const struct s390_opcode s390_opcodes[] = { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2}, { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, +/* QEMU-ADD: */ + { "mvhhi", OP16(0xe544LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "mvghi", OP16(0xe548LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "mvhi", OP16(0xe54cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "chhsi", OP16(0xe554LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clhhsi", OP16(0xe555LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "cghsi", OP16(0xe558LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clghsi", OP16(0xe559LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "chsi", OP16(0xe55cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clfhsi", OP16(0xe55dLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, +/* QEMU-END */ { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, @@ -1116,6 +1201,9 @@ static const struct s390_opcode s390_opcodes[] = { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, +/* QEMU-ADD: */ + { "pfd", OP48(0xe30000000036LL), MASK_RXY_URRD, INSTR_RXY_URRD, 3, 6}, +/* QEMU-END */ { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, @@ -1135,6 +1223,32 @@ static const struct s390_opcode s390_opcodes[] = { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4}, +/* QEMU-ADD: */ + { "exrl", OP16(0xc600ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "pfdrl", OP16(0xc602ll), MASK_RIL_UP, INSTR_RIL_UP, 3, 6}, + { "cghrl", OP16(0xc604ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "chrl", OP16(0xc605ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clghrl", OP16(0xc606ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clhrl", OP16(0xc607ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "cgrl", OP16(0xc608ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clgrl", OP16(0xc60all), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "cgfrl", OP16(0xc60cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "crl", OP16(0xc60dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clgfrl", OP16(0xc60ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clrl", OP16(0xc60fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + + { "llhrl", OP16(0xc400ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lghrl", OP16(0xc404ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lhrl", OP16(0xc405ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "llghrl", OP16(0xc406ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "sthrl", OP16(0xc407ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "stgrl", OP16(0xc40bll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "llgfrl", OP16(0xc40ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "strl", OP16(0xc40fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, +/* QEMU-END */ { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, @@ -1265,6 +1379,29 @@ static const struct s390_opcode s390_opcodes[] = { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, +/* QEMU-ADD: */ + { "crt", OP16(0xb972LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "cgrt", OP16(0xb960LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "clrt", OP16(0xb973LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "clgrt", OP16(0xb961LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "locr", OP16(0xb9f2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6}, + { "locgr", OP16(0xb9e2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6}, + { "popcnt", OP16(0xb9e1LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 6}, + { "ngrk", OP16(0xb9e4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ogrk", OP16(0xb9e6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "xgrk", OP16(0xb9e7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "agrk", OP16(0xb9e8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "sgrk", OP16(0xb9e9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "algrk", OP16(0xb9eaLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "slgrk", OP16(0xb9ebLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "nrk", OP16(0xb9f4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ork", OP16(0xb9f6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "xrk", OP16(0xb9f7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ark", OP16(0xb9f8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "srk", OP16(0xb9f9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "alrk", OP16(0xb9faLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "slrk", OP16(0xb9fbLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, +/* QEMU-END */ { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, @@ -1426,6 +1563,20 @@ static const struct s390_opcode s390_opcodes[] = { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, +/* QEMU-ADD: */ + { "clfebr", OP16(0xb39cLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clfdbr", OP16(0xb39dLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clfxbr", OP16(0xb39eLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgebr", OP16(0xb3acLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgdbr", OP16(0xb3adLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgxbr", OP16(0xb3aeLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "celfbr", OP16(0xb390LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cdlfbr", OP16(0xb391LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cxlfbr", OP16(0xb392LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "celgbr", OP16(0xb3a0LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cdlgbr", OP16(0xb3a1LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cxlgbr", OP16(0xb3a2LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, +/* QEMU-END */ { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0}, { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5}, { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5}, @@ -1774,22 +1925,6 @@ static const struct s390_opcode s390_opcodes[] = { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0}, { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0}, { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0}, - -/* QEMU-ADD: */ - { "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - - { "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - - { "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, -/* QEMU-END */ }; static const int s390_num_opcodes = diff --git a/docs/q35-chipset.cfg b/docs/q35-chipset.cfg new file mode 100644 index 0000000000..1b6efc0f2c --- /dev/null +++ b/docs/q35-chipset.cfg @@ -0,0 +1,129 @@ +################################################################ +# +# qemu -M q35 creates a bare machine with just the very essential +# chipset devices being present: +# +# 00.0 - Host bridge +# 1f.0 - ISA bridge / LPC +# 1f.2 - SATA (AHCI) controller +# 1f.3 - SMBus controller +# +# This config file documents the other devices and how they are +# created. You can simply use "-readconfig $thisfile" to create +# them all. Here is a overview: +# +# 19.0 - Ethernet controller (not created, our e1000 emulation +# doesn't emulate the ich9 device). +# 1a.* - USB Controller #2 (ehci + uhci companions) +# 1b.0 - HD Audio Controller +# 1c.* - PCI Express Ports +# 1d.* - USB Controller #1 (ehci + uhci companions, +# "qemu -M q35 -usb" creates these too) +# 1e.0 - PCI Bridge +# + +[device "ich9-ehci-2"] + driver = "ich9-usb-ehci2" + multifunction = "on" + bus = "pcie.0" + addr = "1a.7" + +[device "ich9-uhci-4"] + driver = "ich9-usb-uhci4" + multifunction = "on" + bus = "pcie.0" + addr = "1a.0" + masterbus = "ich9-ehci-2.0" + firstport = "0" + +[device "ich9-uhci-5"] + driver = "ich9-usb-uhci5" + multifunction = "on" + bus = "pcie.0" + addr = "1a.1" + masterbus = "ich9-ehci-2.0" + firstport = "2" + +[device "ich9-uhci-6"] + driver = "ich9-usb-uhci6" + multifunction = "on" + bus = "pcie.0" + addr = "1a.2" + masterbus = "ich9-ehci-2.0" + firstport = "4" + + +[device "ich9-hda-audio"] + driver = "ich9-intel-hda" + bus = "pcie.0" + addr = "1b.0" + + +[device "ich9-pcie-port-1"] + driver = "ioh3420" + multifunction = "on" + bus = "pcie.0" + addr = "1c.0" + port = "1" + chassis = "1" + +[device "ich9-pcie-port-2"] + driver = "ioh3420" + multifunction = "on" + bus = "pcie.0" + addr = "1c.1" + port = "2" + chassis = "2" + +[device "ich9-pcie-port-3"] + driver = "ioh3420" + multifunction = "on" + bus = "pcie.0" + addr = "1c.2" + port = "3" + chassis = "3" + +[device "ich9-pcie-port-4"] + driver = "ioh3420" + multifunction = "on" + bus = "pcie.0" + addr = "1c.3" + port = "4" + chassis = "4" + + +[device "ich9-ehci-1"] + driver = "ich9-usb-ehci1" + multifunction = "on" + bus = "pcie.0" + addr = "1d.7" + +[device "ich9-uhci-1"] + driver = "ich9-usb-uhci1" + multifunction = "on" + bus = "pcie.0" + addr = "1d.0" + masterbus = "ich9-ehci-1.0" + firstport = "0" + +[device "ich9-uhci-2"] + driver = "ich9-usb-uhci2" + multifunction = "on" + bus = "pcie.0" + addr = "1d.1" + masterbus = "ich9-ehci-1.0" + firstport = "2" + +[device "ich9-uhci-3"] + driver = "ich9-usb-uhci3" + multifunction = "on" + bus = "pcie.0" + addr = "1d.2" + masterbus = "ich9-ehci-1.0" + firstport = "4" + + +[device "ich9-pci-bridge"] + driver = "i82801b11-bridge" + bus = "pcie.0" + addr = "1e.0" @@ -78,7 +78,7 @@ DEFINE_TLS(CPUArchState *,cpu_single_env); /* 0 = Do not count executed instructions. 1 = Precise instruction counting. 2 = Adaptive rate instruction counting. */ -int use_icount = 0; +int use_icount; #if !defined(CONFIG_USER_ONLY) diff --git a/fsdev/Makefile.objs b/fsdev/Makefile.objs index cb1e2500b9..ee16ca600c 100644 --- a/fsdev/Makefile.objs +++ b/fsdev/Makefile.objs @@ -7,3 +7,4 @@ extra-obj-y = qemu-fsdev-dummy.o else common-obj-y = qemu-fsdev-dummy.o endif +common-obj-y += qemu-fsdev-opts.o diff --git a/fsdev/qemu-fsdev-dummy.c b/fsdev/qemu-fsdev-dummy.c index 4bcf38fe4b..7dc2630a78 100644 --- a/fsdev/qemu-fsdev-dummy.c +++ b/fsdev/qemu-fsdev-dummy.c @@ -20,10 +20,3 @@ int qemu_fsdev_add(QemuOpts *opts) { return 0; } - -static void fsdev_register_config(void) -{ - qemu_add_opts(&qemu_fsdev_opts); - qemu_add_opts(&qemu_virtfs_opts); -} -machine_init(fsdev_register_config); diff --git a/fsdev/qemu-fsdev-opts.c b/fsdev/qemu-fsdev-opts.c new file mode 100644 index 0000000000..6311c7a7e5 --- /dev/null +++ b/fsdev/qemu-fsdev-opts.c @@ -0,0 +1,85 @@ +/* + * Virtio 9p + * + * 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/config-file.h" +#include "qemu/option.h" +#include "qemu/module.h" + +static QemuOptsList qemu_fsdev_opts = { + .name = "fsdev", + .implied_opt_name = "fsdriver", + .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head), + .desc = { + { + .name = "fsdriver", + .type = QEMU_OPT_STRING, + }, { + .name = "path", + .type = QEMU_OPT_STRING, + }, { + .name = "security_model", + .type = QEMU_OPT_STRING, + }, { + .name = "writeout", + .type = QEMU_OPT_STRING, + }, { + .name = "readonly", + .type = QEMU_OPT_BOOL, + + }, { + .name = "socket", + .type = QEMU_OPT_STRING, + }, { + .name = "sock_fd", + .type = QEMU_OPT_NUMBER, + }, + + { /*End of list */ } + }, +}; + +static QemuOptsList qemu_virtfs_opts = { + .name = "virtfs", + .implied_opt_name = "fsdriver", + .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head), + .desc = { + { + .name = "fsdriver", + .type = QEMU_OPT_STRING, + }, { + .name = "path", + .type = QEMU_OPT_STRING, + }, { + .name = "mount_tag", + .type = QEMU_OPT_STRING, + }, { + .name = "security_model", + .type = QEMU_OPT_STRING, + }, { + .name = "writeout", + .type = QEMU_OPT_STRING, + }, { + .name = "readonly", + .type = QEMU_OPT_BOOL, + }, { + .name = "socket", + .type = QEMU_OPT_STRING, + }, { + .name = "sock_fd", + .type = QEMU_OPT_NUMBER, + }, + + { /*End of list */ } + }, +}; + +static void fsdev_register_config(void) +{ + qemu_add_opts(&qemu_fsdev_opts); + qemu_add_opts(&qemu_virtfs_opts); +} +machine_init(fsdev_register_config); diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c index 4cc04d4fde..6eaf36dbfa 100644 --- a/fsdev/qemu-fsdev.c +++ b/fsdev/qemu-fsdev.c @@ -97,11 +97,3 @@ FsDriverEntry *get_fsdev_fsentry(char *id) } return NULL; } - -static void fsdev_register_config(void) -{ - qemu_add_opts(&qemu_fsdev_opts); - qemu_add_opts(&qemu_virtfs_opts); -} -machine_init(fsdev_register_config); - @@ -40,6 +40,7 @@ #include "cpu.h" #include "qemu/sockets.h" #include "sysemu/kvm.h" +#include "qemu/bitops.h" #ifndef TARGET_CPU_MEMORY_RW_DEBUG static inline int target_memory_rw_debug(CPUArchState *env, target_ulong addr, @@ -1535,27 +1536,34 @@ static int cpu_gdb_write_register(CPUAlphaState *env, uint8_t *mem_buf, int n) } #elif defined (TARGET_S390X) -#define NUM_CORE_REGS S390_NUM_TOTAL_REGS +#define NUM_CORE_REGS S390_NUM_REGS static int cpu_gdb_read_register(CPUS390XState *env, uint8_t *mem_buf, int n) { + uint64_t val; + int cc_op; + switch (n) { - case S390_PSWM_REGNUM: GET_REGL(env->psw.mask); break; - case S390_PSWA_REGNUM: GET_REGL(env->psw.addr); break; - case S390_R0_REGNUM ... S390_R15_REGNUM: - GET_REGL(env->regs[n-S390_R0_REGNUM]); break; - case S390_A0_REGNUM ... S390_A15_REGNUM: - GET_REG32(env->aregs[n-S390_A0_REGNUM]); break; - case S390_FPC_REGNUM: GET_REG32(env->fpc); break; - case S390_F0_REGNUM ... S390_F15_REGNUM: - /* XXX */ - break; - case S390_PC_REGNUM: GET_REGL(env->psw.addr); break; - case S390_CC_REGNUM: - env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, - env->cc_vr); - GET_REG32(env->cc_op); - break; + case S390_PSWM_REGNUM: + cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); + val = deposit64(env->psw.mask, 44, 2, cc_op); + GET_REGL(val); + break; + case S390_PSWA_REGNUM: + GET_REGL(env->psw.addr); + break; + case S390_R0_REGNUM ... S390_R15_REGNUM: + GET_REGL(env->regs[n-S390_R0_REGNUM]); + break; + case S390_A0_REGNUM ... S390_A15_REGNUM: + GET_REG32(env->aregs[n-S390_A0_REGNUM]); + break; + case S390_FPC_REGNUM: + GET_REG32(env->fpc); + break; + case S390_F0_REGNUM ... S390_F15_REGNUM: + GET_REG64(env->fregs[n-S390_F0_REGNUM].ll); + break; } return 0; @@ -1570,20 +1578,30 @@ static int cpu_gdb_write_register(CPUS390XState *env, uint8_t *mem_buf, int n) tmp32 = ldl_p(mem_buf); switch (n) { - case S390_PSWM_REGNUM: env->psw.mask = tmpl; break; - case S390_PSWA_REGNUM: env->psw.addr = tmpl; break; - case S390_R0_REGNUM ... S390_R15_REGNUM: - env->regs[n-S390_R0_REGNUM] = tmpl; break; - case S390_A0_REGNUM ... S390_A15_REGNUM: - env->aregs[n-S390_A0_REGNUM] = tmp32; r=4; break; - case S390_FPC_REGNUM: env->fpc = tmp32; r=4; break; - case S390_F0_REGNUM ... S390_F15_REGNUM: - /* XXX */ - break; - case S390_PC_REGNUM: env->psw.addr = tmpl; break; - case S390_CC_REGNUM: env->cc_op = tmp32; r=4; break; + case S390_PSWM_REGNUM: + env->psw.mask = tmpl; + env->cc_op = extract64(tmpl, 44, 2); + break; + case S390_PSWA_REGNUM: + env->psw.addr = tmpl; + break; + case S390_R0_REGNUM ... S390_R15_REGNUM: + env->regs[n-S390_R0_REGNUM] = tmpl; + break; + case S390_A0_REGNUM ... S390_A15_REGNUM: + env->aregs[n-S390_A0_REGNUM] = tmp32; + r = 4; + break; + case S390_FPC_REGNUM: + env->fpc = tmp32; + r = 4; + break; + case S390_F0_REGNUM ... S390_F15_REGNUM: + env->fregs[n-S390_F0_REGNUM].ll = tmpl; + break; + default: + return 0; } - return r; } #elif defined (TARGET_LM32) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index f16ccfbed1..6f427dfc5d 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -177,7 +177,7 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) dc->reset = virtio_pci_reset; } -static TypeInfo virtio_9p_info = { +static const TypeInfo virtio_9p_info = { .name = "virtio-9p-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), diff --git a/hw/Makefile.objs b/hw/Makefile.objs index b8bbed39c1..aa55ce9873 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,3 +1,8 @@ +# core qdev-related obj files, also used by *-user: +universal-obj-y += qdev.o qdev-properties.o +# irq.o needed for qdev GPIO handling: +universal-obj-y += irq.o + common-obj-y = usb/ ide/ pci/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o @@ -31,7 +36,7 @@ common-obj-$(CONFIG_DMA) += dma.o common-obj-$(CONFIG_I82374) += i82374.o common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_APPLESMC) += applesmc.o -common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o +common-obj-y += ccid-card-passthru.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o common-obj-y += fifo.o @@ -42,6 +47,7 @@ extra-obj-y += pci/ # PPC devices common-obj-$(CONFIG_PREP_PCI) += prep_pci.o common-obj-$(CONFIG_I82378) += i82378.o +common-obj-$(CONFIG_PC87312) += pc87312.o # Mac shared devices common-obj-$(CONFIG_MACIO) += macio.o common-obj-$(CONFIG_CUDA) += cuda.o @@ -154,7 +160,6 @@ common-obj-$(CONFIG_SOUND) += $(sound-obj-y) common-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ common-obj-y += usb/ -common-obj-y += irq.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_MAX7310) += max7310.o common-obj-$(CONFIG_WM8750) += wm8750.o @@ -180,7 +185,7 @@ common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += msmouse.o ps2.o -common-obj-y += qdev.o qdev-properties.o qdev-monitor.o +common-obj-y += qdev-monitor.o common-obj-y += qdev-properties-system.o common-obj-$(CONFIG_BRLAPI) += baum.o diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c index fc0a02ae86..30983efc03 100644 --- a/hw/a15mpcore.c +++ b/hw/a15mpcore.c @@ -93,7 +93,7 @@ static void a15mp_priv_class_init(ObjectClass *klass, void *data) /* We currently have no savable state */ } -static TypeInfo a15mp_priv_info = { +static const TypeInfo a15mp_priv_info = { .name = "a15mpcore_priv", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(A15MPPrivState), diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index f802de0824..184734f9b1 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -226,7 +226,7 @@ static void a9mp_priv_class_init(ObjectClass *klass, void *data) dc->reset = a9mp_priv_reset; } -static TypeInfo a9mp_priv_info = { +static const TypeInfo a9mp_priv_info = { .name = "a9mpcore_priv", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(a9mp_priv_state), @@ -1423,7 +1423,7 @@ static void ac97_class_init (ObjectClass *klass, void *data) dc->props = ac97_properties; } -static TypeInfo ac97_info = { +static const TypeInfo ac97_info = { .name = "AC97", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof (AC97LinkState), diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 06a8aca9cb..2f84b4ed4c 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -487,7 +487,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) dc->props = piix4_pm_properties; } -static TypeInfo piix4_pm_info = { +static const TypeInfo piix4_pm_info = { .name = "PIIX4_PM", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX4PMState), diff --git a/hw/ads7846.c b/hw/ads7846.c index fa137e628e..29e5585d91 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -162,7 +162,7 @@ static void ads7846_class_init(ObjectClass *klass, void *data) k->transfer = ads7846_transfer; } -static TypeInfo ads7846_info = { +static const TypeInfo ads7846_info = { .name = "ads7846", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ADS7846State), diff --git a/hw/apb_pci.c b/hw/apb_pci.c index c22e2b0fc3..b9a7ee6a31 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -486,7 +486,7 @@ static void pbm_pci_host_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_HOST; } -static TypeInfo pbm_pci_host_info = { +static const TypeInfo pbm_pci_host_info = { .name = "pbm-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -502,7 +502,7 @@ static void pbm_host_class_init(ObjectClass *klass, void *data) dc->reset = pci_pbm_reset; } -static TypeInfo pbm_host_info = { +static const TypeInfo pbm_host_info = { .name = "pbm", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(APBState), @@ -525,7 +525,7 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pci_device; } -static TypeInfo pbm_pci_bridge_info = { +static const TypeInfo pbm_pci_bridge_info = { .name = "pbm-bridge", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBridge), @@ -895,7 +895,7 @@ static void apic_class_init(ObjectClass *klass, void *data) k->post_load = apic_post_load; } -static TypeInfo apic_info = { +static const TypeInfo apic_info = { .name = "apic", .instance_size = sizeof(APICCommonState), .parent = TYPE_APIC_COMMON, diff --git a/hw/apic_common.c b/hw/apic_common.c index 0658be93c1..6e1b1e0320 100644 --- a/hw/apic_common.c +++ b/hw/apic_common.c @@ -385,7 +385,7 @@ static void apic_common_class_init(ObjectClass *klass, void *data) sc->init = apic_init_common; } -static TypeInfo apic_common_type = { +static const TypeInfo apic_common_type = { .name = TYPE_APIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(APICCommonState), diff --git a/hw/applesmc.c b/hw/applesmc.c index c564b60c0a..5a8c4ff2d2 100644 --- a/hw/applesmc.c +++ b/hw/applesmc.c @@ -236,7 +236,7 @@ static void qdev_applesmc_class_init(ObjectClass *klass, void *data) dc->props = applesmc_isa_properties; } -static TypeInfo applesmc_isa_info = { +static const TypeInfo applesmc_isa_info = { .name = "isa-applesmc", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(struct AppleSMCStatus), diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index 093331124a..469f6bfdee 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -222,7 +222,7 @@ static void mpcore_rirq_class_init(ObjectClass *klass, void *data) dc->props = mpcore_rirq_properties; } -static TypeInfo mpcore_rirq_info = { +static const TypeInfo mpcore_rirq_info = { .name = "realview_mpcore", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mpcore_rirq_state), @@ -252,7 +252,7 @@ static void mpcore_priv_class_init(ObjectClass *klass, void *data) dc->props = mpcore_priv_properties; } -static TypeInfo mpcore_priv_info = { +static const TypeInfo mpcore_priv_info = { .name = "arm11mpcore_priv", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mpcore_priv_state), diff --git a/hw/arm_gic.c b/hw/arm_gic.c index b6062c4241..466dbf7398 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -703,7 +703,7 @@ static void arm_gic_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo arm_gic_info = { +static const TypeInfo arm_gic_info = { .name = TYPE_ARM_GIC, .parent = TYPE_ARM_GIC_COMMON, .instance_size = sizeof(GICState), diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 73ae331807..41799ad765 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -171,7 +171,7 @@ static void arm_gic_common_class_init(ObjectClass *klass, void *data) sc->init = arm_gic_common_init; } -static TypeInfo arm_gic_common_type = { +static const TypeInfo arm_gic_common_type = { .name = TYPE_ARM_GIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GICState), diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c index 6abf0ee160..ae1e51d009 100644 --- a/hw/arm_l2x0.c +++ b/hw/arm_l2x0.c @@ -179,7 +179,7 @@ static void l2x0_class_init(ObjectClass *klass, void *data) dc->reset = l2x0_priv_reset; } -static TypeInfo l2x0_info = { +static const TypeInfo l2x0_info = { .name = "l2x0", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(l2x0_state), diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 1febaeb7b1..0cd3853a36 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -329,7 +329,7 @@ static void arm_mptimer_class_init(ObjectClass *klass, void *data) dc->props = arm_mptimer_properties; } -static TypeInfo arm_mptimer_info = { +static const TypeInfo arm_mptimer_info = { .name = "arm_mptimer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(arm_mptimer_state), diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index b733617aa0..a196fcc4aa 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -410,7 +410,7 @@ static void arm_sysctl_class_init(ObjectClass *klass, void *data) dc->props = arm_sysctl_properties; } -static TypeInfo arm_sysctl_info = { +static const TypeInfo arm_sysctl_info = { .name = "realview_sysctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(arm_sysctl_state), diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 37e28e993c..c1e56be74e 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -361,7 +361,7 @@ static void icp_pit_class_init(ObjectClass *klass, void *data) sdc->init = icp_pit_init; } -static TypeInfo icp_pit_info = { +static const TypeInfo icp_pit_info = { .name = "integrator_pit", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pit_state), @@ -383,7 +383,7 @@ static void sp804_class_init(ObjectClass *klass, void *data) k->props = sp804_properties; } -static TypeInfo sp804_info = { +static const TypeInfo sp804_info = { .name = "sp804", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(sp804_state), diff --git a/hw/armv7m.c b/hw/armv7m.c index ce2ec9b4dc..98fe483c25 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -269,7 +269,7 @@ static void bitband_class_init(ObjectClass *klass, void *data) dc->props = bitband_properties; } -static TypeInfo bitband_info = { +static const TypeInfo bitband_info = { .name = "ARM,bitband-memory", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BitBandState), diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 0907e42c0c..d5798d0309 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -535,7 +535,7 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data) dc->reset = armv7m_nvic_reset; } -static TypeInfo armv7m_nvic_info = { +static const TypeInfo armv7m_nvic_info = { .name = TYPE_NVIC, .parent = TYPE_ARM_GIC_COMMON, .instance_init = armv7m_nvic_instance_init, diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c index 44ed7f4d61..114508fade 100644 --- a/hw/bitbang_i2c.c +++ b/hw/bitbang_i2c.c @@ -230,7 +230,7 @@ static void gpio_i2c_class_init(ObjectClass *klass, void *data) dc->desc = "Virtual GPIO to I2C bridge"; } -static TypeInfo gpio_i2c_info = { +static const TypeInfo gpio_i2c_info = { .name = "gpio_i2c", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GPIOI2CState), diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index 40a239973c..2beee6268e 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -1218,7 +1218,7 @@ static void gem_class_init(ObjectClass *klass, void *data) dc->reset = gem_reset; } -static TypeInfo gem_info = { +static const TypeInfo gem_info = { .class_init = gem_class_init, .name = "cadence_gem", .parent = TYPE_SYS_BUS_DEVICE, diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c index 9e1cb1f152..2a8fadd810 100644 --- a/hw/cadence_ttc.c +++ b/hw/cadence_ttc.c @@ -474,7 +474,7 @@ static void cadence_ttc_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_cadence_ttc; } -static TypeInfo cadence_ttc_info = { +static const TypeInfo cadence_ttc_info = { .name = "cadence_ttc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CadenceTTCState), diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c index 7dd2fe54ed..cf2f53c81c 100644 --- a/hw/cadence_uart.c +++ b/hw/cadence_uart.c @@ -501,7 +501,7 @@ static void cadence_uart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_cadence_uart; } -static TypeInfo cadence_uart_info = { +static const TypeInfo cadence_uart_info = { .name = "cadence_uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(UartState), diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c index 6fd44695ae..c8f8ba3792 100644 --- a/hw/ccid-card-emulated.c +++ b/hw/ccid-card-emulated.c @@ -587,7 +587,7 @@ static void emulated_class_initfn(ObjectClass *klass, void *data) dc->props = emulated_card_properties; } -static TypeInfo emulated_card_info = { +static const TypeInfo emulated_card_info = { .name = EMULATED_DEV_NAME, .parent = TYPE_CCID_CARD, .instance_size = sizeof(EmulatedState), diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c index 4be05471a9..984bd0bf4c 100644 --- a/hw/ccid-card-passthru.c +++ b/hw/ccid-card-passthru.c @@ -336,7 +336,7 @@ static void passthru_class_initfn(ObjectClass *klass, void *data) dc->props = passthru_card_properties; } -static TypeInfo passthru_card_info = { +static const TypeInfo passthru_card_info = { .name = PASSTHRU_DEV_NAME, .parent = TYPE_CCID_CARD, .instance_size = sizeof(PassthruState), diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 80510bc9af..2a2c8dad62 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2933,7 +2933,7 @@ static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) dc->props = isa_vga_cirrus_properties; } -static TypeInfo isa_cirrus_vga_info = { +static const TypeInfo isa_cirrus_vga_info = { .name = "isa-cirrus-vga", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISACirrusVGAState), @@ -3003,7 +3003,7 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data) dc->props = pci_vga_cirrus_properties; } -static TypeInfo cirrus_vga_info = { +static const TypeInfo cirrus_vga_info = { .name = "cirrus-vga", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCICirrusVGAState), diff --git a/hw/cs4231.c b/hw/cs4231.c index 23570d5b41..ae384b90fd 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -166,7 +166,7 @@ static void cs4231_class_init(ObjectClass *klass, void *data) dc->props = cs4231_properties; } -static TypeInfo cs4231_info = { +static const TypeInfo cs4231_info = { .name = "SUNW,CS4231", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CSState), diff --git a/hw/cs4231a.c b/hw/cs4231a.c index 9d528c43b0..73f08594bf 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -682,7 +682,7 @@ static void cs4231a_class_initfn (ObjectClass *klass, void *data) dc->props = cs4231a_properties; } -static TypeInfo cs4231a_info = { +static const TypeInfo cs4231a_info = { .name = "cs4231a", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof (CSState), diff --git a/hw/debugcon.c b/hw/debugcon.c index e8a855e33a..81b2bb00fd 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -119,7 +119,7 @@ static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) dc->props = debugcon_isa_properties; } -static TypeInfo debugcon_isa_info = { +static const TypeInfo debugcon_isa_info = { .name = TYPE_ISA_DEBUGCON_DEVICE, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISADebugconState), diff --git a/hw/debugexit.c b/hw/debugexit.c index 90642eb37f..c1b489ddcb 100644 --- a/hw/debugexit.c +++ b/hw/debugexit.c @@ -60,7 +60,7 @@ static void debug_exit_class_initfn(ObjectClass *klass, void *data) dc->props = debug_exit_properties; } -static TypeInfo debug_exit_info = { +static const TypeInfo debug_exit_info = { .name = TYPE_ISA_DEBUG_EXIT_DEVICE, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISADebugExitState), diff --git a/hw/ds1225y.c b/hw/ds1225y.c index 4b3f69bc67..a6219a7908 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -150,7 +150,7 @@ static void nvram_sysbus_class_init(ObjectClass *klass, void *data) dc->props = nvram_sysbus_properties; } -static TypeInfo nvram_sysbus_info = { +static const TypeInfo nvram_sysbus_info = { .name = "ds1225y", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusNvRamState), diff --git a/hw/ds1338.c b/hw/ds1338.c index 1aefa3ba04..379220638e 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -221,7 +221,7 @@ static void ds1338_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_ds1338; } -static TypeInfo ds1338_info = { +static const TypeInfo ds1338_info = { .name = "ds1338", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(DS1338State), diff --git a/hw/e1000.c b/hw/e1000.c index 92fb00a89f..ef06ca1894 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -61,6 +61,8 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); /* this is the size past which hardware will drop packets when setting LPE=0 */ #define MAXIMUM_ETHERNET_VLAN_SIZE 1522 +/* this is the size past which hardware will drop packets when setting LPE=1 */ +#define MAXIMUM_ETHERNET_LPE_SIZE 16384 /* * HW models: @@ -164,6 +166,11 @@ static void set_phy_ctrl(E1000State *s, int index, uint16_t val) { if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) { + /* no need auto-negotiation if link was down */ + if (s->nic->nc.link_down) { + s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; + return; + } s->nic->nc.link_down = true; e1000_link_down(s); s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; @@ -809,8 +816,9 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) } /* Discard oversized packets if !LPE and !SBP. */ - if (size > MAXIMUM_ETHERNET_VLAN_SIZE - && !(s->mac_reg[RCTL] & E1000_RCTL_LPE) + if ((size > MAXIMUM_ETHERNET_LPE_SIZE || + (size > MAXIMUM_ETHERNET_VLAN_SIZE + && !(s->mac_reg[RCTL] & E1000_RCTL_LPE))) && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) { return size; } @@ -1319,7 +1327,7 @@ static void e1000_class_init(ObjectClass *klass, void *data) dc->props = e1000_properties; } -static TypeInfo e1000_info = { +static const TypeInfo e1000_info = { .name = "e1000", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(E1000State), diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c index 000bd08dee..dbac2c2bbc 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -324,7 +324,7 @@ static void ecc_class_init(ObjectClass *klass, void *data) dc->props = ecc_properties; } -static TypeInfo ecc_info = { +static const TypeInfo ecc_info = { .name = "eccmemctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ECCState), diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 23978eb149..3cb6ccb27d 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -83,7 +83,7 @@ static void empty_slot_class_init(ObjectClass *klass, void *data) k->init = empty_slot_init1; } -static TypeInfo empty_slot_info = { +static const TypeInfo empty_slot_info = { .name = "empty_slot", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(EmptySlot), diff --git a/hw/es1370.c b/hw/es1370.c index 59c3f2329e..977d2e3767 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -1073,7 +1073,7 @@ static void es1370_class_init (ObjectClass *klass, void *data) dc->vmsd = &vmstate_es1370; } -static TypeInfo es1370_info = { +static const TypeInfo es1370_info = { .name = "ES1370", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof (ES1370State), @@ -923,7 +923,7 @@ static void escc_class_init(ObjectClass *klass, void *data) dc->props = escc_properties; } -static TypeInfo escc_info = { +static const TypeInfo escc_info = { .name = "escc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SerialState), diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 289a810edc..ec23fa6edf 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -630,7 +630,7 @@ static void etraxfs_eth_class_init(ObjectClass *klass, void *data) dc->props = etraxfs_eth_properties; } -static TypeInfo etraxfs_eth_info = { +static const TypeInfo etraxfs_eth_info = { .name = "etraxfs-eth", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct fs_eth), diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c index 62a62a36af..64af31c46e 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -165,7 +165,7 @@ static void etraxfs_pic_class_init(ObjectClass *klass, void *data) dc->props = etraxfs_pic_properties; } -static TypeInfo etraxfs_pic_info = { +static const TypeInfo etraxfs_pic_info = { .name = "etraxfs,pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct etrax_pic), diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 7bde8004d0..72c8868639 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -233,7 +233,7 @@ static void etraxfs_ser_class_init(ObjectClass *klass, void *data) dc->reset = etraxfs_ser_reset; } -static TypeInfo etraxfs_ser_info = { +static const TypeInfo etraxfs_ser_info = { .name = "etraxfs,serial", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct etrax_serial), diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index e9273cd95d..d3dac52315 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -336,7 +336,7 @@ static void etraxfs_timer_class_init(ObjectClass *klass, void *data) sdc->init = etraxfs_timer_init; } -static TypeInfo etraxfs_timer_info = { +static const TypeInfo etraxfs_timer_info = { .name = "etraxfs,timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof (struct etrax_timer), diff --git a/hw/exynos4210.c b/hw/exynos4210.c index a7b84d61a0..246a0fc1c3 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -27,6 +27,7 @@ #include "arm-misc.h" #include "loader.h" #include "exynos4210.h" +#include "usb/hcd-ehci.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 @@ -72,6 +73,9 @@ /* Display controllers (FIMD) */ #define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 +/* EHCI */ +#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000 + static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; @@ -338,5 +342,8 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, s->irq_table[exynos4210_get_irq(11, 2)], NULL); + sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR, + s->irq_table[exynos4210_get_irq(28, 3)]); + return s; } diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index 84d36ed11f..ba644b43c2 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -440,7 +440,7 @@ static void exynos4210_combiner_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_exynos4210_combiner; } -static TypeInfo exynos4210_combiner_info = { +static const TypeInfo exynos4210_combiner_info = { .name = "exynos4210.combiner", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210CombinerState), diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c index 5c29b5d01d..3d498b77f8 100644 --- a/hw/exynos4210_fimd.c +++ b/hw/exynos4210_fimd.c @@ -1913,7 +1913,7 @@ static void exynos4210_fimd_class_init(ObjectClass *klass, void *data) k->init = exynos4210_fimd_init; } -static TypeInfo exynos4210_fimd_info = { +static const TypeInfo exynos4210_fimd_info = { .name = "exynos4210.fimd", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210fimdState), diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index 4fea09873a..f67906e42f 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -140,7 +140,7 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, EXT_GIC_ID_I2C7 }, /* int combiner group 28 */ - { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 }, + { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST}, /* int combiner group 29 */ { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, @@ -346,7 +346,7 @@ static void exynos4210_gic_class_init(ObjectClass *klass, void *data) dc->props = exynos4210_gic_properties; } -static TypeInfo exynos4210_gic_info = { +static const TypeInfo exynos4210_gic_info = { .name = "exynos4210.gic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210GicState), @@ -447,7 +447,7 @@ static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data) dc->props = exynos4210_irq_gate_properties; } -static TypeInfo exynos4210_irq_gate_info = { +static const TypeInfo exynos4210_irq_gate_info = { .name = "exynos4210.irq_gate", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210IRQGateState), diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c index 41cd142227..d7d5904cc0 100644 --- a/hw/exynos4210_mct.c +++ b/hw/exynos4210_mct.c @@ -1467,7 +1467,7 @@ static void exynos4210_mct_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_exynos4210_mct_state; } -static TypeInfo exynos4210_mct_info = { +static const TypeInfo exynos4210_mct_info = { .name = "exynos4210.mct", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210MCTState), diff --git a/hw/exynos4210_pmu.c b/hw/exynos4210_pmu.c index a22b8f181a..7c81a1b628 100644 --- a/hw/exynos4210_pmu.c +++ b/hw/exynos4210_pmu.c @@ -484,7 +484,7 @@ static void exynos4210_pmu_class_init(ObjectClass *klass, void *data) dc->vmsd = &exynos4210_pmu_vmstate; } -static TypeInfo exynos4210_pmu_info = { +static const TypeInfo exynos4210_pmu_info = { .name = "exynos4210.pmu", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210PmuState), diff --git a/hw/exynos4210_pwm.c b/hw/exynos4210_pwm.c index 3a3eb8c27a..c8656248a8 100644 --- a/hw/exynos4210_pwm.c +++ b/hw/exynos4210_pwm.c @@ -407,7 +407,7 @@ static void exynos4210_pwm_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_exynos4210_pwm_state; } -static TypeInfo exynos4210_pwm_info = { +static const TypeInfo exynos4210_pwm_info = { .name = "exynos4210.pwm", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210PWMState), diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c index 4f23079095..adaab242fe 100644 --- a/hw/exynos4210_uart.c +++ b/hw/exynos4210_uart.c @@ -661,7 +661,7 @@ static void exynos4210_uart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_exynos4210_uart; } -static TypeInfo exynos4210_uart_info = { +static const TypeInfo exynos4210_uart_info = { .name = "exynos4210.uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210UartState), @@ -2210,7 +2210,7 @@ static void isabus_fdc_class_init1(ObjectClass *klass, void *data) dc->props = isa_fdc_properties; } -static TypeInfo isa_fdc_info = { +static const TypeInfo isa_fdc_info = { .name = "isa-fdc", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(FDCtrlISABus), @@ -2244,7 +2244,7 @@ static void sysbus_fdc_class_init(ObjectClass *klass, void *data) dc->props = sysbus_fdc_properties; } -static TypeInfo sysbus_fdc_info = { +static const TypeInfo sysbus_fdc_info = { .name = "sysbus-fdc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(FDCtrlSysBus), @@ -2267,7 +2267,7 @@ static void sun4m_fdc_class_init(ObjectClass *klass, void *data) dc->props = sun4m_fdc_properties; } -static TypeInfo sun4m_fdc_info = { +static const TypeInfo sun4m_fdc_info = { .name = "SUNW,fdtwo", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(FDCtrlSysBus), diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 26f7125fe2..7c9480c4d7 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -575,7 +575,7 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data) dc->props = fw_cfg_properties; } -static TypeInfo fw_cfg_info = { +static const TypeInfo fw_cfg_info = { .name = "fw_cfg", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(FWCfgState), diff --git a/hw/g364fb.c b/hw/g364fb.c index b46a044607..0c0c8ba302 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -597,7 +597,7 @@ static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) dc->props = g364fb_sysbus_properties; } -static TypeInfo g364fb_sysbus_info = { +static const TypeInfo g364fb_sysbus_info = { .name = "sysbus-g364", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(G364SysBusState), diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index 88c46780d1..760bed0b72 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -256,7 +256,7 @@ static void grlib_gptimer_class_init(ObjectClass *klass, void *data) dc->props = grlib_gptimer_properties; } -static TypeInfo grlib_gptimer_info = { +static const TypeInfo grlib_gptimer_info = { .name = "grlib,apbuart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(UART), diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c index 252ba893e3..7962b74f2c 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -389,7 +389,7 @@ static void grlib_gptimer_class_init(ObjectClass *klass, void *data) dc->props = grlib_gptimer_properties; } -static TypeInfo grlib_gptimer_info = { +static const TypeInfo grlib_gptimer_info = { .name = "grlib,gptimer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GPTimerUnit), diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index 23a6a02bc5..b5427c8039 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -370,7 +370,7 @@ static void grlib_irqmp_class_init(ObjectClass *klass, void *data) dc->props = grlib_irqmp_properties; } -static TypeInfo grlib_irqmp_info = { +static const TypeInfo grlib_irqmp_info = { .name = "grlib,irqmp", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IRQMP), @@ -317,7 +317,7 @@ static void gus_class_initfn (ObjectClass *klass, void *data) dc->props = gus_properties; } -static TypeInfo gus_info = { +static const TypeInfo gus_info = { .name = "gus", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof (GUSState), diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 92a91b5ab1..3190bd1cf8 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -1039,7 +1039,7 @@ static void hda_audio_output_class_init(ObjectClass *klass, void *data) dc->props = hda_audio_properties; } -static TypeInfo hda_audio_output_info = { +static const TypeInfo hda_audio_output_info = { .name = "hda-output", .parent = TYPE_HDA_CODEC_DEVICE, .instance_size = sizeof(HDAAudioState), @@ -1060,7 +1060,7 @@ static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) dc->props = hda_audio_properties; } -static TypeInfo hda_audio_duplex_info = { +static const TypeInfo hda_audio_duplex_info = { .name = "hda-duplex", .parent = TYPE_HDA_CODEC_DEVICE, .instance_size = sizeof(HDAAudioState), @@ -1081,7 +1081,7 @@ static void hda_audio_micro_class_init(ObjectClass *klass, void *data) dc->props = hda_audio_properties; } -static TypeInfo hda_audio_micro_info = { +static const TypeInfo hda_audio_micro_info = { .name = "hda-micro", .parent = TYPE_HDA_CODEC_DEVICE, .instance_size = sizeof(HDAAudioState), @@ -71,12 +71,38 @@ static const uint8_t hid_usage_keys[0x100] = { bool hid_has_events(HIDState *hs) { - return hs->n > 0; + return hs->n > 0 || hs->idle_pending; } -void hid_set_next_idle(HIDState *hs, int64_t curtime) +static void hid_idle_timer(void *opaque) { - hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000; + HIDState *hs = opaque; + + hs->idle_pending = true; + hs->event(hs); +} + +static void hid_del_idle_timer(HIDState *hs) +{ + if (hs->idle_timer) { + qemu_del_timer(hs->idle_timer); + qemu_free_timer(hs->idle_timer); + hs->idle_timer = NULL; + } +} + +void hid_set_next_idle(HIDState *hs) +{ + if (hs->idle) { + uint64_t expire_time = qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec() * hs->idle * 4 / 1000; + if (!hs->idle_timer) { + hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs); + } + qemu_mod_timer_ns(hs->idle_timer, expire_time); + } else { + hid_del_idle_timer(hs); + } } static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) @@ -232,6 +258,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int index; HIDPointerEvent *e; + hs->idle_pending = false; + hid_pointer_activate(hs); /* When the buffer is empty, return the last event. Relative @@ -319,6 +347,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) { + hs->idle_pending = false; + if (len < 2) { return 0; } @@ -377,6 +407,8 @@ void hid_reset(HIDState *hs) hs->n = 0; hs->protocol = 1; hs->idle = 0; + hs->idle_pending = false; + hid_del_idle_timer(hs); } void hid_free(HIDState *hs) @@ -390,6 +422,7 @@ void hid_free(HIDState *hs) qemu_remove_mouse_event_handler(hs->ptr.eh_entry); break; } + hid_del_idle_timer(hs); } void hid_init(HIDState *hs, int kind, HIDEventFunc event) @@ -412,9 +445,7 @@ static int hid_post_load(void *opaque, int version_id) { HIDState *s = opaque; - if (s->idle) { - hid_set_next_idle(s, qemu_get_clock_ns(vm_clock)); - } + hid_set_next_idle(s); return 0; } @@ -43,7 +43,8 @@ struct HIDState { int kind; int32_t protocol; uint8_t idle; - int64_t next_idle_clock; + bool idle_pending; + QEMUTimer *idle_timer; HIDEventFunc event; }; @@ -52,7 +53,7 @@ void hid_reset(HIDState *hs); void hid_free(HIDState *hs); bool hid_has_events(HIDState *hs); -void hid_set_next_idle(HIDState *hs, int64_t curtime); +void hid_set_next_idle(HIDState *hs); void hid_pointer_activate(HIDState *hs); int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len); int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len); diff --git a/hw/highbank.c b/hw/highbank.c index 6005622f3a..98deca8bce 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -168,7 +168,7 @@ static void highbank_regs_class_init(ObjectClass *klass, void *data) dc->reset = highbank_regs_reset; } -static TypeInfo highbank_regs_info = { +static const TypeInfo highbank_regs_info = { .name = "highbank-regs", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(HighbankRegsState), @@ -745,7 +745,7 @@ static void hpet_device_class_init(ObjectClass *klass, void *data) dc->props = hpet_device_properties; } -static TypeInfo hpet_device_info = { +static const TypeInfo hpet_device_info = { .name = "hpet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(HPETState), @@ -228,7 +228,7 @@ static void i2c_slave_class_init(ObjectClass *klass, void *data) k->props = i2c_props; } -static TypeInfo i2c_slave_type_info = { +static const TypeInfo i2c_slave_type_info = { .name = TYPE_I2C_SLAVE, .parent = TYPE_DEVICE, .instance_size = sizeof(I2CSlave), diff --git a/hw/i82374.c b/hw/i82374.c index 4a922c3f4e..6a62ba2ab8 100644 --- a/hw/i82374.c +++ b/hw/i82374.c @@ -153,7 +153,7 @@ static void i82374_class_init(ObjectClass *klass, void *data) dc->props = i82374_properties; } -static TypeInfo i82374_isa_info = { +static const TypeInfo i82374_isa_info = { .name = "i82374", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAi82374State), diff --git a/hw/i82378.c b/hw/i82378.c index c6b0b5ec55..0914d7bbfb 100644 --- a/hw/i82378.c +++ b/hw/i82378.c @@ -262,7 +262,7 @@ static void pci_i82378_class_init(ObjectClass *klass, void *data) dc->props = i82378_properties; } -static TypeInfo pci_i82378_info = { +static const TypeInfo pci_i82378_info = { .name = "i82378", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIi82378State), diff --git a/hw/i8254.c b/hw/i8254.c index 7c2aa6238d..394b2e81d7 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -347,7 +347,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data) dc->props = pit_properties; } -static TypeInfo pit_info = { +static const TypeInfo pit_info = { .name = "isa-pit", .parent = TYPE_PIT_COMMON, .instance_size = sizeof(PITCommonState), diff --git a/hw/i8254_common.c b/hw/i8254_common.c index 08ab8d14bd..8c2e45a92e 100644 --- a/hw/i8254_common.c +++ b/hw/i8254_common.c @@ -294,7 +294,7 @@ static void pit_common_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo pit_common_type = { +static const TypeInfo pit_common_type = { .name = TYPE_PIT_COMMON, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PITCommonState), diff --git a/hw/i8259.c b/hw/i8259.c index 8fc6339250..264879e097 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -481,7 +481,7 @@ static void i8259_class_init(ObjectClass *klass, void *data) dc->reset = pic_reset; } -static TypeInfo i8259_info = { +static const TypeInfo i8259_info = { .name = "isa-i8259", .instance_size = sizeof(PICCommonState), .parent = TYPE_PIC_COMMON, diff --git a/hw/i8259_common.c b/hw/i8259_common.c index ab3d98b2a1..fc91056afb 100644 --- a/hw/i8259_common.c +++ b/hw/i8259_common.c @@ -144,7 +144,7 @@ static void pic_common_class_init(ObjectClass *klass, void *data) ic->init = pic_init_common; } -static TypeInfo pic_common_type = { +static const TypeInfo pic_common_type = { .name = TYPE_PIC_COMMON, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PICCommonState), diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index d0724499c7..21f50ea5be 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1247,7 +1247,7 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data) dc->reset = sysbus_ahci_reset; } -static TypeInfo sysbus_ahci_info = { +static const TypeInfo sysbus_ahci_info = { .name = "sysbus-ahci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysbusAHCIState), diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index ee855b670f..745ef94deb 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -342,7 +342,7 @@ static void cmd646_ide_class_init(ObjectClass *klass, void *data) dc->props = cmd646_ide_properties; } -static TypeInfo cmd646_ide_info = { +static const TypeInfo cmd646_ide_info = { .name = "cmd646-ide", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), diff --git a/hw/ide/ich.c b/hw/ide/ich.c index de39b3067a..1fb803d340 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -156,7 +156,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data) dc->reset = pci_ich9_reset; } -static TypeInfo ich_ahci_info = { +static const TypeInfo ich_ahci_info = { .name = "ich9-ahci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(AHCIPCIState), diff --git a/hw/ide/isa.c b/hw/ide/isa.c index aa0e7fa22d..fb7bb8201d 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -111,7 +111,7 @@ static void isa_ide_class_initfn(ObjectClass *klass, void *data) dc->props = isa_ide_properties; } -static TypeInfo isa_ide_info = { +static const TypeInfo isa_ide_info = { .name = "isa-ide", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAIDEState), diff --git a/hw/ide/piix.c b/hw/ide/piix.c index df95aec195..4d3e82266c 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -251,7 +251,7 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo piix3_ide_info = { +static const TypeInfo piix3_ide_info = { .name = "piix3-ide", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), @@ -271,7 +271,7 @@ static void piix3_ide_xen_class_init(ObjectClass *klass, void *data) dc->unplug = pci_piix3_xen_ide_unplug; } -static TypeInfo piix3_ide_xen_info = { +static const TypeInfo piix3_ide_xen_info = { .name = "piix3-ide-xen", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), @@ -292,7 +292,7 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo piix4_ide_info = { +static const TypeInfo piix4_ide_info = { .name = "piix4-ide", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index d2fe77398f..c436b38bcb 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -216,7 +216,7 @@ static void ide_hd_class_init(ObjectClass *klass, void *data) dc->props = ide_hd_properties; } -static TypeInfo ide_hd_info = { +static const TypeInfo ide_hd_info = { .name = "ide-hd", .parent = TYPE_IDE_DEVICE, .instance_size = sizeof(IDEDrive), @@ -238,7 +238,7 @@ static void ide_cd_class_init(ObjectClass *klass, void *data) dc->props = ide_cd_properties; } -static TypeInfo ide_cd_info = { +static const TypeInfo ide_cd_info = { .name = "ide-cd", .parent = TYPE_IDE_DEVICE, .instance_size = sizeof(IDEDrive), @@ -260,7 +260,7 @@ static void ide_drive_class_init(ObjectClass *klass, void *data) dc->props = ide_drive_properties; } -static TypeInfo ide_drive_info = { +static const TypeInfo ide_drive_info = { .name = "ide-drive", .parent = TYPE_IDE_DEVICE, .instance_size = sizeof(IDEDrive), @@ -275,7 +275,7 @@ static void ide_device_class_init(ObjectClass *klass, void *data) k->props = ide_props; } -static TypeInfo ide_device_type_info = { +static const TypeInfo ide_device_type_info = { .name = TYPE_IDE_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(IDEDevice), diff --git a/hw/ide/via.c b/hw/ide/via.c index 14acb3ac04..f40c1adc8c 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -226,7 +226,7 @@ static void via_ide_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo via_ide_info = { +static const TypeInfo via_ide_info = { .name = "via-ide", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), diff --git a/hw/imx_ccm.c b/hw/imx_ccm.c index 46962e4df9..477903a546 100644 --- a/hw/imx_ccm.c +++ b/hw/imx_ccm.c @@ -306,7 +306,7 @@ static void imx_ccm_class_init(ObjectClass *klass, void *data) dc->desc = "i.MX Clock Control Module"; } -static TypeInfo imx_ccm_info = { +static const TypeInfo imx_ccm_info = { .name = "imx_ccm", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXCCMState), diff --git a/hw/imx_serial.c b/hw/imx_serial.c index 124dbb2860..77ed693a0c 100644 --- a/hw/imx_serial.c +++ b/hw/imx_serial.c @@ -452,7 +452,7 @@ static void imx_serial_class_init(ObjectClass *klass, void *data) dc->props = imx32_serial_properties; } -static TypeInfo imx_serial_info = { +static const TypeInfo imx_serial_info = { .name = "imx-serial", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXSerialState), diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 47fc9cb944..6c824dc36e 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -535,7 +535,7 @@ static void core_class_init(ObjectClass *klass, void *data) dc->props = core_properties; } -static TypeInfo core_info = { +static const TypeInfo core_info = { .name = "integrator_core", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(integratorcm_state), @@ -549,7 +549,7 @@ static void icp_pic_class_init(ObjectClass *klass, void *data) sdc->init = icp_pic_init; } -static TypeInfo icp_pic_info = { +static const TypeInfo icp_pic_info = { .name = "integrator_pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pic_state), diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 98ff93679d..784c229d8f 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -1232,7 +1232,7 @@ static Property intel_hda_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void intel_hda_class_init(ObjectClass *klass, void *data) +static void intel_hda_class_init_common(ObjectClass *klass) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1240,20 +1240,46 @@ static void intel_hda_class_init(ObjectClass *klass, void *data) k->init = intel_hda_init; k->exit = intel_hda_exit; k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = 0x2668; - k->revision = 1; k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO; - dc->desc = "Intel HD Audio Controller"; dc->reset = intel_hda_reset; dc->vmsd = &vmstate_intel_hda; dc->props = intel_hda_properties; } -static TypeInfo intel_hda_info = { +static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + intel_hda_class_init_common(klass); + k->device_id = 0x2668; + k->revision = 1; + dc->desc = "Intel HD Audio Controller (ich6)"; +} + +static void intel_hda_class_init_ich9(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + intel_hda_class_init_common(klass); + k->device_id = 0x293e; + k->revision = 3; + dc->desc = "Intel HD Audio Controller (ich9)"; +} + +static const TypeInfo intel_hda_info_ich6 = { .name = "intel-hda", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(IntelHDAState), - .class_init = intel_hda_class_init, + .class_init = intel_hda_class_init_ich6, +}; + +static const TypeInfo intel_hda_info_ich9 = { + .name = "ich9-intel-hda", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(IntelHDAState), + .class_init = intel_hda_class_init_ich9, }; static void hda_codec_device_class_init(ObjectClass *klass, void *data) @@ -1265,7 +1291,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data) k->props = hda_props; } -static TypeInfo hda_codec_device_type_info = { +static const TypeInfo hda_codec_device_type_info = { .name = TYPE_HDA_CODEC_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(HDACodecDevice), @@ -1277,7 +1303,8 @@ static TypeInfo hda_codec_device_type_info = { static void intel_hda_register_types(void) { type_register_static(&hda_codec_bus_info); - type_register_static(&intel_hda_info); + type_register_static(&intel_hda_info_ich6); + type_register_static(&intel_hda_info_ich9); type_register_static(&hda_codec_device_type_info); } diff --git a/hw/ioapic.c b/hw/ioapic.c index 72730951a6..f06c2dcf2e 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -244,7 +244,7 @@ static void ioapic_class_init(ObjectClass *klass, void *data) dc->reset = ioapic_reset_common; } -static TypeInfo ioapic_info = { +static const TypeInfo ioapic_info = { .name = "ioapic", .parent = TYPE_IOAPIC_COMMON, .instance_size = sizeof(IOAPICCommonState), diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c index 653eef2ce1..7dc552f033 100644 --- a/hw/ioapic_common.c +++ b/hw/ioapic_common.c @@ -103,7 +103,7 @@ static void ioapic_common_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo ioapic_common_type = { +static const TypeInfo ioapic_common_type = { .name = TYPE_IOAPIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IOAPICCommonState), diff --git a/hw/ioh3420.c b/hw/ioh3420.c index d706e195df..95bceb5347 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -226,7 +226,7 @@ static void ioh3420_class_init(ObjectClass *klass, void *data) dc->props = ioh3420_properties; } -static TypeInfo ioh3420_info = { +static const TypeInfo ioh3420_info = { .name = "ioh3420", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIESlot), diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 86b0bbd3d1..fce311bc2a 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -215,7 +215,7 @@ static void isabus_bridge_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo isabus_bridge_info = { +static const TypeInfo isabus_bridge_info = { .name = "isabus-bridge", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusDevice), @@ -229,7 +229,7 @@ static void isa_device_class_init(ObjectClass *klass, void *data) k->bus_type = TYPE_ISA_BUS; } -static TypeInfo isa_device_type_info = { +static const TypeInfo isa_device_type_info = { .name = TYPE_ISA_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(ISADevice), diff --git a/hw/ivshmem.c b/hw/ivshmem.c index c86fddd0b3..afaf9b3bbf 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -810,7 +810,7 @@ static void ivshmem_class_init(ObjectClass *klass, void *data) dc->props = ivshmem_properties; } -static TypeInfo ivshmem_info = { +static const TypeInfo ivshmem_info = { .name = "ivshmem", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(IVShmemState), diff --git a/hw/jazz_led.c b/hw/jazz_led.c index f4a040631e..4822c485f2 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -277,7 +277,7 @@ static void jazz_led_class_init(ObjectClass *klass, void *data) dc->reset = jazz_led_reset; } -static TypeInfo jazz_led_info = { +static const TypeInfo jazz_led_info = { .name = "jazz-led", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LedState), diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c index a4e834744b..d994ea7c97 100644 --- a/hw/kvm/apic.c +++ b/hw/kvm/apic.c @@ -194,7 +194,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data) k->external_nmi = kvm_apic_external_nmi; } -static TypeInfo kvm_apic_info = { +static const TypeInfo kvm_apic_info = { .name = "kvm-apic", .parent = TYPE_APIC_COMMON, .instance_size = sizeof(APICCommonState), diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c index be24973df9..fa40e283f7 100644 --- a/hw/kvm/clock.c +++ b/hw/kvm/clock.c @@ -118,7 +118,7 @@ static void kvmclock_class_init(ObjectClass *klass, void *data) dc->vmsd = &kvmclock_vmsd; } -static TypeInfo kvmclock_info = { +static const TypeInfo kvmclock_info = { .name = "kvmclock", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(KVMClockState), diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c index 57faf64ab2..04ad649b0e 100644 --- a/hw/kvm/i8254.c +++ b/hw/kvm/i8254.c @@ -302,7 +302,7 @@ static void kvm_pit_class_init(ObjectClass *klass, void *data) dc->props = kvm_pit_properties; } -static TypeInfo kvm_pit_info = { +static const TypeInfo kvm_pit_info = { .name = "kvm-pit", .parent = TYPE_PIT_COMMON, .instance_size = sizeof(KVMPITState), diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c index 70e1d185de..5ae8b6819b 100644 --- a/hw/kvm/i8259.c +++ b/hw/kvm/i8259.c @@ -123,7 +123,7 @@ static void kvm_i8259_class_init(ObjectClass *klass, void *data) k->post_load = kvm_pic_put; } -static TypeInfo kvm_i8259_info = { +static const TypeInfo kvm_i8259_info = { .name = "kvm-i8259", .parent = TYPE_PIC_COMMON, .instance_size = sizeof(PICCommonState), diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c index 30db6230b4..23877d4259 100644 --- a/hw/kvm/ioapic.c +++ b/hw/kvm/ioapic.c @@ -150,7 +150,7 @@ static void kvm_ioapic_class_init(ObjectClass *klass, void *data) dc->props = kvm_ioapic_properties; } -static TypeInfo kvm_ioapic_info = { +static const TypeInfo kvm_ioapic_info = { .name = "kvm-ioapic", .parent = TYPE_IOAPIC_COMMON, .instance_size = sizeof(KVMIOAPICState), diff --git a/hw/kvmvapic.c b/hw/kvmvapic.c index 81f4bcfdf6..1b5f416a78 100644 --- a/hw/kvmvapic.c +++ b/hw/kvmvapic.c @@ -804,7 +804,7 @@ static void vapic_class_init(ObjectClass *klass, void *data) sc->init = vapic_init; } -static TypeInfo vapic_type = { +static const TypeInfo vapic_type = { .name = "kvmvapic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(VAPICROMState), diff --git a/hw/lan9118.c b/hw/lan9118.c index 5adf91199b..969b634d47 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -1368,7 +1368,7 @@ static void lan9118_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lan9118; } -static TypeInfo lan9118_info = { +static const TypeInfo lan9118_info = { .name = "lan9118", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(lan9118_state), diff --git a/hw/lance.c b/hw/lance.c index b7265c0fed..a5997fd64e 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -155,7 +155,7 @@ static void lance_class_init(ObjectClass *klass, void *data) dc->props = lance_properties; } -static TypeInfo lance_info = { +static const TypeInfo lance_info = { .name = "lance", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusPCNetState), diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c index 7c2d202d6a..8c82c85f6d 100644 --- a/hw/lm32_juart.c +++ b/hw/lm32_juart.c @@ -144,7 +144,7 @@ static void lm32_juart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lm32_juart; } -static TypeInfo lm32_juart_info = { +static const TypeInfo lm32_juart_info = { .name = "lm32-juart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32JuartState), diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c index 42d5602cf0..8f13355821 100644 --- a/hw/lm32_pic.c +++ b/hw/lm32_pic.c @@ -184,7 +184,7 @@ static void lm32_pic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lm32_pic; } -static TypeInfo lm32_pic_info = { +static const TypeInfo lm32_pic_info = { .name = "lm32-pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32PicState), diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c index e3a9db9748..187ef6d0d6 100644 --- a/hw/lm32_sys.c +++ b/hw/lm32_sys.c @@ -157,7 +157,7 @@ static void lm32_sys_class_init(ObjectClass *klass, void *data) dc->props = lm32_sys_properties; } -static TypeInfo lm32_sys_info = { +static const TypeInfo lm32_sys_info = { .name = "lm32-sys", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32SysState), diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c index bd4c346386..db527e9dc6 100644 --- a/hw/lm32_timer.c +++ b/hw/lm32_timer.c @@ -215,7 +215,7 @@ static void lm32_timer_class_init(ObjectClass *klass, void *data) dc->props = lm32_timer_properties; } -static TypeInfo lm32_timer_info = { +static const TypeInfo lm32_timer_info = { .name = "lm32-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32TimerState), diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c index 89605b8e77..9c89cca49b 100644 --- a/hw/lm32_uart.c +++ b/hw/lm32_uart.c @@ -281,7 +281,7 @@ static void lm32_uart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lm32_uart; } -static TypeInfo lm32_uart_info = { +static const TypeInfo lm32_uart_info = { .name = "lm32-uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32UartState), diff --git a/hw/lm832x.c b/hw/lm832x.c index 3649e3d249..af49dd68bf 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -506,7 +506,7 @@ static void lm8323_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lm_kbd; } -static TypeInfo lm8323_info = { +static const TypeInfo lm8323_info = { .name = "lm8323", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(LM823KbdState), diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 0aafb00b58..89c657fb00 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -2126,7 +2126,7 @@ static void lsi_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lsi_scsi; } -static TypeInfo lsi_info = { +static const TypeInfo lsi_info = { .name = "lsi53c895a", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(LSIState), diff --git a/hw/m48t59.c b/hw/m48t59.c index 393c5c049a..8f1ca3cccd 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -738,7 +738,7 @@ static void m48t59_init_class_isa1(ObjectClass *klass, void *data) dc->props = m48t59_isa_properties; } -static TypeInfo m48t59_isa_info = { +static const TypeInfo m48t59_isa_info = { .name = "m48t59_isa", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(M48t59ISAState), @@ -762,7 +762,7 @@ static void m48t59_class_init(ObjectClass *klass, void *data) dc->props = m48t59_properties; } -static TypeInfo m48t59_info = { +static const TypeInfo m48t59_info = { .name = "m48t59", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(M48t59SysBusState), diff --git a/hw/macio.c b/hw/macio.c index 362afdc7ec..675a71c051 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -90,7 +90,7 @@ static void macio_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_OTHERS << 8; } -static TypeInfo macio_info = { +static const TypeInfo macio_info = { .name = "macio", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MacIOState), diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c index de16cfa090..511004b94e 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -288,7 +288,7 @@ static void mv88w8618_audio_class_init(ObjectClass *klass, void *data) dc->props = mv88w8618_audio_properties; } -static TypeInfo mv88w8618_audio_info = { +static const TypeInfo mv88w8618_audio_info = { .name = "mv88w8618_audio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_audio_state), diff --git a/hw/max111x.c b/hw/max111x.c index 67640f109a..de1be4ddd6 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -162,7 +162,7 @@ static void max1110_class_init(ObjectClass *klass, void *data) k->transfer = max111x_transfer; } -static TypeInfo max1110_info = { +static const TypeInfo max1110_info = { .name = "max1110", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(MAX111xState), @@ -177,7 +177,7 @@ static void max1111_class_init(ObjectClass *klass, void *data) k->transfer = max111x_transfer; } -static TypeInfo max1111_info = { +static const TypeInfo max1111_info = { .name = "max1111", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(MAX111xState), diff --git a/hw/max7310.c b/hw/max7310.c index 1ed18ba876..de2221ba01 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -198,7 +198,7 @@ static void max7310_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_max7310; } -static TypeInfo max7310_info = { +static const TypeInfo max7310_info = { .name = "max7310", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(MAX7310State), diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 2ddd7de09e..2fb11f69a3 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -898,7 +898,7 @@ static void rtc_class_initfn(ObjectClass *klass, void *data) dc->props = mc146818rtc_properties; } -static TypeInfo mc146818rtc_info = { +static const TypeInfo mc146818rtc_info = { .name = "mc146818rtc", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(RTCState), diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c index f46af1c509..d51d1ac993 100644 --- a/hw/milkymist-ac97.c +++ b/hw/milkymist-ac97.c @@ -329,7 +329,7 @@ static void milkymist_ac97_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_ac97; } -static TypeInfo milkymist_ac97_info = { +static const TypeInfo milkymist_ac97_info = { .name = "milkymist-ac97", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistAC97State), diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c index fd54d3129a..ea4d210685 100644 --- a/hw/milkymist-hpdmc.c +++ b/hw/milkymist-hpdmc.c @@ -155,7 +155,7 @@ static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_hpdmc; } -static TypeInfo milkymist_hpdmc_info = { +static const TypeInfo milkymist_hpdmc_info = { .name = "milkymist-hpdmc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistHpdmcState), diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c index f80befc53a..9d15309ab7 100644 --- a/hw/milkymist-memcard.c +++ b/hw/milkymist-memcard.c @@ -288,7 +288,7 @@ static void milkymist_memcard_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_memcard; } -static TypeInfo milkymist_memcard_info = { +static const TypeInfo milkymist_memcard_info = { .name = "milkymist-memcard", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistMemcardState), diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index 4e92ac3dcb..43d6c195eb 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -535,7 +535,7 @@ static void milkymist_minimac2_class_init(ObjectClass *klass, void *data) dc->props = milkymist_minimac2_properties; } -static TypeInfo milkymist_minimac2_info = { +static const TypeInfo milkymist_minimac2_info = { .name = "milkymist-minimac2", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistMinimac2State), diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index 0521829202..c347680ad7 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -529,7 +529,7 @@ static void milkymist_pfpu_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_pfpu; } -static TypeInfo milkymist_pfpu_info = { +static const TypeInfo milkymist_pfpu_info = { .name = "milkymist-pfpu", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistPFPUState), diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c index b7beb4bedb..01660bebf0 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -316,7 +316,7 @@ static void milkymist_softusb_class_init(ObjectClass *klass, void *data) dc->props = milkymist_softusb_properties; } -static TypeInfo milkymist_softusb_info = { +static const TypeInfo milkymist_softusb_info = { .name = "milkymist-softusb", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistSoftUsbState), diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c index 796e795f04..e69ac6f047 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -323,7 +323,7 @@ static void milkymist_sysctl_class_init(ObjectClass *klass, void *data) dc->props = milkymist_sysctl_properties; } -static TypeInfo milkymist_sysctl_info = { +static const TypeInfo milkymist_sysctl_info = { .name = "milkymist-sysctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistSysctlState), diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c index a11772aebe..42de10aafd 100644 --- a/hw/milkymist-tmu2.c +++ b/hw/milkymist-tmu2.c @@ -475,7 +475,7 @@ static void milkymist_tmu2_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_tmu2; } -static TypeInfo milkymist_tmu2_info = { +static const TypeInfo milkymist_tmu2_info = { .name = "milkymist-tmu2", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistTMU2State), diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c index 19e9dbdc75..e73eb8476c 100644 --- a/hw/milkymist-uart.c +++ b/hw/milkymist-uart.c @@ -228,7 +228,7 @@ static void milkymist_uart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_uart; } -static TypeInfo milkymist_uart_info = { +static const TypeInfo milkymist_uart_info = { .name = "milkymist-uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistUartState), diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 561285154f..4d0a5dfb78 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -319,7 +319,7 @@ static void milkymist_vgafb_class_init(ObjectClass *klass, void *data) dc->props = milkymist_vgafb_properties; } -static TypeInfo milkymist_vgafb_info = { +static const TypeInfo milkymist_vgafb_info = { .name = "milkymist-vgafb", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistVgafbState), diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 635143d20c..2250e675a5 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -1004,7 +1004,7 @@ static void mips_malta_class_init(ObjectClass *klass, void *data) k->init = mips_malta_sysbus_device_init; } -static TypeInfo mips_malta_device = { +static const TypeInfo mips_malta_device = { .name = "mips-malta", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MaltaState), diff --git a/hw/mipsnet.c b/hw/mipsnet.c index bb752d3950..feac8159ee 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -269,7 +269,7 @@ static void mipsnet_class_init(ObjectClass *klass, void *data) dc->props = mipsnet_properties; } -static TypeInfo mipsnet_info = { +static const TypeInfo mipsnet_info = { .name = "mipsnet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MIPSnetState), diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c index 84522e9722..9c57d7665f 100644 --- a/hw/mpc8544_guts.c +++ b/hw/mpc8544_guts.c @@ -128,7 +128,7 @@ static void mpc8544_guts_class_init(ObjectClass *klass, void *data) k->init = mpc8544_guts_initfn; } -static TypeInfo mpc8544_guts_info = { +static const TypeInfo mpc8544_guts_info = { .name = "mpc8544-guts", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GutsState), diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index fb4b739c7c..7ae05e389f 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -248,7 +248,7 @@ static void mst_fpga_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_mst_fpga_regs; } -static TypeInfo mst_fpga_info = { +static const TypeInfo mst_fpga_info = { .name = "mainstone-fpga", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mst_irq_state), diff --git a/hw/musicpal.c b/hw/musicpal.c index 77a585eee6..24a1722703 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -428,7 +428,7 @@ static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) dc->props = mv88w8618_eth_properties; } -static TypeInfo mv88w8618_eth_info = { +static const TypeInfo mv88w8618_eth_info = { .name = "mv88w8618_eth", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_eth_state), @@ -643,7 +643,7 @@ static void musicpal_lcd_class_init(ObjectClass *klass, void *data) dc->vmsd = &musicpal_lcd_vmsd; } -static TypeInfo musicpal_lcd_info = { +static const TypeInfo musicpal_lcd_info = { .name = "musicpal_lcd", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_lcd_state), @@ -762,7 +762,7 @@ static void mv88w8618_pic_class_init(ObjectClass *klass, void *data) dc->vmsd = &mv88w8618_pic_vmsd; } -static TypeInfo mv88w8618_pic_info = { +static const TypeInfo mv88w8618_pic_info = { .name = "mv88w8618_pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_pic_state), @@ -939,7 +939,7 @@ static void mv88w8618_pit_class_init(ObjectClass *klass, void *data) dc->vmsd = &mv88w8618_pit_vmsd; } -static TypeInfo mv88w8618_pit_info = { +static const TypeInfo mv88w8618_pit_info = { .name = "mv88w8618_pit", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_pit_state), @@ -1019,7 +1019,7 @@ static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data) dc->vmsd = &mv88w8618_flashcfg_vmsd; } -static TypeInfo mv88w8618_flashcfg_info = { +static const TypeInfo mv88w8618_flashcfg_info = { .name = "mv88w8618_flashcfg", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_flashcfg_state), @@ -1341,7 +1341,7 @@ static void musicpal_gpio_class_init(ObjectClass *klass, void *data) dc->vmsd = &musicpal_gpio_vmsd; } -static TypeInfo musicpal_gpio_info = { +static const TypeInfo musicpal_gpio_info = { .name = "musicpal_gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_gpio_state), @@ -1495,7 +1495,7 @@ static void musicpal_key_class_init(ObjectClass *klass, void *data) dc->vmsd = &musicpal_key_vmsd; } -static TypeInfo musicpal_key_info = { +static const TypeInfo musicpal_key_info = { .name = "musicpal_key", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_key_state), @@ -1674,7 +1674,7 @@ static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) sdc->init = mv88w8618_wlan_init; } -static TypeInfo mv88w8618_wlan_info = { +static const TypeInfo mv88w8618_wlan_info = { .name = "mv88w8618_wlan", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusDevice), @@ -435,7 +435,7 @@ static void nand_class_init(ObjectClass *klass, void *data) dc->props = nand_properties; } -static TypeInfo nand_info = { +static const TypeInfo nand_info = { .name = "nand", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(NANDFlashState), diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index c2c00c215f..7c11229f1a 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -97,7 +97,7 @@ static void isa_ne2000_class_initfn(ObjectClass *klass, void *data) dc->props = ne2000_isa_properties; } -static TypeInfo ne2000_isa_info = { +static const TypeInfo ne2000_isa_info = { .name = "ne2k_isa", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISANE2000State), diff --git a/hw/ne2000.c b/hw/ne2000.c index 00efa74a0f..872115c454 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -773,7 +773,7 @@ static void ne2000_class_init(ObjectClass *klass, void *data) dc->props = ne2000_properties; } -static TypeInfo ne2000_info = { +static const TypeInfo ne2000_info = { .name = "ne2k_pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCINE2000State), diff --git a/hw/omap1.c b/hw/omap1.c index 8536e96687..e85f2e2423 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -2830,7 +2830,7 @@ static void omap_rtc_tick(void *opaque) s->round = 0; } - memcpy(&s->current_tm, localtime(&s->ti), sizeof(s->current_tm)); + localtime_r(&s->ti, &s->current_tm); if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { s->status |= 0x40; diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index 25655325d0..15bdd629bf 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -747,7 +747,7 @@ static void omap_gpio_class_init(ObjectClass *klass, void *data) dc->props = omap_gpio_properties; } -static TypeInfo omap_gpio_info = { +static const TypeInfo omap_gpio_info = { .name = "omap-gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_gpif_s), @@ -776,7 +776,7 @@ static void omap2_gpio_class_init(ObjectClass *klass, void *data) dc->props = omap2_gpio_properties; } -static TypeInfo omap2_gpio_info = { +static const TypeInfo omap2_gpio_info = { .name = "omap2-gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap2_gpif_s), diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index ba08e6400c..e0a5087f37 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -471,7 +471,7 @@ static void omap_i2c_class_init(ObjectClass *klass, void *data) dc->reset = omap_i2c_reset; } -static TypeInfo omap_i2c_info = { +static const TypeInfo omap_i2c_info = { .name = "omap_i2c", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OMAPI2CState), diff --git a/hw/omap_intc.c b/hw/omap_intc.c index 61e0dafbdd..113725ef98 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -389,7 +389,7 @@ static void omap_intc_class_init(ObjectClass *klass, void *data) dc->props = omap_intc_properties; } -static TypeInfo omap_intc_info = { +static const TypeInfo omap_intc_info = { .name = "omap-intc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_intr_handler_s), @@ -633,7 +633,7 @@ static void omap2_intc_class_init(ObjectClass *klass, void *data) dc->props = omap2_intc_properties; } -static TypeInfo omap2_intc_info = { +static const TypeInfo omap2_intc_info = { .name = "omap2-intc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_intr_handler_s), diff --git a/hw/onenand.c b/hw/onenand.c index 26bf991d6d..b82bf7d333 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -821,7 +821,7 @@ static void onenand_class_init(ObjectClass *klass, void *data) dc->props = onenand_properties; } -static TypeInfo onenand_info = { +static const TypeInfo onenand_info = { .name = "onenand", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OneNANDState), diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index a0dfdce1f9..746a959f6b 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -718,7 +718,7 @@ static void open_eth_class_init(ObjectClass *klass, void *data) dc->props = open_eth_properties; } -static TypeInfo open_eth_info = { +static const TypeInfo open_eth_info = { .name = "open_eth", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OpenEthState), diff --git a/hw/openpic.c b/hw/openpic.c index 9c956b9dcc..23fa8f9635 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -39,26 +39,32 @@ #include "openpic.h" #include "sysbus.h" #include "pci/msi.h" +#include "qemu/bitops.h" //#define DEBUG_OPENPIC #ifdef DEBUG_OPENPIC -#define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0) +static const int debug_openpic = 1; #else -#define DPRINTF(fmt, ...) do { } while (0) +static const int debug_openpic = 0; #endif +#define DPRINTF(fmt, ...) do { \ + if (debug_openpic) { \ + printf(fmt , ## __VA_ARGS__); \ + } \ + } while (0) + #define MAX_CPU 15 #define MAX_SRC 256 #define MAX_TMR 4 -#define VECTOR_BITS 8 #define MAX_IPI 4 #define MAX_MSI 8 #define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR) #define VID 0x03 /* MPIC version ID */ /* OpenPIC capability flags */ -#define OPENPIC_FLAG_IDE_CRIT (1 << 0) +#define OPENPIC_FLAG_IDR_CRIT (1 << 0) /* OpenPIC address map */ #define OPENPIC_GLB_REG_START 0x0 @@ -115,14 +121,22 @@ #define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */ #define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */ -#define FREP_NIRQ_SHIFT 16 -#define FREP_NCPU_SHIFT 8 -#define FREP_VID_SHIFT 0 +#define FRR_NIRQ_SHIFT 16 +#define FRR_NCPU_SHIFT 8 +#define FRR_VID_SHIFT 0 #define VID_REVISION_1_2 2 #define VID_REVISION_1_3 3 -#define VENI_GENERIC 0x00000000 /* Generic Vendor ID */ +#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ + +#define GCR_RESET 0x80000000 +#define GCR_MODE_PASS 0x00000000 +#define GCR_MODE_MIXED 0x20000000 +#define GCR_MODE_PROXY 0x60000000 + +#define TBCR_CI 0x80000000 /* count inhibit */ +#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ #define IDR_EP_SHIFT 31 #define IDR_EP_MASK (1 << IDR_EP_SHIFT) @@ -137,27 +151,13 @@ #define MSIIR_IBS_SHIFT 24 #define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) -#define BF_WIDTH(_bits_) \ -(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) - -static inline void set_bit(uint32_t *field, int bit) -{ - field[bit >> 5] |= 1 << (bit & 0x1F); -} - -static inline void reset_bit(uint32_t *field, int bit) -{ - field[bit >> 5] &= ~(1 << (bit & 0x1F)); -} - -static inline int test_bit(uint32_t *field, int bit) -{ - return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; -} - static int get_current_cpu(void) { - return cpu_single_env->cpu_index; + if (!cpu_single_env) { + return -1; + } + + return cpu_single_env->cpu_index; } static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, @@ -165,43 +165,61 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); -typedef struct IRQ_queue_t { - uint32_t queue[BF_WIDTH(MAX_IRQ)]; +typedef enum IRQType { + IRQ_TYPE_NORMAL = 0, + IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ + IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ +} IRQType; + +typedef struct IRQQueue { + /* Round up to the nearest 64 IRQs so that the queue length + * won't change when moving between 32 and 64 bit hosts. + */ + unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)]; int next; int priority; - int pending; /* nr of pending bits in queue */ -} IRQ_queue_t; +} IRQQueue; -typedef struct IRQ_src_t { - uint32_t ipvp; /* IRQ vector/priority register */ - uint32_t ide; /* IRQ destination register */ +typedef struct IRQSource { + uint32_t ivpr; /* IRQ vector/priority register */ + uint32_t idr; /* IRQ destination register */ + uint32_t destmask; /* bitmap of CPU destinations */ int last_cpu; + int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ int pending; /* TRUE if IRQ is pending */ -} IRQ_src_t; - -#define IPVP_MASK_SHIFT 31 -#define IPVP_MASK_MASK (1 << IPVP_MASK_SHIFT) -#define IPVP_ACTIVITY_SHIFT 30 -#define IPVP_ACTIVITY_MASK (1 << IPVP_ACTIVITY_SHIFT) -#define IPVP_MODE_SHIFT 29 -#define IPVP_MODE_MASK (1 << IPVP_MODE_SHIFT) -#define IPVP_POLARITY_SHIFT 23 -#define IPVP_POLARITY_MASK (1 << IPVP_POLARITY_SHIFT) -#define IPVP_SENSE_SHIFT 22 -#define IPVP_SENSE_MASK (1 << IPVP_SENSE_SHIFT) - -#define IPVP_PRIORITY_MASK (0x1F << 16) -#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) -#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) -#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) - -typedef struct IRQ_dst_t { - uint32_t pctp; /* CPU current task priority */ - uint32_t pcsr; /* CPU sensitivity register */ - IRQ_queue_t raised; - IRQ_queue_t servicing; + IRQType type; + bool level:1; /* level-triggered */ + bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ +} IRQSource; + +#define IVPR_MASK_SHIFT 31 +#define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT) +#define IVPR_ACTIVITY_SHIFT 30 +#define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT) +#define IVPR_MODE_SHIFT 29 +#define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT) +#define IVPR_POLARITY_SHIFT 23 +#define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT) +#define IVPR_SENSE_SHIFT 22 +#define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT) + +#define IVPR_PRIORITY_MASK (0xF << 16) +#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) +#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) + +/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ +#define IDR_EP 0x80000000 /* external pin */ +#define IDR_CI 0x40000000 /* critical interrupt */ + +typedef struct IRQDest { + int32_t ctpr; /* CPU current task priority */ + IRQQueue raised; + IRQQueue servicing; qemu_irq *irqs; -} IRQ_dst_t; + + /* Count of IRQ sources asserting on non-INT outputs */ + uint32_t outputs_active[OPENPIC_OUTPUT_NB]; +} IRQDest; typedef struct OpenPICState { SysBusDevice busdev; @@ -212,31 +230,32 @@ typedef struct OpenPICState { uint32_t flags; uint32_t nb_irqs; uint32_t vid; - uint32_t veni; /* Vendor identification register */ - uint32_t spve_mask; - uint32_t tifr_reset; - uint32_t ipvp_reset; - uint32_t ide_reset; + uint32_t vir; /* Vendor identification register */ + uint32_t vector_mask; + uint32_t tfrr_reset; + uint32_t ivpr_reset; + uint32_t idr_reset; uint32_t brr1; + uint32_t mpic_mode_mask; /* Sub-regions */ MemoryRegion sub_io_mem[5]; /* Global registers */ - uint32_t frep; /* Feature reporting register */ - uint32_t glbc; /* Global configuration register */ - uint32_t pint; /* Processor initialization register */ + uint32_t frr; /* Feature reporting register */ + uint32_t gcr; /* Global configuration register */ + uint32_t pir; /* Processor initialization register */ uint32_t spve; /* Spurious vector register */ - uint32_t tifr; /* Timer frequency reporting register */ + uint32_t tfrr; /* Timer frequency reporting register */ /* Source registers */ - IRQ_src_t src[MAX_IRQ]; + IRQSource src[MAX_IRQ]; /* Local registers per output pin */ - IRQ_dst_t dst[MAX_CPU]; + IRQDest dst[MAX_CPU]; uint32_t nb_cpus; /* Timer registers */ struct { - uint32_t ticc; /* Global timer current count register */ - uint32_t tibc; /* Global timer base count register */ + uint32_t tccr; /* Global timer current count register */ + uint32_t tbcr; /* Global timer base count register */ } timers[MAX_TMR]; /* Shared MSI registers */ struct { @@ -248,156 +267,195 @@ typedef struct OpenPICState { uint32_t irq_msi; } OpenPICState; -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src); - -static inline void IRQ_setbit(IRQ_queue_t *q, int n_IRQ) +static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { - q->pending++; - set_bit(q->queue, n_IRQ); + set_bit(n_IRQ, q->queue); } -static inline void IRQ_resetbit(IRQ_queue_t *q, int n_IRQ) +static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) { - q->pending--; - reset_bit(q->queue, n_IRQ); + clear_bit(n_IRQ, q->queue); } -static inline int IRQ_testbit(IRQ_queue_t *q, int n_IRQ) +static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) { - return test_bit(q->queue, n_IRQ); + return test_bit(n_IRQ, q->queue); } -static void IRQ_check(OpenPICState *opp, IRQ_queue_t *q) +static void IRQ_check(OpenPICState *opp, IRQQueue *q) { - int next, i; - int priority; - - next = -1; - priority = -1; + int irq = -1; + int next = -1; + int priority = -1; + + for (;;) { + irq = find_next_bit(q->queue, opp->max_irq, irq + 1); + if (irq == opp->max_irq) { + break; + } - if (!q->pending) { - /* IRQ bitmap is empty */ - goto out; - } + DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", + irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); - for (i = 0; i < opp->max_irq; i++) { - if (IRQ_testbit(q, i)) { - DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", - i, IPVP_PRIORITY(opp->src[i].ipvp), priority); - if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { - next = i; - priority = IPVP_PRIORITY(opp->src[i].ipvp); - } + if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { + next = irq; + priority = IVPR_PRIORITY(opp->src[irq].ivpr); } } -out: q->next = next; q->priority = priority; } -static int IRQ_get_next(OpenPICState *opp, IRQ_queue_t *q) +static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) { - if (q->next == -1) { - /* XXX: optimize */ - IRQ_check(opp, q); - } + /* XXX: optimize */ + IRQ_check(opp, q); return q->next; } -static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) +static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, + bool active, bool was_active) { - IRQ_dst_t *dst; - IRQ_src_t *src; + IRQDest *dst; + IRQSource *src; int priority; dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; - priority = IPVP_PRIORITY(src->ipvp); - if (priority <= dst->pctp) { - /* Too low priority */ - DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", - __func__, n_IRQ, n_CPU); + + DPRINTF("%s: IRQ %d active %d was %d\n", + __func__, n_IRQ, active, was_active); + + if (src->output != OPENPIC_OUTPUT_INT) { + DPRINTF("%s: output %d irq %d active %d was %d count %d\n", + __func__, src->output, n_IRQ, active, was_active, + dst->outputs_active[src->output]); + + /* On Freescale MPIC, critical interrupts ignore priority, + * IACK, EOI, etc. Before MPIC v4.1 they also ignore + * masking. + */ + if (active) { + if (!was_active && dst->outputs_active[src->output]++ == 0) { + DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", + __func__, src->output, n_CPU, n_IRQ); + qemu_irq_raise(dst->irqs[src->output]); + } + } else { + if (was_active && --dst->outputs_active[src->output] == 0) { + DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n", + __func__, src->output, n_CPU, n_IRQ); + qemu_irq_lower(dst->irqs[src->output]); + } + } + return; } - if (IRQ_testbit(&dst->raised, n_IRQ)) { - /* Interrupt miss */ - DPRINTF("%s: IRQ %d was missed on CPU %d\n", - __func__, n_IRQ, n_CPU); - return; + + priority = IVPR_PRIORITY(src->ivpr); + + /* Even if the interrupt doesn't have enough priority, + * it is still raised, in case ctpr is lowered later. + */ + if (active) { + IRQ_setbit(&dst->raised, n_IRQ); + } else { + IRQ_resetbit(&dst->raised, n_IRQ); } - src->ipvp |= IPVP_ACTIVITY_MASK; - IRQ_setbit(&dst->raised, n_IRQ); - if (priority < dst->raised.priority) { - /* An higher priority IRQ is already raised */ - DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n", - __func__, n_IRQ, dst->raised.next, n_CPU); - return; + + IRQ_check(opp, &dst->raised); + + if (active && priority <= dst->ctpr) { + DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", + __func__, n_IRQ, priority, dst->ctpr, n_CPU); + active = 0; } - IRQ_get_next(opp, &dst->raised); - if (IRQ_get_next(opp, &dst->servicing) != -1 && - priority <= dst->servicing.priority) { - DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", - __func__, n_IRQ, dst->servicing.next, n_CPU); - /* Already servicing a higher priority IRQ */ - return; + + if (active) { + if (IRQ_get_next(opp, &dst->servicing) >= 0 && + priority <= dst->servicing.priority) { + DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", + __func__, n_IRQ, dst->servicing.next, n_CPU); + } else { + DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", + __func__, n_CPU, n_IRQ, dst->raised.next); + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + } + } else { + IRQ_get_next(opp, &dst->servicing); + if (dst->raised.priority > dst->ctpr && + dst->raised.priority > dst->servicing.priority) { + DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", + __func__, n_IRQ, dst->raised.next, dst->raised.priority, + dst->ctpr, dst->servicing.priority, n_CPU); + /* IRQ line stays asserted */ + } else { + DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", + __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU); + qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + } } - DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); - openpic_irq_raise(opp, n_CPU, src); } /* update pic state because registers for n_IRQ have changed value */ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) { - IRQ_src_t *src; + IRQSource *src; + bool active, was_active; int i; src = &opp->src[n_IRQ]; + active = src->pending; - if (!src->pending) { - /* no irq pending */ - DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); - return; - } - if (src->ipvp & IPVP_MASK_MASK) { + if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); - return; + active = false; } - if (IPVP_PRIORITY(src->ipvp) == 0) { - /* Priority set to zero */ - DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); + + was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); + + /* + * We don't have a similar check for already-active because + * ctpr may have changed and we need to withdraw the interrupt. + */ + if (!active && !was_active) { + DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ); return; } - if (src->ipvp & IPVP_ACTIVITY_MASK) { - /* IRQ already active */ - DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); - return; + + if (active) { + src->ivpr |= IVPR_ACTIVITY_MASK; + } else { + src->ivpr &= ~IVPR_ACTIVITY_MASK; } - if (src->ide == 0x00000000) { + + if (src->idr == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; } - if (src->ide == (1 << src->last_cpu)) { + if (src->idr == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ - IRQ_local_pipe(opp, src->last_cpu, n_IRQ); - } else if (!(src->ipvp & IPVP_MODE_MASK)) { + IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); + } else if (!(src->ivpr & IVPR_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { - if (src->ide & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ); + if (src->destmask & (1 << i)) { + IRQ_local_pipe(opp, i, n_IRQ, active, was_active); } } } else { /* Distributed delivery mode */ for (i = src->last_cpu + 1; i != src->last_cpu; i++) { - if (i == opp->nb_cpus) + if (i == opp->nb_cpus) { i = 0; - if (src->ide & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ); + } + if (src->destmask & (1 << i)) { + IRQ_local_pipe(opp, i, n_IRQ, active, was_active); src->last_cpu = i; break; } @@ -408,23 +466,38 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) static void openpic_set_irq(void *opaque, int n_IRQ, int level) { OpenPICState *opp = opaque; - IRQ_src_t *src; + IRQSource *src; + + if (n_IRQ >= MAX_IRQ) { + fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ); + abort(); + } src = &opp->src[n_IRQ]; - DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", - n_IRQ, level, src->ipvp); - if (src->ipvp & IPVP_SENSE_MASK) { + DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", + n_IRQ, level, src->ivpr); + if (src->level) { /* level-sensitive irq */ src->pending = level; - if (!level) { - src->ipvp &= ~IPVP_ACTIVITY_MASK; - } + openpic_update_irq(opp, n_IRQ); } else { /* edge-sensitive irq */ - if (level) + if (level) { src->pending = 1; + openpic_update_irq(opp, n_IRQ); + } + + if (src->output != OPENPIC_OUTPUT_INT) { + /* Edge-triggered interrupts shouldn't be used + * with non-INT delivery, but just in case, + * try to make it do something sane rather than + * cause an interrupt storm. This is close to + * what you'd probably see happen in real hardware. + */ + src->pending = 0; + openpic_update_irq(opp, n_IRQ); + } } - openpic_update_irq(opp, n_IRQ); } static void openpic_reset(DeviceState *d) @@ -432,79 +505,154 @@ static void openpic_reset(DeviceState *d) OpenPICState *opp = FROM_SYSBUS(typeof (*opp), sysbus_from_qdev(d)); int i; - opp->glbc = 0x80000000; + opp->gcr = GCR_RESET; /* Initialise controller registers */ - opp->frep = ((opp->nb_irqs -1) << FREP_NIRQ_SHIFT) | - ((opp->nb_cpus -1) << FREP_NCPU_SHIFT) | - (opp->vid << FREP_VID_SHIFT); + opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) | + ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) | + (opp->vid << FRR_VID_SHIFT); - opp->pint = 0x00000000; - opp->spve = -1 & opp->spve_mask; - opp->tifr = opp->tifr_reset; + opp->pir = 0; + opp->spve = -1 & opp->vector_mask; + opp->tfrr = opp->tfrr_reset; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { - opp->src[i].ipvp = opp->ipvp_reset; - opp->src[i].ide = opp->ide_reset; + opp->src[i].ivpr = opp->ivpr_reset; + opp->src[i].idr = opp->idr_reset; + + switch (opp->src[i].type) { + case IRQ_TYPE_NORMAL: + opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK); + break; + + case IRQ_TYPE_FSLINT: + opp->src[i].ivpr |= IVPR_POLARITY_MASK; + break; + + case IRQ_TYPE_FSLSPECIAL: + break; + } } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { - opp->dst[i].pctp = 0x0000000F; - opp->dst[i].pcsr = 0x00000000; - memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); + opp->dst[i].ctpr = 15; + memset(&opp->dst[i].raised, 0, sizeof(IRQQueue)); opp->dst[i].raised.next = -1; - memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); + memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue)); opp->dst[i].servicing.next = -1; } /* Initialise timers */ for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].ticc = 0x00000000; - opp->timers[i].tibc = 0x80000000; + opp->timers[i].tccr = 0; + opp->timers[i].tbcr = TBCR_CI; } /* Go out of RESET state */ - opp->glbc = 0x00000000; + opp->gcr = 0; } -static inline uint32_t read_IRQreg_ide(OpenPICState *opp, int n_IRQ) +static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ) { - return opp->src[n_IRQ].ide; + return opp->src[n_IRQ].idr; } -static inline uint32_t read_IRQreg_ipvp(OpenPICState *opp, int n_IRQ) +static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) { - return opp->src[n_IRQ].ipvp; + return opp->src[n_IRQ].ivpr; } -static inline void write_IRQreg_ide(OpenPICState *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) { - uint32_t tmp; + IRQSource *src = &opp->src[n_IRQ]; + uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; + uint32_t crit_mask = 0; + uint32_t mask = normal_mask; + int crit_shift = IDR_EP_SHIFT - opp->nb_cpus; + int i; + + if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { + crit_mask = mask << crit_shift; + mask |= crit_mask | IDR_EP; + } + + src->idr = val & mask; + DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); + + if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { + if (src->idr & crit_mask) { + if (src->idr & normal_mask) { + DPRINTF("%s: IRQ configured for multiple output types, using " + "critical\n", __func__); + } - tmp = val & 0xC0000000; - tmp |= val & ((1ULL << MAX_CPU) - 1); - opp->src[n_IRQ].ide = tmp; - DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); + src->output = OPENPIC_OUTPUT_CINT; + src->nomask = true; + src->destmask = 0; + + for (i = 0; i < opp->nb_cpus; i++) { + int n_ci = IDR_CI0_SHIFT - i; + + if (src->idr & (1UL << n_ci)) { + src->destmask |= 1UL << i; + } + } + } else { + src->output = OPENPIC_OUTPUT_INT; + src->nomask = false; + src->destmask = src->idr & normal_mask; + } + } else { + src->destmask = src->idr; + } } -static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) { - /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ + uint32_t mask; + + /* NOTE when implementing newer FSL MPIC models: starting with v4.0, + * the polarity bit is read-only on internal interrupts. + */ + mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | + IVPR_POLARITY_MASK | opp->vector_mask; + /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000) - | (val & 0x800F00FF); + opp->src[n_IRQ].ivpr = + (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); + + /* For FSL internal interrupts, The sense bit is reserved and zero, + * and the interrupt is always level-triggered. Timers and IPIs + * have no sense or polarity bits, and are edge-triggered. + */ + switch (opp->src[n_IRQ].type) { + case IRQ_TYPE_NORMAL: + opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); + break; + + case IRQ_TYPE_FSLINT: + opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; + break; + + case IRQ_TYPE_FSLSPECIAL: + opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); + break; + } + openpic_update_irq(opp, n_IRQ); - DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, - opp->src[n_IRQ].ipvp); + DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, + opp->src[n_IRQ].ivpr); } static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { OpenPICState *opp = opaque; - IRQ_dst_t *dst; + IRQDest *dst; int idx; - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); + if (addr & 0xF) { return; + } switch (addr) { case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ break; @@ -518,41 +666,55 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0xB0: openpic_cpu_write_internal(opp, addr, val, get_current_cpu()); break; - case 0x1000: /* FREP */ + case 0x1000: /* FRR */ break; - case 0x1020: /* GLBC */ - if (val & 0x80000000) { + case 0x1020: /* GCR */ + if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); + } else if (opp->mpic_mode_mask) { + CPUArchState *env; + int mpic_proxy = 0; + + opp->gcr &= ~opp->mpic_mode_mask; + opp->gcr |= val & opp->mpic_mode_mask; + + /* Set external proxy mode */ + if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { + mpic_proxy = 1; + } + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = mpic_proxy; + } } break; - case 0x1080: /* VENI */ + case 0x1080: /* VIR */ break; - case 0x1090: /* PINT */ + case 0x1090: /* PIR */ for (idx = 0; idx < opp->nb_cpus; idx++) { - if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) { + if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); dst = &opp->dst[idx]; qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); - } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) { + } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); dst = &opp->dst[idx]; qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); } } - opp->pint = val; + opp->pir = val; break; - case 0x10A0: /* IPI_IPVP */ + case 0x10A0: /* IPI_IVPR */ case 0x10B0: case 0x10C0: case 0x10D0: { int idx; idx = (addr - 0x10A0) >> 4; - write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val); + write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); } break; case 0x10E0: /* SPVE */ - opp->spve = val & opp->spve_mask; + opp->spve = val & opp->vector_mask; break; default: break; @@ -564,24 +726,27 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) OpenPICState *opp = opaque; uint32_t retval; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) + if (addr & 0xF) { return retval; + } switch (addr) { - case 0x1000: /* FREP */ - retval = opp->frep; + case 0x1000: /* FRR */ + retval = opp->frr; break; - case 0x1020: /* GLBC */ - retval = opp->glbc; + case 0x1020: /* GCR */ + retval = opp->gcr; break; - case 0x1080: /* VENI */ - retval = opp->veni; + case 0x1080: /* VIR */ + retval = opp->vir; break; - case 0x1090: /* PINT */ + case 0x1090: /* PIR */ retval = 0x00000000; break; case 0x00: /* Block Revision Register1 (BRR1) */ + retval = opp->brr1; + break; case 0x40: case 0x50: case 0x60: @@ -592,14 +757,14 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) case 0xB0: retval = openpic_cpu_read_internal(opp, addr, get_current_cpu()); break; - case 0x10A0: /* IPI_IPVP */ + case 0x10A0: /* IPI_IVPR */ case 0x10B0: case 0x10C0: case 0x10D0: { int idx; idx = (addr - 0x10A0) >> 4; - retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx); + retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx); } break; case 0x10E0: /* SPVE */ @@ -608,7 +773,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) default: break; } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -619,32 +784,35 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); + if (addr & 0xF) { return; + } idx = (addr >> 6) & 0x3; addr = addr & 0x30; if (addr == 0x0) { - /* TIFR (TFRR) */ - opp->tifr = val; + /* TFRR */ + opp->tfrr = val; return; } switch (addr & 0x30) { - case 0x00: /* TICC (GTCCR) */ + case 0x00: /* TCCR */ break; - case 0x10: /* TIBC (GTBCR) */ - if ((opp->timers[idx].ticc & 0x80000000) != 0 && - (val & 0x80000000) == 0 && - (opp->timers[idx].tibc & 0x80000000) != 0) - opp->timers[idx].ticc &= ~0x80000000; - opp->timers[idx].tibc = val; + case 0x10: /* TBCR */ + if ((opp->timers[idx].tccr & TCCR_TOG) != 0 && + (val & TBCR_CI) == 0 && + (opp->timers[idx].tbcr & TBCR_CI) != 0) { + opp->timers[idx].tccr &= ~TCCR_TOG; + } + opp->timers[idx].tbcr = val; break; - case 0x20: /* TIVP (GTIVPR) */ - write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val); + case 0x20: /* TVPR */ + write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val); break; - case 0x30: /* TIDE (GTIDR) */ - write_IRQreg_ide(opp, opp->irq_tim0 + idx, val); + case 0x30: /* TDR */ + write_IRQreg_idr(opp, opp->irq_tim0 + idx, val); break; } } @@ -655,33 +823,33 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) uint32_t retval = -1; int idx; - DPRINTF("%s: addr %08x\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); if (addr & 0xF) { goto out; } idx = (addr >> 6) & 0x3; if (addr == 0x0) { - /* TIFR (TFRR) */ - retval = opp->tifr; + /* TFRR */ + retval = opp->tfrr; goto out; } switch (addr & 0x30) { - case 0x00: /* TICC (GTCCR) */ - retval = opp->timers[idx].ticc; + case 0x00: /* TCCR */ + retval = opp->timers[idx].tccr; break; - case 0x10: /* TIBC (GTBCR) */ - retval = opp->timers[idx].tibc; + case 0x10: /* TBCR */ + retval = opp->timers[idx].tbcr; break; - case 0x20: /* TIPV (TIPV) */ - retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx); + case 0x20: /* TIPV */ + retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); break; case 0x30: /* TIDE (TIDR) */ - retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx); + retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx); break; } out: - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -692,17 +860,19 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); + if (addr & 0xF) { return; + } addr = addr & 0xFFF0; idx = addr >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(opp, idx, val); + write_IRQreg_idr(opp, idx, val); } else { /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(opp, idx, val); + write_IRQreg_ivpr(opp, idx, val); } } @@ -712,20 +882,21 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) uint32_t retval; int idx; - DPRINTF("%s: addr %08x\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) + if (addr & 0xF) { return retval; + } addr = addr & 0xFFF0; idx = addr >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(opp, idx); + retval = read_IRQreg_idr(opp, idx); } else { /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(opp, idx); + retval = read_IRQreg_ivpr(opp, idx); } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -737,7 +908,8 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, int idx = opp->irq_msi; int srs, ibs; - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -762,7 +934,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) uint64_t r = 0; int i, srs; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); if (addr & 0xF) { return -1; } @@ -781,6 +953,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) r = opp->msi[srs].msir; /* Clear on read */ opp->msi[srs].msir = 0; + openpic_set_irq(opp, opp->irq_msi + srs, 0); break; case 0x120: /* MSISR */ for (i = 0; i < MAX_MSI; i++) { @@ -796,14 +969,20 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx) { OpenPICState *opp = opaque; - IRQ_src_t *src; - IRQ_dst_t *dst; + IRQSource *src; + IRQDest *dst; int s_IRQ, n_IRQ; - DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx, + DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx, addr, val); - if (addr & 0xF) + + if (idx < 0) { return; + } + + if (addr & 0xF) { + return; + } dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { @@ -813,25 +992,45 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, case 0x70: idx = (addr - 0x40) >> 4; /* we use IDE as mask which CPUs to deliver the IPI to still. */ - write_IRQreg_ide(opp, opp->irq_ipi0 + idx, - opp->src[opp->irq_ipi0 + idx].ide | val); + write_IRQreg_idr(opp, opp->irq_ipi0 + idx, + opp->src[opp->irq_ipi0 + idx].idr | val); openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); break; - case 0x80: /* PCTP */ - dst->pctp = val & 0x0000000F; + case 0x80: /* CTPR */ + dst->ctpr = val & 0x0000000F; + + DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n", + __func__, idx, dst->ctpr, dst->raised.priority, + dst->servicing.priority); + + if (dst->raised.priority <= dst->ctpr) { + DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n", + __func__, idx); + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); + } else if (dst->raised.priority > dst->servicing.priority) { + DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n", + __func__, idx, dst->raised.next); + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); + } + break; case 0x90: /* WHOAMI */ /* Read-only register */ break; - case 0xA0: /* PIAC */ + case 0xA0: /* IACK */ /* Read-only register */ break; - case 0xB0: /* PEOI */ - DPRINTF("PEOI\n"); + case 0xB0: /* EOI */ + DPRINTF("EOI\n"); s_IRQ = IRQ_get_next(opp, &dst->servicing); + + if (s_IRQ < 0) { + DPRINTF("%s: EOI with no interrupt in service\n", __func__); + break; + } + IRQ_resetbit(&dst->servicing, s_IRQ); - dst->servicing.next = -1; /* Set up next servicing IRQ */ s_IRQ = IRQ_get_next(opp, &dst->servicing); /* Check queued interrupts. */ @@ -839,10 +1038,10 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, src = &opp->src[n_IRQ]; if (n_IRQ != -1 && (s_IRQ == -1 || - IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { + IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", idx, n_IRQ); - openpic_irq_raise(opp, idx, src); + qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); } break; default: @@ -856,81 +1055,93 @@ static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val, openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); } + +static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) +{ + IRQSource *src; + int retval, irq; + + DPRINTF("Lower OpenPIC INT output\n"); + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); + + irq = IRQ_get_next(opp, &dst->raised); + DPRINTF("IACK: irq=%d\n", irq); + + if (irq == -1) { + /* No more interrupt pending */ + return opp->spve; + } + + src = &opp->src[irq]; + if (!(src->ivpr & IVPR_ACTIVITY_MASK) || + !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { + fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n", + __func__, irq, dst->ctpr, src->ivpr); + openpic_update_irq(opp, irq); + retval = opp->spve; + } else { + /* IRQ enter servicing state */ + IRQ_setbit(&dst->servicing, irq); + retval = IVPR_VECTOR(opp, src->ivpr); + } + + if (!src->level) { + /* edge-sensitive IRQ */ + src->ivpr &= ~IVPR_ACTIVITY_MASK; + src->pending = 0; + IRQ_resetbit(&dst->raised, irq); + } + + if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { + src->idr &= ~(1 << cpu); + if (src->idr && !src->level) { + /* trigger on CPUs that didn't know about it yet */ + openpic_set_irq(opp, irq, 1); + openpic_set_irq(opp, irq, 0); + /* if all CPUs knew about it, set active bit again */ + src->ivpr |= IVPR_ACTIVITY_MASK; + } + } + + return retval; +} + static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, int idx) { OpenPICState *opp = opaque; - IRQ_src_t *src; - IRQ_dst_t *dst; + IRQDest *dst; uint32_t retval; - int n_IRQ; - DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr); + DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) + + if (idx < 0) { + return retval; + } + + if (addr & 0xF) { return retval; + } dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { - case 0x00: /* Block Revision Register1 (BRR1) */ - retval = opp->brr1; - break; - case 0x80: /* PCTP */ - retval = dst->pctp; + case 0x80: /* CTPR */ + retval = dst->ctpr; break; case 0x90: /* WHOAMI */ retval = idx; break; - case 0xA0: /* PIAC */ - DPRINTF("Lower OpenPIC INT output\n"); - qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); - n_IRQ = IRQ_get_next(opp, &dst->raised); - DPRINTF("PIAC: irq=%d\n", n_IRQ); - if (n_IRQ == -1) { - /* No more interrupt pending */ - retval = IPVP_VECTOR(opp->spve); - } else { - src = &opp->src[n_IRQ]; - if (!(src->ipvp & IPVP_ACTIVITY_MASK) || - !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { - /* - Spurious level-sensitive IRQ - * - Priorities has been changed - * and the pending IRQ isn't allowed anymore - */ - src->ipvp &= ~IPVP_ACTIVITY_MASK; - retval = IPVP_VECTOR(opp->spve); - } else { - /* IRQ enter servicing state */ - IRQ_setbit(&dst->servicing, n_IRQ); - retval = IPVP_VECTOR(src->ipvp); - } - IRQ_resetbit(&dst->raised, n_IRQ); - dst->raised.next = -1; - if (!(src->ipvp & IPVP_SENSE_MASK)) { - /* edge-sensitive IRQ */ - src->ipvp &= ~IPVP_ACTIVITY_MASK; - src->pending = 0; - } - - if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { - src->ide &= ~(1 << idx); - if (src->ide && !(src->ipvp & IPVP_SENSE_MASK)) { - /* trigger on CPUs that didn't know about it yet */ - openpic_set_irq(opp, n_IRQ, 1); - openpic_set_irq(opp, n_IRQ, 0); - /* if all CPUs knew about it, set active bit again */ - src->ipvp |= IPVP_ACTIVITY_MASK; - } - } - } + case 0xA0: /* IACK */ + retval = openpic_iack(opp, dst, idx); break; - case 0xB0: /* PEOI */ + case 0xB0: /* EOI */ retval = 0; break; default: break; } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -1040,12 +1251,20 @@ static const MemoryRegionOps openpic_msi_ops_be = { }, }; -static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) +static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; - for (i = 0; i < BF_WIDTH(MAX_IRQ); i++) - qemu_put_be32s(f, &q->queue[i]); + for (i = 0; i < ARRAY_SIZE(q->queue); i++) { + /* Always put the lower half of a 64-bit long first, in case we + * restore on a 32-bit host. The least significant bits correspond + * to lower IRQ numbers in the bitmap. + */ + qemu_put_be32(f, (uint32_t)q->queue[i]); +#if LONG_MAX > 0x7FFFFFFF + qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32)); +#endif + } qemu_put_sbe32s(f, &q->next); qemu_put_sbe32s(f, &q->priority); @@ -1056,40 +1275,50 @@ static void openpic_save(QEMUFile* f, void *opaque) OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; - qemu_put_be32s(f, &opp->glbc); - qemu_put_be32s(f, &opp->veni); - qemu_put_be32s(f, &opp->pint); + qemu_put_be32s(f, &opp->gcr); + qemu_put_be32s(f, &opp->vir); + qemu_put_be32s(f, &opp->pir); qemu_put_be32s(f, &opp->spve); - qemu_put_be32s(f, &opp->tifr); - - for (i = 0; i < opp->max_irq; i++) { - qemu_put_be32s(f, &opp->src[i].ipvp); - qemu_put_be32s(f, &opp->src[i].ide); - qemu_put_sbe32s(f, &opp->src[i].last_cpu); - qemu_put_sbe32s(f, &opp->src[i].pending); - } + qemu_put_be32s(f, &opp->tfrr); qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_put_be32s(f, &opp->dst[i].pctp); - qemu_put_be32s(f, &opp->dst[i].pcsr); + qemu_put_sbe32s(f, &opp->dst[i].ctpr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); + qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, + sizeof(opp->dst[i].outputs_active)); } for (i = 0; i < MAX_TMR; i++) { - qemu_put_be32s(f, &opp->timers[i].ticc); - qemu_put_be32s(f, &opp->timers[i].tibc); + qemu_put_be32s(f, &opp->timers[i].tccr); + qemu_put_be32s(f, &opp->timers[i].tbcr); + } + + for (i = 0; i < opp->max_irq; i++) { + qemu_put_be32s(f, &opp->src[i].ivpr); + qemu_put_be32s(f, &opp->src[i].idr); + qemu_put_sbe32s(f, &opp->src[i].last_cpu); + qemu_put_sbe32s(f, &opp->src[i].pending); } } -static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) +static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; - for (i = 0; i < BF_WIDTH(MAX_IRQ); i++) - qemu_get_be32s(f, &q->queue[i]); + for (i = 0; i < ARRAY_SIZE(q->queue); i++) { + unsigned long val; + + val = qemu_get_be32(f); +#if LONG_MAX > 0x7FFFFFFF + val <<= 32; + val |= qemu_get_be32(f); +#endif + + q->queue[i] = val; + } qemu_get_sbe32s(f, &q->next); qemu_get_sbe32s(f, &q->priority); @@ -1100,63 +1329,61 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; - if (version_id != 1) + if (version_id != 1) { return -EINVAL; + } - qemu_get_be32s(f, &opp->glbc); - qemu_get_be32s(f, &opp->veni); - qemu_get_be32s(f, &opp->pint); + qemu_get_be32s(f, &opp->gcr); + qemu_get_be32s(f, &opp->vir); + qemu_get_be32s(f, &opp->pir); qemu_get_be32s(f, &opp->spve); - qemu_get_be32s(f, &opp->tifr); - - for (i = 0; i < opp->max_irq; i++) { - qemu_get_be32s(f, &opp->src[i].ipvp); - qemu_get_be32s(f, &opp->src[i].ide); - qemu_get_sbe32s(f, &opp->src[i].last_cpu); - qemu_get_sbe32s(f, &opp->src[i].pending); - } + qemu_get_be32s(f, &opp->tfrr); qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_get_be32s(f, &opp->dst[i].pctp); - qemu_get_be32s(f, &opp->dst[i].pcsr); + qemu_get_sbe32s(f, &opp->dst[i].ctpr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); + qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, + sizeof(opp->dst[i].outputs_active)); } for (i = 0; i < MAX_TMR; i++) { - qemu_get_be32s(f, &opp->timers[i].ticc); - qemu_get_be32s(f, &opp->timers[i].tibc); + qemu_get_be32s(f, &opp->timers[i].tccr); + qemu_get_be32s(f, &opp->timers[i].tbcr); } - return 0; -} + for (i = 0; i < opp->max_irq; i++) { + uint32_t val; -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src) -{ - int n_ci = IDR_CI0_SHIFT - n_CPU; + val = qemu_get_be32(f); + write_IRQreg_idr(opp, i, val); + val = qemu_get_be32(f); + write_IRQreg_ivpr(opp, i, val); - if ((opp->flags & OPENPIC_FLAG_IDE_CRIT) && (src->ide & (1 << n_ci))) { - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); - } else { - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + qemu_get_be32s(f, &opp->src[i].ivpr); + qemu_get_be32s(f, &opp->src[i].idr); + qemu_get_sbe32s(f, &opp->src[i].last_cpu); + qemu_get_sbe32s(f, &opp->src[i].pending); } + + return 0; } -struct memreg { +typedef struct MemReg { const char *name; MemoryRegionOps const *ops; bool map; hwaddr start_addr; ram_addr_t size; -}; +} MemReg; static int openpic_init(SysBusDevice *dev) { OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); int i, j; - struct memreg list_le[] = { + MemReg list_le[] = { {"glb", &openpic_glb_ops_le, true, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, {"tmr", &openpic_tmr_ops_le, true, @@ -1168,7 +1395,7 @@ static int openpic_init(SysBusDevice *dev) {"cpu", &openpic_cpu_ops_le, true, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, }; - struct memreg list_be[] = { + MemReg list_be[] = { {"glb", &openpic_glb_ops_be, true, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, {"tmr", &openpic_tmr_ops_be, true, @@ -1180,35 +1407,56 @@ static int openpic_init(SysBusDevice *dev) {"cpu", &openpic_cpu_ops_be, true, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, }; - struct memreg *list; + MemReg *list; switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: default: - opp->flags |= OPENPIC_FLAG_IDE_CRIT; + opp->flags |= OPENPIC_FLAG_IDR_CRIT; opp->nb_irqs = 80; opp->vid = VID_REVISION_1_2; - opp->veni = VENI_GENERIC; - opp->spve_mask = 0xFFFF; - opp->tifr_reset = 0x00000000; - opp->ipvp_reset = 0x80000000; - opp->ide_reset = 0x00000001; + opp->vir = VIR_GENERIC; + opp->vector_mask = 0xFFFF; + opp->tfrr_reset = 0; + opp->ivpr_reset = IVPR_MASK_MASK; + opp->idr_reset = 1 << 0; opp->max_irq = FSL_MPIC_20_MAX_IRQ; opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; opp->irq_msi = FSL_MPIC_20_MSI_IRQ; opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; + /* XXX really only available as of MPIC 4.0 */ + opp->mpic_mode_mask = GCR_MODE_PROXY; + msi_supported = true; list = list_be; + + for (i = 0; i < FSL_MPIC_20_MAX_EXT; i++) { + opp->src[i].level = false; + } + + /* Internal interrupts, including message and MSI */ + for (i = 16; i < MAX_SRC; i++) { + opp->src[i].type = IRQ_TYPE_FSLINT; + opp->src[i].level = true; + } + + /* timers and IPIs */ + for (i = MAX_SRC; i < MAX_IRQ; i++) { + opp->src[i].type = IRQ_TYPE_FSLSPECIAL; + opp->src[i].level = false; + } + break; + case OPENPIC_MODEL_RAVEN: opp->nb_irqs = RAVEN_MAX_EXT; opp->vid = VID_REVISION_1_3; - opp->veni = VENI_GENERIC; - opp->spve_mask = 0xFF; - opp->tifr_reset = 0x003F7A00; - opp->ipvp_reset = 0xA0000000; - opp->ide_reset = 0x00000000; + opp->vir = VIR_GENERIC; + opp->vector_mask = 0xFF; + opp->tfrr_reset = 4160000; + opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK; + opp->idr_reset = 0; opp->max_irq = RAVEN_MAX_IRQ; opp->irq_ipi0 = RAVEN_IPI_IRQ; opp->irq_tim0 = RAVEN_TMR_IRQ; @@ -1270,7 +1518,7 @@ static void openpic_class_init(ObjectClass *klass, void *data) dc->reset = openpic_reset; } -static TypeInfo openpic_info = { +static const TypeInfo openpic_info = { .name = "openpic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OpenPICState), diff --git a/hw/parallel.c b/hw/parallel.c index 64a46c6055..3a4e06bab0 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -599,7 +599,7 @@ static void parallel_isa_class_initfn(ObjectClass *klass, void *data) dc->props = parallel_isa_properties; } -static TypeInfo parallel_isa_info = { +static const TypeInfo parallel_isa_info = { .name = "isa-parallel", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAParallelState), diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c index 192848998c..ec0bc4bb95 100644 --- a/hw/pc-testdev.c +++ b/hw/pc-testdev.c @@ -172,7 +172,7 @@ static void testdev_class_init(ObjectClass *klass, void *data) k->init = init_test_device; } -static TypeInfo testdev_info = { +static const TypeInfo testdev_info = { .name = TYPE_TESTDEV, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(struct PCTestdev), @@ -103,6 +103,11 @@ static void ioport80_write(void *opaque, hwaddr addr, uint64_t data, { } +static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0xffffffffffffffffULL; +} + /* MSDOS compatibility mode FPU exception support */ static qemu_irq ferr_irq; @@ -123,6 +128,11 @@ static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data, qemu_irq_lower(ferr_irq); } +static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0xffffffffffffffffULL; +} + /* TSC handling */ uint64_t cpu_get_tsc(CPUX86State *env) { @@ -501,7 +511,7 @@ static void port92_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_port92_isa; } -static TypeInfo port92_info = { +static const TypeInfo port92_info = { .name = "port92", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(Port92State), @@ -960,6 +970,7 @@ static void cpu_request_exit(void *opaque, int irq, int level) static const MemoryRegionOps ioport80_io_ops = { .write = ioport80_write, + .read = ioport80_read, .endianness = DEVICE_NATIVE_ENDIAN, .impl = { .min_access_size = 1, @@ -969,6 +980,7 @@ static const MemoryRegionOps ioport80_io_ops = { static const MemoryRegionOps ioportF0_io_ops = { .write = ioportF0_write, + .read = ioportF0_read, .endianness = DEVICE_NATIVE_ENDIAN, .impl = { .min_access_size = 1, diff --git a/hw/pc87312.c b/hw/pc87312.c new file mode 100644 index 0000000000..6a17afd45c --- /dev/null +++ b/hw/pc87312.c @@ -0,0 +1,387 @@ +/* + * QEMU National Semiconductor PC87312 (Super I/O) + * + * Copyright (c) 2010-2012 Herve Poussineau + * Copyright (c) 2011-2012 Andreas Färber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "pc87312.h" +#include "sysemu/blockdev.h" +#include "sysemu/sysemu.h" +#include "char/char.h" +#include "trace.h" + + +#define REG_FER 0 +#define REG_FAR 1 +#define REG_PTR 2 + +#define FER regs[REG_FER] +#define FAR regs[REG_FAR] +#define PTR regs[REG_PTR] + +#define FER_PARALLEL_EN 0x01 +#define FER_UART1_EN 0x02 +#define FER_UART2_EN 0x04 +#define FER_FDC_EN 0x08 +#define FER_FDC_4 0x10 +#define FER_FDC_ADDR 0x20 +#define FER_IDE_EN 0x40 +#define FER_IDE_ADDR 0x80 + +#define FAR_PARALLEL_ADDR 0x03 +#define FAR_UART1_ADDR 0x0C +#define FAR_UART2_ADDR 0x30 +#define FAR_UART_3_4 0xC0 + +#define PTR_POWER_DOWN 0x01 +#define PTR_CLOCK_DOWN 0x02 +#define PTR_PWDN 0x04 +#define PTR_IRQ_5_7 0x08 +#define PTR_UART1_TEST 0x10 +#define PTR_UART2_TEST 0x20 +#define PTR_LOCK_CONF 0x40 +#define PTR_EPP_MODE 0x80 + + +/* Parallel port */ + +static inline bool is_parallel_enabled(PC87312State *s) +{ + return s->FER & FER_PARALLEL_EN; +} + +static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 }; + +static inline uint32_t get_parallel_iobase(PC87312State *s) +{ + return parallel_base[s->FAR & FAR_PARALLEL_ADDR]; +} + +static const uint32_t parallel_irq[] = { 5, 7, 5, 0 }; + +static inline uint32_t get_parallel_irq(PC87312State *s) +{ + int idx; + idx = (s->FAR & FAR_PARALLEL_ADDR); + if (idx == 0) { + return (s->PTR & PTR_IRQ_5_7) ? 7 : 5; + } else { + return parallel_irq[idx]; + } +} + +static inline bool is_parallel_epp(PC87312State *s) +{ + return s->PTR & PTR_EPP_MODE; +} + + +/* UARTs */ + +static const uint32_t uart_base[2][4] = { + { 0x3e8, 0x338, 0x2e8, 0x220 }, + { 0x2e8, 0x238, 0x2e0, 0x228 } +}; + +static inline uint32_t get_uart_iobase(PC87312State *s, int i) +{ + int idx; + idx = (s->FAR >> (2 * i + 2)) & 0x3; + if (idx == 0) { + return 0x3f8; + } else if (idx == 1) { + return 0x2f8; + } else { + return uart_base[idx & 1][(s->FAR & FAR_UART_3_4) >> 6]; + } +} + +static inline uint32_t get_uart_irq(PC87312State *s, int i) +{ + int idx; + idx = (s->FAR >> (2 * i + 2)) & 0x3; + return (idx & 1) ? 3 : 4; +} + +static inline bool is_uart_enabled(PC87312State *s, int i) +{ + return s->FER & (FER_UART1_EN << i); +} + + +/* Floppy controller */ + +static inline bool is_fdc_enabled(PC87312State *s) +{ + return s->FER & FER_FDC_EN; +} + +static inline uint32_t get_fdc_iobase(PC87312State *s) +{ + return (s->FER & FER_FDC_ADDR) ? 0x370 : 0x3f0; +} + + +/* IDE controller */ + +static inline bool is_ide_enabled(PC87312State *s) +{ + return s->FER & FER_IDE_EN; +} + +static inline uint32_t get_ide_iobase(PC87312State *s) +{ + return (s->FER & FER_IDE_ADDR) ? 0x170 : 0x1f0; +} + + +static void reconfigure_devices(PC87312State *s) +{ + error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)", + s->FER, s->FAR, s->PTR); +} + +static void pc87312_soft_reset(PC87312State *s) +{ + static const uint8_t fer_init[] = { + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x0f, 0x0f, 0x0f, 0x0f, + 0x49, 0x49, 0x49, 0x49, 0x07, 0x07, 0x07, 0x07, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x08, 0x00, + }; + static const uint8_t far_init[] = { + 0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x00, 0x01, + 0x01, 0x09, 0x08, 0x08, 0x10, 0x11, 0x39, 0x24, + 0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x39, 0x24, + 0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x10, 0x10, + }; + static const uint8_t ptr_init[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + }; + + s->read_id_step = 0; + s->selected_index = REG_FER; + + s->FER = fer_init[s->config & 0x1f]; + s->FAR = far_init[s->config & 0x1f]; + s->PTR = ptr_init[s->config & 0x1f]; +} + +static void pc87312_hard_reset(PC87312State *s) +{ + pc87312_soft_reset(s); +} + +static void pc87312_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + PC87312State *s = opaque; + + trace_pc87312_io_write(addr, val); + + if ((addr & 1) == 0) { + /* Index register */ + s->read_id_step = 2; + s->selected_index = val; + } else { + /* Data register */ + if (s->selected_index < 3) { + s->regs[s->selected_index] = val; + reconfigure_devices(s); + } + } +} + +static uint32_t pc87312_ioport_read(void *opaque, uint32_t addr) +{ + PC87312State *s = opaque; + uint32_t val; + + if ((addr & 1) == 0) { + /* Index register */ + if (s->read_id_step++ == 0) { + val = 0x88; + } else if (s->read_id_step++ == 1) { + val = 0; + } else { + val = s->selected_index; + } + } else { + /* Data register */ + if (s->selected_index < 3) { + val = s->regs[s->selected_index]; + } else { + /* Invalid selected index */ + val = 0; + } + } + + trace_pc87312_io_read(addr, val); + return val; +} + +static int pc87312_post_load(void *opaque, int version_id) +{ + PC87312State *s = opaque; + + reconfigure_devices(s); + return 0; +} + +static void pc87312_reset(DeviceState *d) +{ + PC87312State *s = PC87312(d); + + pc87312_soft_reset(s); +} + +static int pc87312_init(ISADevice *dev) +{ + PC87312State *s; + DeviceState *d; + ISADevice *isa; + ISABus *bus; + CharDriverState *chr; + DriveInfo *drive; + char name[5]; + int i; + + s = PC87312(dev); + bus = isa_bus_from_device(dev); + pc87312_hard_reset(s); + + if (is_parallel_enabled(s)) { + chr = parallel_hds[0]; + if (chr == NULL) { + chr = qemu_chr_new("par0", "null", NULL); + } + isa = isa_create(bus, "isa-parallel"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "index", 0); + qdev_prop_set_uint32(d, "iobase", get_parallel_iobase(s)); + qdev_prop_set_uint32(d, "irq", get_parallel_irq(s)); + qdev_prop_set_chr(d, "chardev", chr); + qdev_init_nofail(d); + s->parallel.dev = isa; + trace_pc87312_info_parallel(get_parallel_iobase(s), + get_parallel_irq(s)); + } + + for (i = 0; i < 2; i++) { + if (is_uart_enabled(s, i)) { + chr = serial_hds[i]; + if (chr == NULL) { + snprintf(name, sizeof(name), "ser%d", i); + chr = qemu_chr_new(name, "null", NULL); + } + isa = isa_create(bus, "isa-serial"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "index", i); + qdev_prop_set_uint32(d, "iobase", get_uart_iobase(s, i)); + qdev_prop_set_uint32(d, "irq", get_uart_irq(s, i)); + qdev_prop_set_chr(d, "chardev", chr); + qdev_init_nofail(d); + s->uart[i].dev = isa; + trace_pc87312_info_serial(i, get_uart_iobase(s, i), + get_uart_irq(s, i)); + } + } + + if (is_fdc_enabled(s)) { + isa = isa_create(bus, "isa-fdc"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "iobase", get_fdc_iobase(s)); + qdev_prop_set_uint32(d, "irq", 6); + drive = drive_get(IF_FLOPPY, 0, 0); + if (drive != NULL) { + qdev_prop_set_drive_nofail(d, "driveA", drive->bdrv); + } + drive = drive_get(IF_FLOPPY, 0, 1); + if (drive != NULL) { + qdev_prop_set_drive_nofail(d, "driveB", drive->bdrv); + } + qdev_init_nofail(d); + s->fdc.dev = isa; + trace_pc87312_info_floppy(get_fdc_iobase(s)); + } + + if (is_ide_enabled(s)) { + isa = isa_create(bus, "isa-ide"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "iobase", get_ide_iobase(s)); + qdev_prop_set_uint32(d, "iobase2", get_ide_iobase(s) + 0x206); + qdev_prop_set_uint32(d, "irq", 14); + qdev_init_nofail(d); + s->ide.dev = isa; + trace_pc87312_info_ide(get_ide_iobase(s)); + } + + register_ioport_write(s->iobase, 2, 1, pc87312_ioport_write, s); + register_ioport_read(s->iobase, 2, 1, pc87312_ioport_read, s); + return 0; +} + +static const VMStateDescription vmstate_pc87312 = { + .name = "pc87312", + .version_id = 1, + .minimum_version_id = 1, + .post_load = pc87312_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(read_id_step, PC87312State), + VMSTATE_UINT8(selected_index, PC87312State), + VMSTATE_UINT8_ARRAY(regs, PC87312State, 3), + VMSTATE_END_OF_LIST() + } +}; + +static Property pc87312_properties[] = { + DEFINE_PROP_HEX32("iobase", PC87312State, iobase, 0x398), + DEFINE_PROP_UINT8("config", PC87312State, config, 1), + DEFINE_PROP_END_OF_LIST() +}; + +static void pc87312_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + + ic->init = pc87312_init; + dc->reset = pc87312_reset; + dc->vmsd = &vmstate_pc87312; + dc->props = pc87312_properties; +} + +static const TypeInfo pc87312_type_info = { + .name = TYPE_PC87312, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(PC87312State), + .class_init = pc87312_class_init, +}; + +static void pc87312_register_types(void) +{ + type_register_static(&pc87312_type_info); +} + +type_init(pc87312_register_types) diff --git a/hw/pc87312.h b/hw/pc87312.h new file mode 100644 index 0000000000..7ca7912ba7 --- /dev/null +++ b/hw/pc87312.h @@ -0,0 +1,66 @@ +/* + * QEMU National Semiconductor PC87312 (Super I/O) + * + * Copyright (c) 2010-2012 Herve Poussineau + * Copyright (c) 2011-2012 Andreas Färber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_PC87312_H +#define QEMU_PC87312_H + +#include "isa.h" + + +#define TYPE_PC87312 "pc87312" +#define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312) + +typedef struct PC87312State { + ISADevice dev; + + uint32_t iobase; + uint8_t config; /* initial configuration */ + + struct { + ISADevice *dev; + } parallel; + + struct { + ISADevice *dev; + } uart[2]; + + struct { + ISADevice *dev; + BlockDriverState *drive[2]; + uint32_t base; + } fdc; + + struct { + ISADevice *dev; + uint32_t base; + } ide; + + uint8_t read_id_step; + uint8_t selected_index; + + uint8_t regs[3]; +} PC87312State; + + +#endif diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 2b3d58b852..e630aeab9d 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -282,10 +282,10 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args) } #endif -static QEMUMachine pc_machine_v1_4 = { - .name = "pc-1.4", +static QEMUMachine pc_i440fx_machine_v1_4 = { + .name = "pc-i440fx-1.4", .alias = "pc", - .desc = "Standard PC", + .desc = "Standard PC (i440FX + PIIX, 1996)", .init = pc_init_pci_1_3, .max_cpus = 255, .is_default = 1, @@ -646,7 +646,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { - qemu_register_machine(&pc_machine_v1_4); + qemu_register_machine(&pc_i440fx_machine_v1_4); qemu_register_machine(&pc_machine_v1_3); qemu_register_machine(&pc_machine_v1_2); qemu_register_machine(&pc_machine_v1_1); diff --git a/hw/pc_q35.c b/hw/pc_q35.c index ef540b6a71..52d997613f 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -209,9 +209,9 @@ static void pc_q35_init(QEMUMachineInitArgs *args) } static QEMUMachine pc_q35_machine = { - .name = "q35-next", + .name = "pc-q35-1.4", .alias = "q35", - .desc = "Q35 chipset PC", + .desc = "Standard PC (Q35 + ICH9, 2009)", .init = pc_q35_init, .max_cpus = 255, }; diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index 7567593a63..7f6c12c8a8 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -256,7 +256,7 @@ static void pcsysfw_class_init (ObjectClass *klass, void *data) dc->props = pcsysfw_properties; } -static TypeInfo pcsysfw_info = { +static const TypeInfo pcsysfw_info = { .name = "pc-sysfw", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof (PcSysFwDevice), diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 94840c4af7..5fd1bcf08e 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2150,7 +2150,7 @@ void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) bus->dma_context_opaque = opaque; } -static TypeInfo pci_device_type_info = { +static const TypeInfo pci_device_type_info = { .name = TYPE_PCI_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(PCIDevice), diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 2dd312db35..1124c53b8c 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -152,7 +152,7 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) dc->vmsd = &pci_bridge_dev_vmstate; } -static TypeInfo pci_bridge_dev_info = { +static const TypeInfo pci_bridge_dev_info = { .name = "pci-bridge", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBridgeDev), diff --git a/hw/pckbd.c b/hw/pckbd.c index 6db7bbcc06..3bad09baf2 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -512,7 +512,7 @@ static void i8042_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_kbd_isa; } -static TypeInfo i8042_info = { +static const TypeInfo i8042_info = { .name = "i8042", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAKBDState), diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 40a0e6eda4..a94f642136 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -361,7 +361,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data) dc->props = pcnet_properties; } -static TypeInfo pcnet_info = { +static const TypeInfo pcnet_info = { .name = "pcnet", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIPCNetState), diff --git a/hw/pcspk.c b/hw/pcspk.c index 6d55ebe82f..dfab9559ae 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -187,7 +187,7 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data) dc->props = pcspk_properties; } -static TypeInfo pcspk_info = { +static const TypeInfo pcspk_info = { .name = "isa-pcspk", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PCSpkState), diff --git a/hw/piix4.c b/hw/piix4.c index 799ed1729c..c1cb94d39f 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -117,7 +117,7 @@ static void piix4_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_piix4; } -static TypeInfo piix4_info = { +static const TypeInfo piix4_info = { .name = "PIIX4", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX4State), diff --git a/hw/pl011.c b/hw/pl011.c index 35835f36c0..002a50e16a 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -300,7 +300,7 @@ static void pl011_arm_class_init(ObjectClass *klass, void *data) sdc->init = pl011_arm_init; } -static TypeInfo pl011_arm_info = { +static const TypeInfo pl011_arm_info = { .name = "pl011", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl011_state), @@ -314,7 +314,7 @@ static void pl011_luminary_class_init(ObjectClass *klass, void *data) sdc->init = pl011_luminary_init; } -static TypeInfo pl011_luminary_info = { +static const TypeInfo pl011_luminary_info = { .name = "pl011_luminary", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl011_state), diff --git a/hw/pl022.c b/hw/pl022.c index fbd7ded0cf..c160e9061c 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -293,7 +293,7 @@ static void pl022_class_init(ObjectClass *klass, void *data) sdc->init = pl022_init; } -static TypeInfo pl022_info = { +static const TypeInfo pl022_info = { .name = "pl022", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl022_state), diff --git a/hw/pl031.c b/hw/pl031.c index 3a23ecde48..757867ff79 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -250,7 +250,7 @@ static void pl031_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl031; } -static TypeInfo pl031_info = { +static const TypeInfo pl031_info = { .name = "pl031", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl031_state), diff --git a/hw/pl041.c b/hw/pl041.c index 4436d97c50..0b71c45748 100644 --- a/hw/pl041.c +++ b/hw/pl041.c @@ -632,7 +632,7 @@ static void pl041_device_class_init(ObjectClass *klass, void *data) dc->props = pl041_device_properties; } -static TypeInfo pl041_device_info = { +static const TypeInfo pl041_device_info = { .name = "pl041", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl041_state), diff --git a/hw/pl050.c b/hw/pl050.c index 47032f1260..5d06bc9a3f 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -168,7 +168,7 @@ static void pl050_kbd_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl050; } -static TypeInfo pl050_kbd_info = { +static const TypeInfo pl050_kbd_info = { .name = "pl050_keyboard", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl050_state), @@ -184,7 +184,7 @@ static void pl050_mouse_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl050; } -static TypeInfo pl050_mouse_info = { +static const TypeInfo pl050_mouse_info = { .name = "pl050_mouse", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl050_state), diff --git a/hw/pl061.c b/hw/pl061.c index f1ed5ced1d..a78e819d96 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -304,7 +304,7 @@ static void pl061_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl061; } -static TypeInfo pl061_info = { +static const TypeInfo pl061_info = { .name = "pl061", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl061_state), @@ -320,7 +320,7 @@ static void pl061_luminary_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl061; } -static TypeInfo pl061_luminary_info = { +static const TypeInfo pl061_luminary_info = { .name = "pl061_luminary", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl061_state), diff --git a/hw/pl080.c b/hw/pl080.c index 26150af757..f6bbf98a7e 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -386,7 +386,7 @@ static void pl080_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl080; } -static TypeInfo pl080_info = { +static const TypeInfo pl080_info = { .name = "pl080", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl080_state), @@ -403,7 +403,7 @@ static void pl081_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl080; } -static TypeInfo pl081_info = { +static const TypeInfo pl081_info = { .name = "pl081", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl080_state), diff --git a/hw/pl110.c b/hw/pl110.c index 098e335aea..3d0ac00ade 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -480,7 +480,7 @@ static void pl110_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl110; } -static TypeInfo pl110_info = { +static const TypeInfo pl110_info = { .name = "pl110", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl110_state), @@ -497,7 +497,7 @@ static void pl110_versatile_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl110; } -static TypeInfo pl110_versatile_info = { +static const TypeInfo pl110_versatile_info = { .name = "pl110_versatile", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl110_state), @@ -514,7 +514,7 @@ static void pl111_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl110; } -static TypeInfo pl111_info = { +static const TypeInfo pl111_info = { .name = "pl111", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl110_state), diff --git a/hw/pl181.c b/hw/pl181.c index cbddb741ce..98529f7821 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -500,7 +500,7 @@ static void pl181_class_init(ObjectClass *klass, void *data) k->no_user = 1; } -static TypeInfo pl181_info = { +static const TypeInfo pl181_info = { .name = "pl181", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl181_state), diff --git a/hw/pl190.c b/hw/pl190.c index 40199302a9..76ac159374 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -274,7 +274,7 @@ static void pl190_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl190; } -static TypeInfo pl190_info = { +static const TypeInfo pl190_info = { .name = "pl190", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl190_state), diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index b262f31e5a..3a9e1c7b43 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -225,6 +225,10 @@ static int ppce500_load_device_tree(CPUPPCState *env, kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", hypercall, sizeof(hypercall)); + /* if KVM supports the idle hcall, set property indicating this */ + if (kvmppc_get_hasidle(env)) { + qemu_devtree_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); + } } /* Create CPU nodes */ @@ -493,8 +497,8 @@ void ppce500_init(PPCE500Params *params) irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; - env->mpic_cpu_base = MPC8544_CCSRBAR_BASE + - MPC8544_MPIC_REGS_OFFSET + 0x20000; + env->mpic_iack = MPC8544_CCSRBAR_BASE + + MPC8544_MPIC_REGS_OFFSET + 0x200A0; ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index 4483b8d292..25a4e91b69 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -237,6 +237,17 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) } +static void ppc_booke_timer_reset_handle(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + env->spr[SPR_BOOKE_TSR] = 0; + env->spr[SPR_BOOKE_TCR] = 0; + + booke_update_irq(cpu); +} + void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) { ppc_tb_t *tb_env; @@ -257,4 +268,6 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); booke_timer->wdt_timer = qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); + + qemu_register_reset(ppc_booke_timer_reset_handle, cpu); } diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 9c78c863e8..417583a96d 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -37,6 +37,7 @@ #include "ide.h" #include "loader.h" #include "mc146818rtc.h" +#include "pc87312.h" #include "sysemu/blockdev.h" #include "sysemu/arch_init.h" #include "exec/address-spaces.h" @@ -181,7 +182,6 @@ typedef struct sysctrl_t { M48t59State *nvram; uint8_t state; uint8_t syscontrol; - uint8_t fake_io[2]; int contiguous_map; int endian; } sysctrl_t; @@ -192,24 +192,6 @@ enum { static sysctrl_t *sysctrl; -static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) -{ - sysctrl_t *sysctrl = opaque; - - PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, - val); - sysctrl->fake_io[addr - 0x0398] = val; -} - -static uint32_t PREP_io_read (void *opaque, uint32_t addr) -{ - sysctrl_t *sysctrl = opaque; - - PPC_IO_DPRINTF("0x%08" PRIx32 " <= 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, - sysctrl->fake_io[addr - 0x0398]); - return sysctrl->fake_io[addr - 0x0398]; -} - static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) { sysctrl_t *sysctrl = opaque; @@ -476,10 +458,10 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) PCIBus *pci_bus; PCIDevice *pci; ISABus *isa_bus; + ISADevice *isa; qemu_irq *cpu_exit_irq; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DriveInfo *fd[MAX_FD]; sysctrl = g_malloc0(sizeof(sysctrl_t)); @@ -606,6 +588,11 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) sysbus_connect_irq(&pcihost->busdev, 3, qdev_get_gpio_in(&pci->qdev, 11)); isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&pci->qdev, "isa.0")); + /* Super I/O (parallel + serial ports) */ + isa = isa_create(isa_bus, TYPE_PC87312); + qdev_prop_set_uint8(&isa->qdev, "config", 13); /* fdc, ser0, ser1, par0 */ + qdev_init_nofail(&isa->qdev); + /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl, "ppc-io", 0x00800000); @@ -614,8 +601,6 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) /* init basic PC hardware */ pci_vga_init(pci_bus); - if (serial_hds[0]) - serial_isa_init(isa_bus, 0, serial_hds[0]); nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; @@ -639,17 +624,7 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) } isa_create_simple(isa_bus, "i8042"); - // SB16_init(); - - for(i = 0; i < MAX_FD; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - } - fdctrl_init_isa(isa_bus, fd); - - /* Register fake IO ports for PREP */ sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET]; - register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl); - register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl); /* System control ports */ register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl); register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl); diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 177aa2d122..1b2c34f92c 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -212,7 +212,7 @@ static void ppce500_spin_class_init(ObjectClass *klass, void *data) k->init = ppce500_spin_initfn; } -static TypeInfo ppce500_spin_info = { +static const TypeInfo ppce500_spin_info = { .name = "e500-spin", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SpinState), diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 3c51bc82aa..f3dffef5ab 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1194,7 +1194,7 @@ static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pxa2xx_rtc_regs; } -static TypeInfo pxa2xx_rtc_sysbus_info = { +static const TypeInfo pxa2xx_rtc_sysbus_info = { .name = "pxa2xx_rtc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxRTCState), @@ -1442,7 +1442,7 @@ static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data) k->send = pxa2xx_i2c_tx; } -static TypeInfo pxa2xx_i2c_slave_info = { +static const TypeInfo pxa2xx_i2c_slave_info = { .name = "pxa2xx-i2c-slave", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(PXA2xxI2CSlaveState), @@ -1510,7 +1510,7 @@ static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data) dc->props = pxa2xx_i2c_properties; } -static TypeInfo pxa2xx_i2c_info = { +static const TypeInfo pxa2xx_i2c_info = { .name = "pxa2xx_i2c", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxI2CState), @@ -2273,7 +2273,7 @@ static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) sdc->init = pxa2xx_ssp_init; } -static TypeInfo pxa2xx_ssp_info = { +static const TypeInfo pxa2xx_ssp_info = { .name = "pxa2xx-ssp", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxSSPState), diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index dbea1d2098..693b1c23d9 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -559,7 +559,7 @@ static void pxa2xx_dma_class_init(ObjectClass *klass, void *data) dc->props = pxa2xx_dma_properties; } -static TypeInfo pxa2xx_dma_info = { +static const TypeInfo pxa2xx_dma_info = { .name = "pxa2xx-dma", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxDMAState), diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 7aaf4092df..016833dfa1 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -334,7 +334,7 @@ static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data) dc->props = pxa2xx_gpio_properties; } -static TypeInfo pxa2xx_gpio_info = { +static const TypeInfo pxa2xx_gpio_info = { .name = "pxa2xx-gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxGPIOInfo), diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index 70b2b79d07..138245b0f9 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -319,7 +319,7 @@ static void pxa2xx_pic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pxa2xx_pic_regs; } -static TypeInfo pxa2xx_pic_info = { +static const TypeInfo pxa2xx_pic_info = { .name = "pxa2xx_pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxPICState), diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index e4ffb15bb2..32c1872680 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -495,7 +495,7 @@ static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) dc->props = pxa25x_timer_dev_properties; } -static TypeInfo pxa25x_timer_dev_info = { +static const TypeInfo pxa25x_timer_dev_info = { .name = "pxa25x-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxTimerInfo), @@ -520,7 +520,7 @@ static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) dc->props = pxa27x_timer_dev_properties; } -static TypeInfo pxa27x_timer_dev_info = { +static const TypeInfo pxa27x_timer_dev_info = { .name = "pxa27x-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxTimerInfo), diff --git a/hw/qdev-core.h b/hw/qdev-core.h index fdf14ec4a6..853bd08a1f 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -182,6 +182,18 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, qbus_walkerfn *busfn, void *opaque); void qdev_reset_all(DeviceState *dev); + +/** + * @qbus_reset_all: + * @bus: Bus to be reset. + * + * Reset @bus and perform a bus-level ("hard") reset of all devices connected + * to it, including recursive processing of all buses below @bus itself. A + * hard reset means that qbus_reset_all will reset all state of the device. + * For PCI devices, for example, this will include the base address registers + * or configuration space. + */ +void qbus_reset_all(BusState *bus); void qbus_reset_all_fn(void *opaque); void qbus_free(BusState *bus); diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index b73986759b..93283ee57a 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -615,3 +615,54 @@ void qdev_machine_init(void) qdev_get_peripheral_anon(); qdev_get_peripheral(); } + +QemuOptsList qemu_device_opts = { + .name = "device", + .implied_opt_name = "driver", + .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head), + .desc = { + /* + * no elements => accept any + * sanity checking will happen later + * when setting device properties + */ + { /* end of list */ } + }, +}; + +QemuOptsList qemu_global_opts = { + .name = "global", + .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head), + .desc = { + { + .name = "driver", + .type = QEMU_OPT_STRING, + },{ + .name = "property", + .type = QEMU_OPT_STRING, + },{ + .name = "value", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +int qemu_global_option(const char *str) +{ + char driver[64], property[64]; + QemuOpts *opts; + int rc, offset; + + rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); + if (rc < 2 || str[offset] != '=') { + error_report("can't parse: \"%s\"", str); + return -1; + } + + opts = qemu_opts_create_nofail(&qemu_global_opts); + qemu_opt_set(opts, "driver", driver); + qemu_opt_set(opts, "property", property); + qemu_opt_set(opts, "value", str+offset+1); + return 0; +} @@ -228,10 +228,15 @@ void qdev_reset_all(DeviceState *dev) qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL); } +void qbus_reset_all(BusState *bus) +{ + qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL); +} + void qbus_reset_all_fn(void *opaque) { BusState *bus = opaque; - qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL); + qbus_reset_all(bus); } /* can be used as ->unplug() callback for the simple cases */ @@ -698,16 +703,18 @@ static void device_class_base_init(ObjectClass *class, void *data) klass->props = NULL; } -static void qdev_remove_from_bus(Object *obj) +static void device_unparent(Object *obj) { DeviceState *dev = DEVICE(obj); - bus_remove_child(dev->parent_bus, dev); + if (dev->parent_bus != NULL) { + bus_remove_child(dev->parent_bus, dev); + } } static void device_class_init(ObjectClass *class, void *data) { - class->unparent = qdev_remove_from_bus; + class->unparent = device_unparent; } void device_reset(DeviceState *dev) @@ -730,7 +737,7 @@ Object *qdev_get_machine(void) return dev; } -static TypeInfo device_type_info = { +static const TypeInfo device_type_info = { .name = TYPE_DEVICE, .parent = TYPE_OBJECT, .instance_size = sizeof(DeviceState), @@ -2310,7 +2310,7 @@ static void qxl_primary_class_init(ObjectClass *klass, void *data) dc->props = qxl_properties; } -static TypeInfo qxl_primary_info = { +static const TypeInfo qxl_primary_info = { .name = "qxl-vga", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIQXLDevice), @@ -2332,7 +2332,7 @@ static void qxl_secondary_class_init(ObjectClass *klass, void *data) dc->props = qxl_properties; } -static TypeInfo qxl_secondary_info = { +static const TypeInfo qxl_secondary_info = { .name = "qxl", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIQXLDevice), diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 5bc37a7120..b1b74d8e9c 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -59,7 +59,7 @@ static void realview_gic_class_init(ObjectClass *klass, void *data) sdc->init = realview_gic_init; } -static TypeInfo realview_gic_info = { +static const TypeInfo realview_gic_info = { .name = "realview_gic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RealViewGICState), diff --git a/hw/rtl8139.c b/hw/rtl8139.c index c59ec6b6df..cfbf3f47c1 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -1258,7 +1258,8 @@ static void rtl8139_reset(DeviceState *d) s->BasicModeStatus = 0x7809; //s->BasicModeStatus |= 0x0040; /* UTP medium */ s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ - s->BasicModeStatus |= 0x0004; /* link is up */ + /* preserve link state */ + s->BasicModeStatus |= s->nic->nc.link_down ? 0 : 0x04; s->NWayAdvert = 0x05e1; /* all modes, full duplex */ s->NWayLPAR = 0x05e1; /* all modes, full duplex */ @@ -3539,7 +3540,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) dc->props = rtl8139_properties; } -static TypeInfo rtl8139_info = { +static const TypeInfo rtl8139_info = { .name = "rtl8139", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(RTL8139State), diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 7e991755b4..bcb09f202e 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -419,7 +419,7 @@ static void s390_virtio_net_class_init(ObjectClass *klass, void *data) dc->props = s390_virtio_net_properties; } -static TypeInfo s390_virtio_net = { +static const TypeInfo s390_virtio_net = { .name = "virtio-net-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -445,7 +445,7 @@ static void s390_virtio_blk_class_init(ObjectClass *klass, void *data) dc->props = s390_virtio_blk_properties; } -static TypeInfo s390_virtio_blk = { +static const TypeInfo s390_virtio_blk = { .name = "virtio-blk-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -467,7 +467,7 @@ static void s390_virtio_serial_class_init(ObjectClass *klass, void *data) dc->props = s390_virtio_serial_properties; } -static TypeInfo s390_virtio_serial = { +static const TypeInfo s390_virtio_serial = { .name = "virtio-serial-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -489,7 +489,7 @@ static void s390_virtio_rng_class_init(ObjectClass *klass, void *data) k->init = s390_virtio_rng_init; } -static TypeInfo s390_virtio_rng = { +static const TypeInfo s390_virtio_rng = { .name = "virtio-rng-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -514,7 +514,7 @@ static void virtio_s390_device_class_init(ObjectClass *klass, void *data) dc->unplug = qdev_simple_unplug_cb; } -static TypeInfo virtio_s390_device_info = { +static const TypeInfo virtio_s390_device_info = { .name = TYPE_VIRTIO_S390_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -537,7 +537,7 @@ static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data) dc->props = s390_virtio_scsi_properties; } -static TypeInfo s390_virtio_scsi = { +static const TypeInfo s390_virtio_scsi = { .name = "virtio-scsi-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -562,7 +562,7 @@ static void s390_virtio_bridge_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo s390_virtio_bridge_info = { +static const TypeInfo s390_virtio_bridge_info = { .name = "s390-virtio-bridge", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusDevice), diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 89b1b66bd2..6b56995189 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -345,7 +345,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data) k->init = init_event_facility; } -static TypeInfo s390_sclp_event_facility_info = { +static const TypeInfo s390_sclp_event_facility_info = { .name = "s390-sclp-event-facility", .parent = TYPE_DEVICE_S390_SCLP, .instance_size = sizeof(S390SCLPDevice), @@ -380,7 +380,7 @@ static void event_class_init(ObjectClass *klass, void *data) dc->exit = event_qdev_exit; } -static TypeInfo s390_sclp_event_type_info = { +static const TypeInfo s390_sclp_event_type_info = { .name = TYPE_SCLP_EVENT, .parent = TYPE_DEVICE, .instance_size = sizeof(SCLPEvent), diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 7ad791d5e3..a9d3a6a91d 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -146,7 +146,7 @@ static void s390_sclp_device_class_init(ObjectClass *klass, void *data) dc->init = s390_sclp_dev_init; } -static TypeInfo s390_sclp_device_info = { +static const TypeInfo s390_sclp_device_info = { .name = TYPE_DEVICE_S390_SCLP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(S390SCLPDevice), diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c index aa70e16665..adc0ee83f4 100644 --- a/hw/s390x/sclpconsole.c +++ b/hw/s390x/sclpconsole.c @@ -291,7 +291,7 @@ static void console_class_init(ObjectClass *klass, void *data) ec->write_event_data = write_event_data; } -static TypeInfo sclp_console_info = { +static const TypeInfo sclp_console_info = { .name = "sclpconsole", .parent = TYPE_SCLP_EVENT, .instance_size = sizeof(SCLPConsole), diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 6e6f5624df..2538498959 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -107,7 +107,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data) k->write_event_data = NULL; } -static TypeInfo sclp_quiesce_info = { +static const TypeInfo sclp_quiesce_info = { .name = "sclpquiesce", .parent = TYPE_SCLP_EVENT, .instance_size = sizeof(SCLPEvent), @@ -1409,7 +1409,7 @@ static void sb16_class_initfn (ObjectClass *klass, void *data) dc->props = sb16_properties; } -static TypeInfo sb16_info = { +static const TypeInfo sb16_info = { .name = "sb16", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof (SB16State), @@ -141,7 +141,7 @@ static void sbi_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_sbi; } -static TypeInfo sbi_info = { +static const TypeInfo sbi_info = { .name = "sbi", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SBIState), diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 970c1fc01b..267a942f76 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1863,7 +1863,7 @@ static void scsi_device_class_init(ObjectClass *klass, void *data) k->props = scsi_props; } -static TypeInfo scsi_device_type_info = { +static const TypeInfo scsi_device_type_info = { .name = TYPE_SCSI_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(SCSIDevice), diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a69735b0a6..f8d7ef3374 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -2389,7 +2389,7 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_disk_state; } -static TypeInfo scsi_hd_info = { +static const TypeInfo scsi_hd_info = { .name = "scsi-hd", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDiskState), @@ -2418,7 +2418,7 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_disk_state; } -static TypeInfo scsi_cd_info = { +static const TypeInfo scsi_cd_info = { .name = "scsi-cd", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDiskState), @@ -2447,7 +2447,7 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_disk_state; } -static TypeInfo scsi_block_info = { +static const TypeInfo scsi_block_info = { .name = "scsi-block", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDiskState), @@ -2481,7 +2481,7 @@ static void scsi_disk_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_disk_state; } -static TypeInfo scsi_disk_info = { +static const TypeInfo scsi_disk_info = { .name = "scsi-disk", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDiskState), diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 4c702be19f..8175474a67 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -499,7 +499,7 @@ static void scsi_generic_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_device; } -static TypeInfo scsi_generic_info = { +static const TypeInfo scsi_generic_info = { .name = "scsi-generic", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDevice), diff --git a/hw/serial-isa.c b/hw/serial-isa.c index 96c78f7f8d..5a6f51f856 100644 --- a/hw/serial-isa.c +++ b/hw/serial-isa.c @@ -99,7 +99,7 @@ static void serial_isa_class_initfn(ObjectClass *klass, void *data) dc->props = serial_isa_properties; } -static TypeInfo serial_isa_info = { +static const TypeInfo serial_isa_info = { .name = "isa-serial", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISASerialState), diff --git a/hw/serial-pci.c b/hw/serial-pci.c index 50e8ab7faf..1c31353f6d 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -221,21 +221,21 @@ static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) dc->props = multi_4x_serial_pci_properties; } -static TypeInfo serial_pci_info = { +static const TypeInfo serial_pci_info = { .name = "pci-serial", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCISerialState), .class_init = serial_pci_class_initfn, }; -static TypeInfo multi_2x_serial_pci_info = { +static const TypeInfo multi_2x_serial_pci_info = { .name = "pci-serial-2x", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIMultiSerialState), .class_init = multi_2x_serial_pci_class_initfn, }; -static TypeInfo multi_4x_serial_pci_info = { +static const TypeInfo multi_4x_serial_pci_info = { .name = "pci-serial-4x", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIMultiSerialState), @@ -48,7 +48,7 @@ static void sga_class_initfn(ObjectClass *klass, void *data) dc->desc = "Serial Graphics Adapter"; } -static TypeInfo sga_info = { +static const TypeInfo sga_info = { .name = "sga", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISASGAState), diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 018b1c198b..077d957003 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -156,7 +156,7 @@ static void sh_pci_host_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R; } -static TypeInfo sh_pci_host_info = { +static const TypeInfo sh_pci_host_info = { .name = "sh_pci_host", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -170,7 +170,7 @@ static void sh_pci_device_class_init(ObjectClass *klass, void *data) sdc->init = sh_pci_device_init; } -static TypeInfo sh_pci_device_info = { +static const TypeInfo sh_pci_device_info = { .name = "sh_pci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SHPCIState), diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index a44ce95c1f..d67c8ccc9f 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -456,7 +456,7 @@ static void slavio_intctl_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_intctl; } -static TypeInfo slavio_intctl_info = { +static const TypeInfo slavio_intctl_info = { .name = "slavio_intctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLAVIO_INTCTLState), diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 704f2b173b..af24cc1ae8 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -478,7 +478,7 @@ static void slavio_misc_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_misc; } -static TypeInfo slavio_misc_info = { +static const TypeInfo slavio_misc_info = { .name = "slavio_misc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MiscState), @@ -492,7 +492,7 @@ static void apc_class_init(ObjectClass *klass, void *data) k->init = apc_init1; } -static TypeInfo apc_info = { +static const TypeInfo apc_info = { .name = "apc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MiscState), diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 584629f1a5..68a4c0cca4 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -420,7 +420,7 @@ static void slavio_timer_class_init(ObjectClass *klass, void *data) dc->props = slavio_timer_properties; } -static TypeInfo slavio_timer_info = { +static const TypeInfo slavio_timer_info = { .name = "slavio_timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLAVIO_TIMERState), diff --git a/hw/smbus.c b/hw/smbus.c index e3cf6a2cc8..a908591590 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -318,7 +318,7 @@ static void smbus_device_class_init(ObjectClass *klass, void *data) sc->send = smbus_i2c_send; } -static TypeInfo smbus_device_type_info = { +static const TypeInfo smbus_device_type_info = { .name = TYPE_SMBUS_DEVICE, .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(SMBusDevice), diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 11adab01b8..d36dc7bbe3 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -123,7 +123,7 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data) dc->props = smbus_eeprom_properties; } -static TypeInfo smbus_eeprom_info = { +static const TypeInfo smbus_eeprom_info = { .name = "smbus-eeprom", .parent = TYPE_SMBUS_DEVICE, .instance_size = sizeof(SMBusEEPROMDevice), diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 2161b4af7a..a34698f9e3 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -774,7 +774,7 @@ static void smc91c111_class_init(ObjectClass *klass, void *data) dc->props = smc91c111_properties; } -static TypeInfo smc91c111_info = { +static const TypeInfo smc91c111_info = { .name = "smc91c111", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(smc91c111_state), diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 8077eb94bc..db34b485aa 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -502,7 +502,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) k->rtce_window_size = 0x10000000; } -static TypeInfo spapr_vlan_info = { +static const TypeInfo spapr_vlan_info = { .name = "spapr-vlan", .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VIOsPAPRVLANDevice), diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index a58621d17e..3a1a4864e6 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -536,7 +536,7 @@ static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo spapr_vio_bridge_info = { +static const TypeInfo spapr_vio_bridge_info = { .name = "spapr-vio-bridge", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusDevice), @@ -552,7 +552,7 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data) k->props = spapr_vio_props; } -static TypeInfo spapr_vio_type_info = { +static const TypeInfo spapr_vio_type_info = { .name = TYPE_VIO_SPAPR_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(VIOsPAPRDevice), diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 2d811320ca..7fc0e13f9f 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -967,7 +967,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) k->rtce_window_size = 0x10000000; } -static TypeInfo spapr_vscsi_info = { +static const TypeInfo spapr_vscsi_info = { .name = "spapr-vscsi", .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VSCSIState), diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index ec81a7e6e8..5c63eaafa9 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -150,7 +150,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data) dc->props = spapr_vty_properties; } -static TypeInfo spapr_vty_info = { +static const TypeInfo spapr_vty_info = { .name = "spapr-vty", .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VIOsPAPRVTYDevice), diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index d11a302f20..6d0df51749 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -300,7 +300,7 @@ static void sparc32_dma_class_init(ObjectClass *klass, void *data) dc->props = sparc32_dma_properties; } -static TypeInfo sparc32_dma_info = { +static const TypeInfo sparc32_dma_info = { .name = "sparc32_dma", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(DMAState), diff --git a/hw/spitz.c b/hw/spitz.c index 8e1be7fb21..f1659c4502 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1022,7 +1022,7 @@ static void sl_nand_class_init(ObjectClass *klass, void *data) dc->props = sl_nand_properties; } -static TypeInfo sl_nand_info = { +static const TypeInfo sl_nand_info = { .name = "sl-nand", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLNANDState), @@ -1057,7 +1057,7 @@ static void spitz_keyboard_class_init(ObjectClass *klass, void *data) dc->props = spitz_keyboard_properties; } -static TypeInfo spitz_keyboard_info = { +static const TypeInfo spitz_keyboard_info = { .name = "spitz-keyboard", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SpitzKeyboardState), @@ -1086,7 +1086,7 @@ static void corgi_ssp_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_corgi_ssp_regs; } -static TypeInfo corgi_ssp_info = { +static const TypeInfo corgi_ssp_info = { .name = "corgi-ssp", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(CorgiSSPState), @@ -1116,7 +1116,7 @@ static void spitz_lcdtg_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_spitz_lcdtg_regs; } -static TypeInfo spitz_lcdtg_info = { +static const TypeInfo spitz_lcdtg_info = { .name = "spitz-lcdtg", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(SpitzLCDTG), diff --git a/hw/ssd0303.c b/hw/ssd0303.c index cbdf49af57..8777b1681a 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -306,7 +306,7 @@ static void ssd0303_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_ssd0303; } -static TypeInfo ssd0303_info = { +static const TypeInfo ssd0303_info = { .name = "ssd0303", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(ssd0303_state), diff --git a/hw/ssd0323.c b/hw/ssd0323.c index fe6f801ae7..84c86a5244 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -357,7 +357,7 @@ static void ssd0323_class_init(ObjectClass *klass, void *data) k->cs_polarity = SSI_CS_HIGH; } -static TypeInfo ssd0323_info = { +static const TypeInfo ssd0323_info = { .name = "ssd0323", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ssd0323_state), diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index d61c3328d9..dca8906e7d 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -259,7 +259,7 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data) k->cs_polarity = SSI_CS_LOW; } -static TypeInfo ssi_sd_info = { +static const TypeInfo ssi_sd_info = { .name = "ssi-sd", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ssi_sd_state), @@ -78,7 +78,7 @@ static void ssi_slave_class_init(ObjectClass *klass, void *data) } } -static TypeInfo ssi_slave_info = { +static const TypeInfo ssi_slave_info = { .name = TYPE_SSI_SLAVE, .parent = TYPE_DEVICE, .class_init = ssi_slave_class_init, diff --git a/hw/stellaris.c b/hw/stellaris.c index 26da3c7f60..12e4568534 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1354,7 +1354,7 @@ static void stellaris_i2c_class_init(ObjectClass *klass, void *data) sdc->init = stellaris_i2c_init; } -static TypeInfo stellaris_i2c_info = { +static const TypeInfo stellaris_i2c_info = { .name = "stellaris-i2c", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_i2c_state), @@ -1368,7 +1368,7 @@ static void stellaris_gptm_class_init(ObjectClass *klass, void *data) sdc->init = stellaris_gptm_init; } -static TypeInfo stellaris_gptm_info = { +static const TypeInfo stellaris_gptm_info = { .name = "stellaris-gptm", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(gptm_state), @@ -1382,7 +1382,7 @@ static void stellaris_adc_class_init(ObjectClass *klass, void *data) sdc->init = stellaris_adc_init; } -static TypeInfo stellaris_adc_info = { +static const TypeInfo stellaris_adc_info = { .name = "stellaris-adc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_adc_state), diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index d7e1e21ff9..5e9053fa26 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -434,7 +434,7 @@ static void stellaris_enet_class_init(ObjectClass *klass, void *data) dc->props = stellaris_enet_properties; } -static TypeInfo stellaris_enet_info = { +static const TypeInfo stellaris_enet_info = { .name = "stellaris_enet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_enet_state), diff --git a/hw/stream.c b/hw/stream.c index be57e8b247..d4cf84d4c0 100644 --- a/hw/stream.c +++ b/hw/stream.c @@ -8,7 +8,7 @@ stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app) k->push(sink, buf, len, app); } -static TypeInfo stream_slave_info = { +static const TypeInfo stream_slave_info = { .name = TYPE_STREAM_SLAVE, .parent = TYPE_INTERFACE, .class_size = sizeof(StreamSlaveClass), diff --git a/hw/strongarm.c b/hw/strongarm.c index 804c1a37a6..af688ac4ca 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -212,7 +212,7 @@ static void strongarm_pic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_strongarm_pic_regs; } -static TypeInfo strongarm_pic_info = { +static const TypeInfo strongarm_pic_info = { .name = "strongarm_pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMPICState), @@ -433,7 +433,7 @@ static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_strongarm_rtc_regs; } -static TypeInfo strongarm_rtc_sysbus_info = { +static const TypeInfo strongarm_rtc_sysbus_info = { .name = "strongarm-rtc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMRTCState), @@ -674,7 +674,7 @@ static void strongarm_gpio_class_init(ObjectClass *klass, void *data) dc->desc = "StrongARM GPIO controller"; } -static TypeInfo strongarm_gpio_info = { +static const TypeInfo strongarm_gpio_info = { .name = "strongarm-gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMGPIOInfo), @@ -840,7 +840,7 @@ static void strongarm_ppc_class_init(ObjectClass *klass, void *data) dc->desc = "StrongARM PPC controller"; } -static TypeInfo strongarm_ppc_info = { +static const TypeInfo strongarm_ppc_info = { .name = "strongarm-ppc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMPPCInfo), @@ -1299,7 +1299,7 @@ static void strongarm_uart_class_init(ObjectClass *klass, void *data) dc->props = strongarm_uart_properties; } -static TypeInfo strongarm_uart_info = { +static const TypeInfo strongarm_uart_info = { .name = "strongarm-uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMUARTState), @@ -1538,7 +1538,7 @@ static void strongarm_ssp_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_strongarm_ssp_regs; } -static TypeInfo strongarm_ssp_info = { +static const TypeInfo strongarm_ssp_info = { .name = "strongarm-ssp", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMSSPState), diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c index b78d54f232..f8f4d023a3 100644 --- a/hw/sun4c_intctl.c +++ b/hw/sun4c_intctl.c @@ -193,7 +193,7 @@ static void sun4c_intctl_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_sun4c_intctl; } -static TypeInfo sun4c_intctl_info = { +static const TypeInfo sun4c_intctl_info = { .name = "sun4c_intctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Sun4c_INTCTLState), diff --git a/hw/sun4m.c b/hw/sun4m.c index 0d84b373b1..5925d292c3 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -633,7 +633,7 @@ static void idreg_class_init(ObjectClass *klass, void *data) k->init = idreg_init1; } -static TypeInfo idreg_info = { +static const TypeInfo idreg_info = { .name = "macio_idreg", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IDRegState), @@ -675,7 +675,7 @@ static void afx_class_init(ObjectClass *klass, void *data) k->init = afx_init1; } -static TypeInfo afx_info = { +static const TypeInfo afx_info = { .name = "tcx_afx", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(AFXState), @@ -752,7 +752,7 @@ static void prom_class_init(ObjectClass *klass, void *data) dc->props = prom_properties; } -static TypeInfo prom_info = { +static const TypeInfo prom_info = { .name = "openprom", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PROMState), @@ -816,7 +816,7 @@ static void ram_class_init(ObjectClass *klass, void *data) dc->props = ram_properties; } -static TypeInfo ram_info = { +static const TypeInfo ram_info = { .name = "memory", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RamDevice), diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c index ce6819e10b..8f9635f343 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -373,7 +373,7 @@ static void iommu_class_init(ObjectClass *klass, void *data) dc->props = iommu_properties; } -static TypeInfo iommu_info = { +static const TypeInfo iommu_info = { .name = "iommu", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IOMMUState), diff --git a/hw/sun4u.c b/hw/sun4u.c index cbfd217587..3a06d70795 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -618,7 +618,7 @@ static void ebus_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_OTHER; } -static TypeInfo ebus_info = { +static const TypeInfo ebus_info = { .name = "ebus", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(EbusState), @@ -695,7 +695,7 @@ static void prom_class_init(ObjectClass *klass, void *data) dc->props = prom_properties; } -static TypeInfo prom_info = { +static const TypeInfo prom_info = { .name = "openprom", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PROMState), @@ -752,7 +752,7 @@ static void ram_class_init(ObjectClass *klass, void *data) dc->props = ram_properties; } -static TypeInfo ram_info = { +static const TypeInfo ram_info = { .name = "memory", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RamDevice), diff --git a/hw/sysbus.c b/hw/sysbus.c index 49a41775f8..f0ab8a859a 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -255,7 +255,7 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data) k->bus_type = TYPE_SYSTEM_BUS; } -static TypeInfo sysbus_device_type_info = { +static const TypeInfo sysbus_device_type_info = { .name = TYPE_SYS_BUS_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(SysBusDevice), @@ -716,7 +716,7 @@ static void tcx_class_init(ObjectClass *klass, void *data) dc->props = tcx_properties; } -static TypeInfo tcx_info = { +static const TypeInfo tcx_info = { .name = "SUNW,tcx", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(TCXState), diff --git a/hw/tmp105.c b/hw/tmp105.c index 9c67e644dd..0ade4eb6bd 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -239,7 +239,7 @@ static void tmp105_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_tmp105; } -static TypeInfo tmp105_info = { +static const TypeInfo tmp105_info = { .name = "tmp105", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(TMP105State), @@ -270,7 +270,7 @@ static void tosa_dac_class_init(ObjectClass *klass, void *data) k->send = tosa_dac_send; } -static TypeInfo tosa_dac_info = { +static const TypeInfo tosa_dac_info = { .name = "tosa_dac", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(TosaDACState), @@ -285,7 +285,7 @@ static void tosa_ssp_class_init(ObjectClass *klass, void *data) k->transfer = tosa_ssp_tansfer; } -static TypeInfo tosa_ssp_info = { +static const TypeInfo tosa_ssp_info = { .name = "tosa-ssp", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(SSISlave), diff --git a/hw/tusb6010.c b/hw/tusb6010.c index 990d50619d..7d05b31024 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -798,7 +798,7 @@ static void tusb6010_class_init(ObjectClass *klass, void *data) dc->reset = tusb6010_reset; } -static TypeInfo tusb6010_info = { +static const TypeInfo tusb6010_info = { .name = "tusb6010", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(TUSBState), diff --git a/hw/twl92230.c b/hw/twl92230.c index c71e4a2af0..70d9b03e55 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -867,7 +867,7 @@ static void twl92230_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_menelaus; } -static TypeInfo twl92230_info = { +static const TypeInfo twl92230_info = { .name = "twl92230", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(MenelausState), @@ -307,6 +307,12 @@ typedef struct USBDeviceClass { */ void (*flush_ep_queue)(USBDevice *dev, USBEndpoint *ep); + /* + * Called by the hcd to let the device know the queue for an endpoint + * has been unlinked / stopped. Optional may be NULL. + */ + void (*ep_stopped)(USBDevice *dev, USBEndpoint *ep); + const char *product_desc; const USBDesc *usb_desc; } USBDeviceClass; @@ -539,11 +545,23 @@ void usb_device_set_interface(USBDevice *dev, int interface, void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep); +void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep); + const char *usb_device_get_product_desc(USBDevice *dev); const USBDesc *usb_device_get_usb_desc(USBDevice *dev); int ehci_create_ich9_with_companions(PCIBus *bus, int slot); -#endif +/* quirks.c */ + +/* In bulk endpoints are streaming data sources (iow behave like isoc eps) */ +#define USB_QUIRK_BUFFER_BULK_IN 0x01 +/* Bulk pkts in FTDI format, need special handling when combining packets */ +#define USB_QUIRK_IS_FTDI 0x02 +int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol); + +#endif diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 5a4eeb6d13..d1bbbc06e7 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -4,11 +4,11 @@ common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o common-obj-y += libhw.o -common-obj-$(CONFIG_SMARTCARD) += dev-smartcard-reader.o -common-obj-$(CONFIG_USB_REDIR) += redirect.o +common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o common-obj-y += host-$(HOST_USB).o dev-bluetooth.o common-obj-y += dev-hid.o dev-storage.o dev-wacom.o common-obj-y += dev-serial.o dev-network.o dev-audio.o +common-obj-y += dev-smartcard-reader.o common-obj-y += dev-uas.o diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 10260a13ac..2dc76756a0 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -189,6 +189,14 @@ void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) } } +void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->ep_stopped) { + klass->ep_stopped(dev, ep); + } +} + static int usb_qdev_init(DeviceState *qdev) { USBDevice *dev = USB_DEVICE(qdev); @@ -620,7 +628,7 @@ static void usb_device_class_init(ObjectClass *klass, void *data) k->props = usb_props; } -static TypeInfo usb_device_type_info = { +static const TypeInfo usb_device_type_info = { .name = TYPE_USB_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(USBDevice), diff --git a/hw/usb/core.c b/hw/usb/core.c index e315fc1021..d057aab900 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -761,7 +761,7 @@ USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); USBPacket *p; - while ((p = QTAILQ_FIRST(&uep->queue)) != NULL) { + QTAILQ_FOREACH(p, &uep->queue, queue) { if (p->id == id) { return p; } diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index b669601c92..b8c79b85e9 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -684,7 +684,7 @@ static void usb_audio_class_init(ObjectClass *klass, void *data) k->set_interface = usb_audio_set_interface; } -static TypeInfo usb_audio_info = { +static const TypeInfo usb_audio_info = { .name = "usb-audio", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBAudioState), diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index a0d7a88d91..adbf9d4697 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -555,7 +555,7 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_bt; } -static TypeInfo bt_info = { +static const TypeInfo bt_info = { .name = "usb-bt-dongle", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(struct USBBtState), diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index ce38fef9f6..29b64819ab 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -501,7 +501,7 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p, break; case SET_IDLE: hs->idle = (uint8_t) (value >> 8); - hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock)); + hid_set_next_idle(hs); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } @@ -523,16 +523,14 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) switch (p->pid) { case USB_TOKEN_IN: if (p->ep->nr == 1) { - int64_t curtime = qemu_get_clock_ns(vm_clock); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } - if (!hid_has_events(hs) && - (!hs->idle || hs->next_idle_clock - curtime > 0)) { + if (!hid_has_events(hs)) { p->status = USB_RET_NAK; return; } - hid_set_next_idle(hs, curtime); + hid_set_next_idle(hs); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { len = hid_pointer_poll(hs, buf, p->iov.size); } else if (hs->kind == HID_KEYBOARD) { @@ -659,7 +657,7 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) dc->props = usb_tablet_properties; } -static TypeInfo usb_tablet_info = { +static const TypeInfo usb_tablet_info = { .name = "usb-tablet", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHIDState), @@ -678,7 +676,7 @@ static void usb_mouse_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_ptr; } -static TypeInfo usb_mouse_info = { +static const TypeInfo usb_mouse_info = { .name = "usb-mouse", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHIDState), @@ -697,7 +695,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_kbd; } -static TypeInfo usb_keyboard_info = { +static const TypeInfo usb_keyboard_info = { .name = "usb-kbd", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHIDState), diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 470fbbb86c..79f2f46d55 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -568,7 +568,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_hub; } -static TypeInfo hub_info = { +static const TypeInfo hub_info = { .name = "usb-hub", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHubState), diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 1c54863452..9dede4c68d 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1433,7 +1433,7 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data) dc->props = net_properties; } -static TypeInfo net_info = { +static const TypeInfo net_info = { .name = "usb-net", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBNetState), diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 20cf5337b7..47ac8c9b69 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -600,7 +600,7 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data) dc->props = serial_properties; } -static TypeInfo serial_info = { +static const TypeInfo serial_info = { .name = "usb-serial", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBSerialState), @@ -628,7 +628,7 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data) dc->props = braille_properties; } -static TypeInfo braille_info = { +static const TypeInfo braille_info = { .name = "usb-braille", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBSerialState), diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index f26bb341f7..979a473b37 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1322,7 +1322,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data) dc->props = ccid_properties; } -static TypeInfo ccid_info = { +static const TypeInfo ccid_info = { .name = CCID_DEV_NAME, .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBCCIDState), @@ -1338,7 +1338,7 @@ static void ccid_card_class_init(ObjectClass *klass, void *data) k->props = ccid_props; } -static TypeInfo ccid_card_type_info = { +static const TypeInfo ccid_card_type_info = { .name = TYPE_CCID_CARD, .parent = TYPE_DEVICE, .instance_size = sizeof(CCIDCardState), diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 5025597673..1b87352db0 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -716,7 +716,7 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data) dc->props = msd_properties; } -static TypeInfo msd_info = { +static const TypeInfo msd_info = { .name = "usb-storage", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(MSDState), diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 9a0088928f..d904d1a40b 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -757,7 +757,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_uas; } -static TypeInfo uas_info = { +static const TypeInfo uas_info = { .name = "usb-uas", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(UASDevice), diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 9ab368a6c5..ab9fa2ef48 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -366,7 +366,7 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_wacom; } -static TypeInfo wacom_info = { +static const TypeInfo wacom_info = { .name = "usb-wacom-tablet", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBWacomState), diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index ee77d41db5..0eb78269f7 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -16,14 +16,8 @@ */ #include "hw/usb/hcd-ehci.h" -#include "hw/pci/pci.h" #include "qemu/range.h" -typedef struct EHCIPCIState { - PCIDevice pcidev; - EHCIState ehci; -} EHCIPCIState; - typedef struct EHCIPCIInfo { const char *name; uint16_t vendor_id; @@ -33,7 +27,7 @@ typedef struct EHCIPCIInfo { static int usb_ehci_pci_initfn(PCIDevice *dev) { - EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev); + EHCIPCIState *i = PCI_EHCI(dev); EHCIState *s = &i->ehci; uint8_t *pci_conf = dev->config; @@ -83,7 +77,7 @@ static int usb_ehci_pci_initfn(PCIDevice *dev) static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int l) { - EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev); + EHCIPCIState *i = PCI_EHCI(dev); bool busmaster; pci_default_write_config(dev, addr, val, l); @@ -115,12 +109,8 @@ static void ehci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - EHCIPCIInfo *i = data; k->init = usb_ehci_pci_initfn; - k->vendor_id = i->vendor_id; - k->device_id = i->device_id; - k->revision = i->revision; k->class_id = PCI_CLASS_SERIAL_USB; k->config_write = usb_ehci_pci_write_config; k->no_hotplug = 1; @@ -128,6 +118,24 @@ static void ehci_class_init(ObjectClass *klass, void *data) dc->props = ehci_pci_properties; } +static const TypeInfo ehci_pci_type_info = { + .name = TYPE_PCI_EHCI, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EHCIPCIState), + .abstract = true, + .class_init = ehci_class_init, +}; + +static void ehci_data_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + EHCIPCIInfo *i = data; + + k->vendor_id = i->vendor_id; + k->device_id = i->device_id; + k->revision = i->revision; +} + static struct EHCIPCIInfo ehci_pci_info[] = { { .name = "usb-ehci", @@ -150,12 +158,13 @@ static struct EHCIPCIInfo ehci_pci_info[] = { static void ehci_pci_register_types(void) { TypeInfo ehci_type_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(EHCIPCIState), - .class_init = ehci_class_init, + .parent = TYPE_PCI_EHCI, + .class_init = ehci_data_class_init, }; int i; + type_register_static(&ehci_pci_type_info); + for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) { ehci_type_info.name = ehci_pci_info[i].name; ehci_type_info.class_data = ehci_pci_info + i; diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index 803df92f31..b68a66a63b 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -16,12 +16,6 @@ */ #include "hw/usb/hcd-ehci.h" -#include "hw/sysbus.h" - -typedef struct EHCISysBusState { - SysBusDevice busdev; - EHCIState ehci; -} EHCISysBusState; static const VMStateDescription vmstate_ehci_sysbus = { .name = "ehci-sysbus", @@ -40,11 +34,12 @@ static Property ehci_sysbus_properties[] = { static int usb_ehci_sysbus_initfn(SysBusDevice *dev) { - EHCISysBusState *i = FROM_SYSBUS(EHCISysBusState, dev); + EHCISysBusState *i = SYS_BUS_EHCI(dev); + SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(dev); EHCIState *s = &i->ehci; - s->capsbase = 0x100; - s->opregbase = 0x140; + s->capsbase = sec->capsbase; + s->opregbase = sec->opregbase; s->dma = &dma_context_memory; usb_ehci_initfn(s, DEVICE(dev)); @@ -63,16 +58,48 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data) dc->props = ehci_sysbus_properties; } -TypeInfo ehci_xlnx_type_info = { - .name = "xlnx,ps7-usb", +static const TypeInfo ehci_type_info = { + .name = TYPE_SYS_BUS_EHCI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(EHCISysBusState), + .abstract = true, .class_init = ehci_sysbus_class_init, + .class_size = sizeof(SysBusEHCIClass), +}; + +static void ehci_xlnx_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + + sec->capsbase = 0x100; + sec->opregbase = 0x140; +} + +static const TypeInfo ehci_xlnx_type_info = { + .name = "xlnx,ps7-usb", + .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_xlnx_class_init, +}; + +static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + + sec->capsbase = 0x0; + sec->opregbase = 0x10; +} + +static const TypeInfo ehci_exynos4210_type_info = { + .name = TYPE_EXYNOS4210_EHCI, + .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_exynos4210_class_init, }; static void ehci_sysbus_register_types(void) { + type_register_static(&ehci_type_info); type_register_static(&ehci_xlnx_type_info); + type_register_static(&ehci_exynos4210_type_info); } type_init(ehci_sysbus_register_types) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 7536837fb2..320b7e7239 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -109,12 +109,13 @@ #define FRAME_TIMER_FREQ 1000 #define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ) +#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8) #define NB_MAXINTRATE 8 // Max rate at which controller issues ints #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction #define MAX_QH 100 // Max allowable queue heads in a chain -#define MIN_FR_PER_TICK 3 // Min frames to process when catching up -#define PERIODIC_ACTIVE 64 +#define MIN_UFR_PER_TICK 24 /* Min frames to process when catching up */ +#define PERIODIC_ACTIVE 512 /* Micro-frames */ /* Internal periodic / asynchronous schedule state machine states */ @@ -192,6 +193,7 @@ static int ehci_state_executing(EHCIQueue *q); static int ehci_state_writeback(EHCIQueue *q); static int ehci_state_advqueue(EHCIQueue *q); static int ehci_fill_queue(EHCIPacket *p); +static void ehci_free_packet(EHCIPacket *p); static const char *nr2str(const char **n, size_t len, uint32_t nr) { @@ -438,6 +440,136 @@ static inline bool ehci_periodic_enabled(EHCIState *s) return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE); } +/* Get an array of dwords from main memory */ +static inline int get_dwords(EHCIState *ehci, uint32_t addr, + uint32_t *buf, int num) +{ + int i; + + if (!ehci->dma) { + ehci_raise_irq(ehci, USBSTS_HSE); + ehci->usbcmd &= ~USBCMD_RUNSTOP; + trace_usb_ehci_dma_error(); + return -1; + } + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + dma_memory_read(ehci->dma, addr, buf, sizeof(*buf)); + *buf = le32_to_cpu(*buf); + } + + return num; +} + +/* Put an array of dwords in to main memory */ +static inline int put_dwords(EHCIState *ehci, uint32_t addr, + uint32_t *buf, int num) +{ + int i; + + if (!ehci->dma) { + ehci_raise_irq(ehci, USBSTS_HSE); + ehci->usbcmd &= ~USBCMD_RUNSTOP; + trace_usb_ehci_dma_error(); + return -1; + } + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint32_t tmp = cpu_to_le32(*buf); + dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp)); + } + + return num; +} + +static int ehci_get_pid(EHCIqtd *qtd) +{ + switch (get_field(qtd->token, QTD_TOKEN_PID)) { + case 0: + return USB_TOKEN_OUT; + case 1: + return USB_TOKEN_IN; + case 2: + return USB_TOKEN_SETUP; + default: + fprintf(stderr, "bad token\n"); + return 0; + } +} + +static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh) +{ + uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR); + uint32_t endp = get_field(qh->epchar, QH_EPCHAR_EP); + if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || + (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || + (qh->current_qtd != q->qh.current_qtd) || + (q->async && qh->next_qtd != q->qh.next_qtd) || + (memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd, + 7 * sizeof(uint32_t)) != 0) || + (q->dev != NULL && q->dev->addr != devaddr)) { + return false; + } else { + return true; + } +} + +static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd) +{ + if (p->qtdaddr != p->queue->qtdaddr || + (p->queue->async && !NLPTR_TBIT(p->qtd.next) && + (p->qtd.next != qtd->next)) || + (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) || + p->qtd.token != qtd->token || + p->qtd.bufptr[0] != qtd->bufptr[0]) { + return false; + } else { + return true; + } +} + +static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd) +{ + int ep = get_field(q->qh.epchar, QH_EPCHAR_EP); + int pid = ehci_get_pid(qtd); + + /* Note the pid changing is normal for ep 0 (the control ep) */ + if (q->last_pid && ep != 0 && pid != q->last_pid) { + return false; + } else { + return true; + } +} + +/* Finish executing and writeback a packet outside of the regular + fetchqh -> fetchqtd -> execute -> writeback cycle */ +static void ehci_writeback_async_complete_packet(EHCIPacket *p) +{ + EHCIQueue *q = p->queue; + EHCIqtd qtd; + EHCIqh qh; + int state; + + /* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */ + get_dwords(q->ehci, NLPTR_GET(q->qhaddr), + (uint32_t *) &qh, sizeof(EHCIqh) >> 2); + get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), + (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); + if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) { + p->async = EHCI_ASYNC_INITIALIZED; + ehci_free_packet(p); + return; + } + + state = ehci_get_state(q->ehci, q->async); + ehci_state_executing(q); + ehci_state_writeback(q); /* Frees the packet! */ + if (!(q->qh.token & QTD_TOKEN_HALT)) { + ehci_state_advqueue(q); + } + ehci_set_state(q->ehci, q->async, state); +} + /* packet management */ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) @@ -455,17 +587,7 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) static void ehci_free_packet(EHCIPacket *p) { if (p->async == EHCI_ASYNC_FINISHED) { - EHCIQueue *q = p->queue; - int state = ehci_get_state(q->ehci, q->async); - /* This is a normal, but rare condition (cancel racing completion) */ - fprintf(stderr, "EHCI: Warning packet completed but not processed\n"); - ehci_state_executing(q); - ehci_state_writeback(q); - if (!(q->qh.token & QTD_TOKEN_HALT)) { - ehci_state_advqueue(q); - } - ehci_set_state(q->ehci, q->async, state); - /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */ + ehci_writeback_async_complete_packet(p); return; } trace_usb_ehci_packet_action(p->queue, p, "free"); @@ -500,6 +622,17 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async) return q; } +static void ehci_queue_stopped(EHCIQueue *q) +{ + int endp = get_field(q->qh.epchar, QH_EPCHAR_EP); + + if (!q->last_pid || !q->dev) { + return; + } + + usb_device_ep_stopped(q->dev, usb_ep_get(q->dev, q->last_pid, endp)); +} + static int ehci_cancel_queue(EHCIQueue *q) { EHCIPacket *p; @@ -507,7 +640,7 @@ static int ehci_cancel_queue(EHCIQueue *q) p = QTAILQ_FIRST(&q->packets); if (p == NULL) { - return 0; + goto leave; } trace_usb_ehci_queue_action(q, "cancel"); @@ -515,6 +648,9 @@ static int ehci_cancel_queue(EHCIQueue *q) ehci_free_packet(p); packets++; } while ((p = QTAILQ_FIRST(&q->packets)) != NULL); + +leave: + ehci_queue_stopped(q); return packets; } @@ -526,6 +662,7 @@ static int ehci_reset_queue(EHCIQueue *q) packets = ehci_cancel_queue(q); q->dev = NULL; q->qtdaddr = 0; + q->last_pid = 0; return packets; } @@ -634,7 +771,6 @@ static void ehci_attach(USBPort *port) *portsc |= PORTSC_CSC; ehci_raise_irq(s, USBSTS_PCD); - ehci_commit_irq(s); } static void ehci_detach(USBPort *port) @@ -664,7 +800,6 @@ static void ehci_detach(USBPort *port) *portsc |= PORTSC_CSC; ehci_raise_irq(s, USBSTS_PCD); - ehci_commit_irq(s); } static void ehci_child_detach(USBPort *port, USBDevice *child) @@ -833,7 +968,15 @@ static uint64_t ehci_opreg_read(void *ptr, hwaddr addr, EHCIState *s = ptr; uint32_t val; - val = s->opreg[addr >> 2]; + switch (addr) { + case FRINDEX: + /* Round down to mult of 8, else it can go backwards on migration */ + val = s->frindex & ~7; + break; + default: + val = s->opreg[addr >> 2]; + } + trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val); return val; } @@ -984,7 +1127,8 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, break; case FRINDEX: - val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */ + val &= 0x00003fff; /* frindex is 14bits */ + s->usbsts_frindex = val; break; case CONFIGFLAG: @@ -1017,48 +1161,6 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, *mmio, old); } -/* Get an array of dwords from main memory */ -static inline int get_dwords(EHCIState *ehci, uint32_t addr, - uint32_t *buf, int num) -{ - int i; - - if (!ehci->dma) { - ehci_raise_irq(ehci, USBSTS_HSE); - ehci->usbcmd &= ~USBCMD_RUNSTOP; - trace_usb_ehci_dma_error(); - return -1; - } - - for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - dma_memory_read(ehci->dma, addr, buf, sizeof(*buf)); - *buf = le32_to_cpu(*buf); - } - - return num; -} - -/* Put an array of dwords in to main memory */ -static inline int put_dwords(EHCIState *ehci, uint32_t addr, - uint32_t *buf, int num) -{ - int i; - - if (!ehci->dma) { - ehci_raise_irq(ehci, USBSTS_HSE); - ehci->usbcmd &= ~USBCMD_RUNSTOP; - trace_usb_ehci_dma_error(); - return -1; - } - - for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - uint32_t tmp = cpu_to_le32(*buf); - dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp)); - } - - return num; -} - /* * Write the qh back to guest physical memory. This step isn't * in the EHCI spec but we need to do it since we don't share @@ -1257,6 +1359,9 @@ static void ehci_execute_complete(EHCIQueue *q) if (tbytes) { /* 4.15.1.2 must raise int on a short input packet */ ehci_raise_irq(q->ehci, USBSTS_INT); + if (q->async) { + q->ehci->int_req_by_async = true; + } } } else { tbytes = 0; @@ -1301,22 +1406,11 @@ static int ehci_execute(EHCIPacket *p, const char *action) return -1; } - p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH; - switch (p->pid) { - case 0: - p->pid = USB_TOKEN_OUT; - break; - case 1: - p->pid = USB_TOKEN_IN; - break; - case 2: - p->pid = USB_TOKEN_SETUP; - break; - default: - fprintf(stderr, "bad token\n"); - break; + if (!ehci_verify_pid(p->queue, &p->qtd)) { + ehci_queue_stopped(p->queue); /* Mark the ep in the prev dir stopped */ } - + p->pid = ehci_get_pid(&p->qtd); + p->queue->last_pid = p->pid; endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); ep = usb_ep_get(p->queue->dev, p->pid, endp); @@ -1551,8 +1645,7 @@ out: static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) { - EHCIPacket *p; - uint32_t entry, devaddr, endp; + uint32_t entry; EHCIQueue *q; EHCIqh qh; @@ -1561,7 +1654,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) if (NULL == q) { q = ehci_alloc_queue(ehci, entry, async); } - p = QTAILQ_FIRST(&q->packets); q->seen++; if (q->seen > 1) { @@ -1582,19 +1674,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) * The overlay area of the qh should never be changed by the guest, * except when idle, in which case the reset is a nop. */ - devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR); - endp = get_field(qh.epchar, QH_EPCHAR_EP); - if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || - (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || - (qh.current_qtd != q->qh.current_qtd) || - (q->async && qh.next_qtd != q->qh.next_qtd) || - (memcmp(&qh.altnext_qtd, &q->qh.altnext_qtd, - 7 * sizeof(uint32_t)) != 0) || - (q->dev != NULL && q->dev->addr != devaddr)) { + if (!ehci_verify_qh(q, &qh)) { if (ehci_reset_queue(q) > 0) { ehci_trace_guest_bug(ehci, "guest updated active QH"); } - p = NULL; } q->qh = qh; @@ -1604,14 +1687,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) } if (q->dev == NULL) { - q->dev = ehci_find_device(q->ehci, devaddr); - } - - if (p && p->async == EHCI_ASYNC_FINISHED) { - /* I/O finished -- continue processing queue */ - trace_usb_ehci_packet_action(p->queue, p, "complete"); - ehci_set_state(ehci, async, EST_EXECUTING); - goto out; + q->dev = ehci_find_device(q->ehci, + get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)); } if (async && (q->qh.epchar & QH_EPCHAR_H)) { @@ -1762,13 +1839,11 @@ static int ehci_state_fetchqtd(EHCIQueue *q) p = QTAILQ_FIRST(&q->packets); if (p != NULL) { - if (p->qtdaddr != q->qtdaddr || - (q->async && !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]) { + if (!ehci_verify_qtd(p, &qtd)) { ehci_cancel_queue(q); - ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD"); + if (qtd.token & QTD_TOKEN_ACTIVE) { + ehci_trace_guest_bug(q->ehci, "guest updated active qTD"); + } p = NULL; } else { p->qtd = qtd; @@ -1777,11 +1852,6 @@ static int ehci_state_fetchqtd(EHCIQueue *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); } else if (p != NULL) { switch (p->async) { @@ -1797,10 +1867,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q) ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); break; case EHCI_ASYNC_FINISHED: - /* - * We get here when advqueue moves to a packet which is already - * finished, which can happen with packets queued up by fill_queue - */ + /* Complete executing of the packet */ ehci_set_state(q->ehci, q->async, EST_EXECUTING); break; } @@ -1859,6 +1926,10 @@ static int ehci_fill_queue(EHCIPacket *p) if (!(qtd.token & QTD_TOKEN_ACTIVE)) { break; } + if (!ehci_verify_pid(q, &qtd)) { + ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid"); + break; + } p = ehci_alloc_packet(q); p->qtdaddr = qtdaddr; p->qtd = qtd; @@ -2176,16 +2247,16 @@ static void ehci_advance_periodic_state(EHCIState *ehci) } } -static void ehci_update_frindex(EHCIState *ehci, int frames) +static void ehci_update_frindex(EHCIState *ehci, int uframes) { int i; - if (!ehci_enabled(ehci)) { + if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) { return; } - for (i = 0; i < frames; i++) { - ehci->frindex += 8; + for (i = 0; i < uframes; i++) { + ehci->frindex++; if (ehci->frindex == 0x00002000) { ehci_raise_irq(ehci, USBSTS_FLR); @@ -2209,33 +2280,33 @@ static void ehci_frame_timer(void *opaque) int need_timer = 0; int64_t expire_time, t_now; uint64_t ns_elapsed; - int frames, skipped_frames; + int uframes, skipped_uframes; int i; t_now = qemu_get_clock_ns(vm_clock); ns_elapsed = t_now - ehci->last_run_ns; - frames = ns_elapsed / FRAME_TIMER_NS; + uframes = ns_elapsed / UFRAME_TIMER_NS; if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) { need_timer++; - if (frames > ehci->maxframes) { - skipped_frames = frames - ehci->maxframes; - ehci_update_frindex(ehci, skipped_frames); - ehci->last_run_ns += FRAME_TIMER_NS * skipped_frames; - frames -= skipped_frames; - DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames); + if (uframes > (ehci->maxframes * 8)) { + skipped_uframes = uframes - (ehci->maxframes * 8); + ehci_update_frindex(ehci, skipped_uframes); + ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes; + uframes -= skipped_uframes; + DPRINTF("WARNING - EHCI skipped %d uframes\n", skipped_uframes); } - for (i = 0; i < frames; i++) { + for (i = 0; i < uframes; i++) { /* * If we're running behind schedule, we should not catch up * too fast, as that will make some guests unhappy: - * 1) We must process a minimum of MIN_FR_PER_TICK frames, + * 1) We must process a minimum of MIN_UFR_PER_TICK frames, * otherwise we will never catch up * 2) Process frames until the guest has requested an irq (IOC) */ - if (i >= MIN_FR_PER_TICK) { + if (i >= MIN_UFR_PER_TICK) { ehci_commit_irq(ehci); if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) { break; @@ -2245,13 +2316,15 @@ static void ehci_frame_timer(void *opaque) ehci->periodic_sched_active--; } ehci_update_frindex(ehci, 1); - ehci_advance_periodic_state(ehci); - ehci->last_run_ns += FRAME_TIMER_NS; + if ((ehci->frindex & 7) == 0) { + ehci_advance_periodic_state(ehci); + } + ehci->last_run_ns += UFRAME_TIMER_NS; } } else { ehci->periodic_sched_active = 0; - ehci_update_frindex(ehci, frames); - ehci->last_run_ns += FRAME_TIMER_NS * frames; + ehci_update_frindex(ehci, uframes); + ehci->last_run_ns += UFRAME_TIMER_NS * uframes; } if (ehci->periodic_sched_active) { @@ -2282,7 +2355,7 @@ static void ehci_frame_timer(void *opaque) /* If we've raised int, we speed up the timer, so that we quickly * notice any new packets queued up in response */ if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) { - expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 2); + expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 4); ehci->int_req_by_async = false; } else { expire_time = t_now + (get_ticks_per_sec() @@ -2330,6 +2403,17 @@ static USBBusOps ehci_bus_ops = { .wakeup_endpoint = ehci_wakeup_endpoint, }; +static void usb_ehci_pre_save(void *opaque) +{ + EHCIState *ehci = opaque; + uint32_t new_frindex; + + /* Round down frindex to a multiple of 8 for migration compatibility */ + new_frindex = ehci->frindex & ~7; + ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS; + ehci->frindex = new_frindex; +} + static int usb_ehci_post_load(void *opaque, int version_id) { EHCIState *s = opaque; @@ -2380,6 +2464,7 @@ const VMStateDescription vmstate_ehci = { .name = "ehci-core", .version_id = 2, .minimum_version_id = 1, + .pre_save = usb_ehci_pre_save, .post_load = usb_ehci_post_load, .fields = (VMStateField[]) { /* mmio registers */ diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index e35144d386..e95bb7ec46 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -24,6 +24,8 @@ #include "trace.h" #include "sysemu/dma.h" #include "sysemu/sysemu.h" +#include "hw/pci/pci.h" +#include "hw/sysbus.h" #ifndef EHCI_DEBUG #define EHCI_DEBUG 0 @@ -248,6 +250,7 @@ struct EHCIQueue { EHCIqh qh; /* copy of current QH (being worked on) */ uint32_t qhaddr; /* address QH read from */ uint32_t qtdaddr; /* address QTD read from */ + int last_pid; /* pid of last packet executed */ USBDevice *dev; QTAILQ_HEAD(pkts_head, EHCIPacket) packets; }; @@ -321,4 +324,43 @@ extern const VMStateDescription vmstate_ehci; void usb_ehci_initfn(EHCIState *s, DeviceState *dev); +#define TYPE_PCI_EHCI "pci-ehci-usb" +#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI) + +typedef struct EHCIPCIState { + /*< private >*/ + PCIDevice pcidev; + /*< public >*/ + + EHCIState ehci; +} EHCIPCIState; + + +#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" +#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb" + +#define SYS_BUS_EHCI(obj) \ + OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI) +#define SYS_BUS_EHCI_CLASS(class) \ + OBJECT_CLASS_CHECK(SysBusEHCIClass, (class), TYPE_SYS_BUS_EHCI) +#define SYS_BUS_EHCI_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SysBusEHCIClass, (obj), TYPE_SYS_BUS_EHCI) + +typedef struct EHCISysBusState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + EHCIState ehci; +} EHCISysBusState; + +typedef struct SysBusEHCIClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + + uint16_t capsbase; + uint16_t opregbase; +} SysBusEHCIClass; + #endif diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 052c4a3037..6a2f5f8c5d 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -430,6 +430,23 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr) return NULL; } +static void ohci_stop_endpoints(OHCIState *ohci) +{ + USBDevice *dev; + int i, j; + + for (i = 0; i < ohci->num_ports; i++) { + dev = ohci->rhport[i].port.dev; + if (dev && dev->attached) { + usb_device_ep_stopped(dev, &dev->ep_ctl); + for (j = 0; j < USB_MAX_ENDPOINTS; j++) { + usb_device_ep_stopped(dev, &dev->ep_in[j]); + usb_device_ep_stopped(dev, &dev->ep_out[j]); + } + } + } +} + /* Reset the controller */ static void ohci_reset(void *opaque) { @@ -478,6 +495,7 @@ static void ohci_reset(void *opaque) usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; } + ohci_stop_endpoints(ohci); DPRINTF("usb-ohci: Reset %s\n", ohci->name); } @@ -1147,6 +1165,8 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) if (ohci->async_td && addr == ohci->async_td) { usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; + usb_device_ep_stopped(ohci->usb_packet.ep->dev, + ohci->usb_packet.ep); } continue; } @@ -1227,10 +1247,12 @@ static void ohci_frame_boundary(void *opaque) } /* Cancel all pending packets if either of the lists has been disabled. */ - if (ohci->async_td && - ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { - usb_cancel_packet(&ohci->usb_packet); - ohci->async_td = 0; + if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { + if (ohci->async_td) { + usb_cancel_packet(&ohci->usb_packet); + ohci->async_td = 0; + } + ohci_stop_endpoints(ohci); } ohci->old_ctl = ohci->ctl; ohci_process_lists(ohci, 0); @@ -1887,7 +1909,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) dc->props = ohci_pci_properties; } -static TypeInfo ohci_pci_info = { +static const TypeInfo ohci_pci_info = { .name = "pci-ohci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(OHCIPCIState), @@ -1910,7 +1932,7 @@ static void ohci_sysbus_class_init(ObjectClass *klass, void *data) dc->props = ohci_sysbus_properties; } -static TypeInfo ohci_sysbus_info = { +static const TypeInfo ohci_sysbus_info = { .name = "sysbus-ohci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OHCISysBusState), diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 2af754b5cf..60645aa21f 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -75,6 +75,11 @@ #define FRAME_MAX_LOOPS 256 +/* Must be large enough to handle 10 frame delay for initial isoc requests */ +#define QH_VALID 32 + +#define MAX_FRAMES_PER_TICK (QH_VALID / 2) + #define NB_PORTS 2 enum { @@ -166,6 +171,7 @@ struct UHCIState { /* Properties */ char *masterbus; uint32_t firstport; + uint32_t maxframes; }; typedef struct UHCI_TD { @@ -206,9 +212,7 @@ static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td, queue->ep = ep; QTAILQ_INIT(&queue->asyncs); QTAILQ_INSERT_HEAD(&s->queues, queue, next); - /* valid needs to be large enough to handle 10 frame delay - * for initial isochronous requests */ - queue->valid = 32; + queue->valid = QH_VALID; trace_usb_uhci_queue_add(queue->token); return queue; } @@ -222,6 +226,7 @@ static void uhci_queue_free(UHCIQueue *queue, const char *reason) async = QTAILQ_FIRST(&queue->asyncs); uhci_async_cancel(async); } + usb_device_ep_stopped(queue->ep->dev, queue->ep); trace_usb_uhci_queue_del(queue->token, reason); QTAILQ_REMOVE(&s->queues, queue, next); @@ -433,7 +438,7 @@ static int uhci_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_uhci = { .name = "uhci", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .minimum_version_id_old = 1, .post_load = uhci_post_load, @@ -451,44 +456,16 @@ static const VMStateDescription vmstate_uhci = { VMSTATE_UINT8(status2, UHCIState), VMSTATE_TIMER(frame_timer, UHCIState), VMSTATE_INT64_V(expire_time, UHCIState, 2), + VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3), VMSTATE_END_OF_LIST() } }; -static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; - switch(addr) { - case 0x0c: - s->sof_timing = val; - break; - } -} - -static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x0c: - val = s->sof_timing; - break; - default: - val = 0xff; - break; - } - return val; -} - -static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +static void uhci_port_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { UHCIState *s = opaque; - addr &= 0x1f; trace_usb_uhci_mmio_writew(addr, val); switch(addr) { @@ -498,7 +475,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) trace_usb_uhci_schedule_start(); s->expire_time = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / FRAME_TIMER_FREQ); - qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); + qemu_mod_timer(s->frame_timer, s->expire_time); s->status &= ~UHCI_STS_HCHALTED; } else if (!(val & UHCI_CMD_RS)) { s->status |= UHCI_STS_HCHALTED; @@ -537,6 +514,17 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) if (s->status & UHCI_STS_HCHALTED) s->frnum = val & 0x7ff; break; + case 0x08: + s->fl_base_addr &= 0xffff0000; + s->fl_base_addr |= val & ~0xfff; + break; + case 0x0a: + s->fl_base_addr &= 0x0000ffff; + s->fl_base_addr |= (val << 16); + break; + case 0x0c: + s->sof_timing = val & 0xff; + break; case 0x10 ... 0x1f: { UHCIPort *port; @@ -568,12 +556,11 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) +static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size) { UHCIState *s = opaque; uint32_t val; - addr &= 0x1f; switch(addr) { case 0x00: val = s->cmd; @@ -587,6 +574,15 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) case 0x06: val = s->frnum; break; + case 0x08: + val = s->fl_base_addr & 0xffff; + break; + case 0x0a: + val = (s->fl_base_addr >> 16) & 0xffff; + break; + case 0x0c: + val = s->sof_timing; + break; case 0x10 ... 0x1f: { UHCIPort *port; @@ -609,38 +605,6 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) return val; } -static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; - trace_usb_uhci_mmio_writel(addr, val); - - switch(addr) { - case 0x08: - s->fl_base_addr = val & ~0xfff; - break; - } -} - -static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x08: - val = s->fl_base_addr; - break; - default: - val = 0xffffffff; - break; - } - trace_usb_uhci_mmio_readl(addr, val); - return val; -} - /* signal resume if controller suspended */ static void uhci_resume (void *opaque) { @@ -853,7 +817,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, } if (q) { - q->valid = 32; + q->valid = QH_VALID; } /* Is active ? */ @@ -1174,10 +1138,10 @@ static void uhci_bh(void *opaque) static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; + uint64_t t_now, t_last_run; + int i, frames; + const uint64_t frame_t = get_ticks_per_sec() / FRAME_TIMER_FREQ; - /* prepare the timer for the next frame */ - s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); - s->frame_bytes = 0; s->completions_only = false; qemu_bh_cancel(s->bh); @@ -1191,7 +1155,35 @@ static void uhci_frame_timer(void *opaque) return; } - /* Complete the previous frame */ + /* We still store expire_time in our state, for migration */ + t_last_run = s->expire_time - frame_t; + t_now = qemu_get_clock_ns(vm_clock); + + /* Process up to MAX_FRAMES_PER_TICK frames */ + frames = (t_now - t_last_run) / frame_t; + if (frames > s->maxframes) { + int skipped = frames - s->maxframes; + s->expire_time += skipped * frame_t; + s->frnum = (s->frnum + skipped) & 0x7ff; + frames -= skipped; + } + if (frames > MAX_FRAMES_PER_TICK) { + frames = MAX_FRAMES_PER_TICK; + } + + for (i = 0; i < frames; i++) { + s->frame_bytes = 0; + trace_usb_uhci_frame_start(s->frnum); + uhci_async_validate_begin(s); + uhci_process_frame(s); + uhci_async_validate_end(s); + /* The spec says frnum is the frame currently being processed, and + * the guest must look at frnum - 1 on interrupt, so inc frnum now */ + s->frnum = (s->frnum + 1) & 0x7ff; + s->expire_time += frame_t; + } + + /* Complete the previous frame(s) */ if (s->pending_int_mask) { s->status2 |= s->pending_int_mask; s->status |= UHCI_STS_USBINT; @@ -1199,32 +1191,17 @@ static void uhci_frame_timer(void *opaque) } s->pending_int_mask = 0; - /* Start new frame */ - s->frnum = (s->frnum + 1) & 0x7ff; - - trace_usb_uhci_frame_start(s->frnum); - - uhci_async_validate_begin(s); - - uhci_process_frame(s); - - uhci_async_validate_end(s); - - qemu_mod_timer(s->frame_timer, s->expire_time); + qemu_mod_timer(s->frame_timer, t_now + frame_t); } -static const MemoryRegionPortio uhci_portio[] = { - { 0, 32, 2, .write = uhci_ioport_writew, }, - { 0, 32, 2, .read = uhci_ioport_readw, }, - { 0, 32, 4, .write = uhci_ioport_writel, }, - { 0, 32, 4, .read = uhci_ioport_readl, }, - { 0, 32, 1, .write = uhci_ioport_writeb, }, - { 0, 32, 1, .read = uhci_ioport_readb, }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps uhci_ioport_ops = { - .old_portio = uhci_portio, + .read = uhci_port_read, + .write = uhci_port_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 2, + .impl.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, }; static USBPortOps uhci_port_ops = { @@ -1311,6 +1288,7 @@ static Property uhci_properties[] = { DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280), + DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index e2de71ef1a..92f2eee3bc 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1177,6 +1177,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, XHCISlot *slot; XHCIEPContext *epctx; int i, xferi, killed = 0; + USBEndpoint *ep = NULL; assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); @@ -1192,9 +1193,15 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, xferi = epctx->next_xfer; for (i = 0; i < TD_QUEUE; i++) { + if (epctx->transfers[xferi].packet.ep) { + ep = epctx->transfers[xferi].packet.ep; + } killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi]); xferi = (xferi + 1) % TD_QUEUE; } + if (ep) { + usb_device_ep_stopped(ep->dev, ep); + } return killed; } @@ -1963,13 +1970,18 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, if (bsr) { slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT; } else { + USBPacket p; slot->devaddr = xhci->devaddr++; slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr; DPRINTF("xhci: device address is %d\n", slot->devaddr); usb_device_reset(dev); - usb_device_handle_control(dev, NULL, + usb_packet_setup(&p, USB_TOKEN_OUT, + usb_ep_get(dev, USB_TOKEN_OUT, 0), + 0, false, false); + usb_device_handle_control(dev, &p, DeviceOutRequest | USB_REQ_SET_ADDRESS, slot->devaddr, 0, 0, NULL); + assert(p.status != USB_RET_ASYNC); } res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx); @@ -3170,7 +3182,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) k->no_hotplug = 1; } -static TypeInfo xhci_info = { +static const TypeInfo xhci_info = { .name = "nec-usb-xhci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(XHCIState), diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c index 340c21aeb4..172aecbffd 100644 --- a/hw/usb/host-bsd.c +++ b/hw/usb/host-bsd.c @@ -407,7 +407,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->handle_destroy = usb_host_handle_destroy; } -static TypeInfo usb_host_dev_info = { +static const TypeInfo usb_host_dev_info = { .name = "usb-host", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHostDevice), diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 669fbd245c..e8e6a42fb9 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1534,7 +1534,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) dc->props = usb_host_dev_properties; } -static TypeInfo usb_host_dev_info = { +static const TypeInfo usb_host_dev_info = { .name = "usb-host", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHostDevice), diff --git a/hw/usb/quirks-ftdi-ids.h b/hw/usb/quirks-ftdi-ids.h new file mode 100644 index 0000000000..57c12ef662 --- /dev/null +++ b/hw/usb/quirks-ftdi-ids.h @@ -0,0 +1,1255 @@ +/* + * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters. + * Please keep numerically sorted within individual areas, thanks! + * + * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais + * from Rudolf Gugler + * + */ + + +/**********************************/ +/***** devices using FTDI VID *****/ +/**********************************/ + + +#define FTDI_VID 0x0403 /* Vendor Id */ + + +/*** "original" FTDI device PIDs ***/ + +#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ +#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ +#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ +#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ +#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ +#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */ +#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ +#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ + + +/*** third-party PIDs (using FTDI_VID) ***/ + +#define FTDI_LUMEL_PD12_PID 0x6002 + +/* + * Marvell OpenRD Base, Client + * http://www.open-rd.org + * OpenRD Base, Client use VID 0x0403 + */ +#define MARVELL_OPENRD_PID 0x9e90 + +/* www.candapter.com Ewert Energy Systems CANdapter device */ +#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ + +/* + * Texas Instruments XDS100v2 JTAG / BeagleBone A3 + * http://processors.wiki.ti.com/index.php/XDS100 + * http://beagleboard.org/bone + */ +#define TI_XDS100V2_PID 0xa6d0 + +#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ + +/* US Interface Navigator (http://www.usinterface.com/) */ +#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */ +#define FTDI_USINT_WKEY_PID 0xb811 /* Navigator WKEY and FSK lines */ +#define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */ + +/* OOCDlink by Joern Kaipf <joernk@web.de> + * (http://www.joernonline.de/) */ +#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ + +/* Luminary Micro Stellaris Boards, VID = FTDI_VID */ +/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */ +#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8 +#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 +#define LMI_LM3S_ICDI_BOARD_PID 0xbcda + +#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */ + +/* OpenDCC (www.opendcc.de) product id */ +#define FTDI_OPENDCC_PID 0xBFD8 +#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9 +#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA +#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB +#define FTDI_OPENDCC_GBM_PID 0xBFDC + +/* NZR SEM 16+ USB (http://www.nzr.de) */ +#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */ + +/* + * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) + */ +#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */ + +/* DMX4ALL DMX Interfaces */ +#define FTDI_DMX4ALL 0xC850 + +/* + * ASK.fr devices + */ +#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ + +/* www.starting-point-systems.com µChameleon device */ +#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */ + +/* + * Tactrix OpenPort (ECU) devices. + * OpenPort 1.3M submitted by Donour Sizemore. + * OpenPort 1.3S and 1.3U submitted by Ian Abbott. + */ +#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */ +#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */ +#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */ + +#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8 + +/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */ +/* the VID is the standard ftdi vid (FTDI_VID) */ +#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */ +#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */ +#define FTDI_SCS_DEVICE_2_PID 0xD012 +#define FTDI_SCS_DEVICE_3_PID 0xD013 +#define FTDI_SCS_DEVICE_4_PID 0xD014 +#define FTDI_SCS_DEVICE_5_PID 0xD015 +#define FTDI_SCS_DEVICE_6_PID 0xD016 +#define FTDI_SCS_DEVICE_7_PID 0xD017 + +/* iPlus device */ +#define FTDI_IPLUS_PID 0xD070 /* Product Id */ +#define FTDI_IPLUS2_PID 0xD071 /* Product Id */ + +/* + * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com. + */ +#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */ + +/* Propox devices */ +#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739 + +/* Lenz LI-USB Computer Interface. */ +#define FTDI_LENZ_LIUSB_PID 0xD780 + +/* Vardaan Enterprises Serial Interface VEUSB422R3 */ +#define FTDI_VARDAAN_PID 0xF070 + +/* + * Xsens Technologies BV products (http://www.xsens.com). + */ +#define XSENS_CONVERTER_0_PID 0xD388 +#define XSENS_CONVERTER_1_PID 0xD389 +#define XSENS_CONVERTER_2_PID 0xD38A +#define XSENS_CONVERTER_3_PID 0xD38B +#define XSENS_CONVERTER_4_PID 0xD38C +#define XSENS_CONVERTER_5_PID 0xD38D +#define XSENS_CONVERTER_6_PID 0xD38E +#define XSENS_CONVERTER_7_PID 0xD38F + +/* + * NDI (www.ndigital.com) product ids + */ +#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */ +#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */ +#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */ +#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */ +#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */ + +/* + * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs + */ +#define FTDI_CHAMSYS_24_MASTER_WING_PID 0xDAF8 +#define FTDI_CHAMSYS_PC_WING_PID 0xDAF9 +#define FTDI_CHAMSYS_USB_DMX_PID 0xDAFA +#define FTDI_CHAMSYS_MIDI_TIMECODE_PID 0xDAFB +#define FTDI_CHAMSYS_MINI_WING_PID 0xDAFC +#define FTDI_CHAMSYS_MAXI_WING_PID 0xDAFD +#define FTDI_CHAMSYS_MEDIA_WING_PID 0xDAFE +#define FTDI_CHAMSYS_WING_PID 0xDAFF + +/* + * Westrex International devices submitted by Cory Lee + */ +#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */ +#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */ + +/* + * ACG Identification Technologies GmbH products (http://www.acg.de/). + * Submitted by anton -at- goto10 -dot- org. + */ +#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ + +/* + * Definitions for Artemis astronomical USB based cameras + * Check it at http://www.artemisccd.co.uk/ + */ +#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */ + +/* + * Definitions for ATIK Instruments astronomical USB based cameras + * Check it at http://www.atik-instruments.com/ + */ +#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Grayscale Camera */ +#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */ +#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */ +#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */ +#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */ + +/* + * Yost Engineering, Inc. products (www.yostengineering.com). + * PID 0xE050 submitted by Aaron Prose. + */ +#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */ + +/* + * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). + * All of these devices use FTDI's vendor ID (0x0403). + * Further IDs taken from ELV Windows .inf file. + * + * The previously included PID for the UO 100 module was incorrect. + * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58). + * + * Armin Laeuger originally sent the PID for the UM 100 module. + */ +#define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */ +#define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */ +#define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */ +#define FTDI_ELV_WS550_PID 0xE004 /* WS 550 */ +#define FTDI_ELV_EC3000_PID 0xE006 /* ENERGY CONTROL 3000 USB */ +#define FTDI_ELV_WS888_PID 0xE008 /* WS 888 */ +#define FTDI_ELV_TWS550_PID 0xE009 /* Technoline WS 550 */ +#define FTDI_ELV_FEM_PID 0xE00A /* Funk Energie Monitor */ +#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */ +#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */ +#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */ +#define FTDI_ELV_UMS100_PID 0xE0EB /* ELV USB Master-Slave Schaltsteckdose UMS 100 */ +#define FTDI_ELV_TFD128_PID 0xE0EC /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */ +#define FTDI_ELV_FM3RX_PID 0xE0ED /* ELV Messwertuebertragung FM3 RX */ +#define FTDI_ELV_WS777_PID 0xE0EE /* Conrad WS 777 */ +#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Energy monitor EM 1010 PC */ +#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */ +#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */ +#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */ +#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */ +#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */ +#define FTDI_ELV_UTP8_PID 0xE0F5 /* ELV UTP 8 */ +#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */ +#define FTDI_ELV_WS444PC_PID 0xE0F7 /* Conrad WS 444 PC */ +#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */ +#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */ +#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */ +#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */ +#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */ +#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */ +#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */ +#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */ +#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */ +#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */ +#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */ +#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */ +/* Additional ELV PIDs that default to using the FTDI D2XX drivers on + * MS Windows, rather than the FTDI Virtual Com Port drivers. + * Maybe these will be easier to use with the libftdi/libusb user-space + * drivers, or possibly the Comedi drivers in some cases. */ +#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */ +#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */ +#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperatur-Feuchte-Messgeraet (TFM 100) */ +#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */ +#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */ + +/* + * EVER Eco Pro UPS (http://www.ever.com.pl/) + */ + +#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */ + +/* + * Active Robots product ids. + */ +#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */ + +/* Pyramid Computer GmbH */ +#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */ + +/* www.elsterelectricity.com Elster Unicom III Optical Probe */ +#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */ + +/* + * Gude Analog- und Digitalsysteme GmbH + */ +#define FTDI_GUDEADS_E808_PID 0xE808 +#define FTDI_GUDEADS_E809_PID 0xE809 +#define FTDI_GUDEADS_E80A_PID 0xE80A +#define FTDI_GUDEADS_E80B_PID 0xE80B +#define FTDI_GUDEADS_E80C_PID 0xE80C +#define FTDI_GUDEADS_E80D_PID 0xE80D +#define FTDI_GUDEADS_E80E_PID 0xE80E +#define FTDI_GUDEADS_E80F_PID 0xE80F +#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */ +#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */ +#define FTDI_GUDEADS_E88A_PID 0xE88A +#define FTDI_GUDEADS_E88B_PID 0xE88B +#define FTDI_GUDEADS_E88C_PID 0xE88C +#define FTDI_GUDEADS_E88D_PID 0xE88D +#define FTDI_GUDEADS_E88E_PID 0xE88E +#define FTDI_GUDEADS_E88F_PID 0xE88F + +/* + * Eclo (http://www.eclo.pt/) product IDs. + * PID 0xEA90 submitted by Martin Grill. + */ +#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */ + +/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */ +#define FTDI_TNC_X_PID 0xEBE0 + +/* + * Teratronik product ids. + * Submitted by O. Wölfelschneider. + */ +#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */ +#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */ + +/* Rig Expert Ukraine devices */ +#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */ + +/* + * Hameg HO820 and HO870 interface (using VID 0x0403) + */ +#define HAMEG_HO820_PID 0xed74 +#define HAMEG_HO730_PID 0xed73 +#define HAMEG_HO720_PID 0xed72 +#define HAMEG_HO870_PID 0xed71 + +/* + * MaxStream devices www.maxstream.net + */ +#define FTDI_MAXSTREAM_PID 0xEE18 /* Xbee PKG-U Module */ + +/* + * microHAM product IDs (http://www.microham.com). + * Submitted by Justin Burket (KL1RL) <zorton@jtan.com> + * and Mike Studer (K6EEP) <k6eep@hamsoftware.org>. + * Ian Abbott <abbotti@mev.co.uk> added a few more from the driver INF file. + */ +#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */ +#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */ +#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */ +#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */ +#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */ +#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */ +#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */ +#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */ + +/* Domintell products http://www.domintell.com */ +#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */ +#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */ + +/* + * The following are the values for the Perle Systems + * UltraPort USB serial converters + */ +#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0 /* Perle UltraPort Product Id */ + +/* Sprog II (Andrew Crosland's SprogII DCC interface) */ +#define FTDI_SPROG_II 0xF0C8 + +/* an infrared receiver for user access control with IR tags */ +#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ + +/* ACT Solutions HomePro ZWave interface + (http://www.act-solutions.com/HomePro-Product-Matrix.html) */ +#define FTDI_ACTZWAVE_PID 0xF2D0 + +/* + * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485, + * USB-TTY aktiv, USB-TTY passiv. Some PIDs are used by several devices + * and I'm not entirely sure which are used by which. + */ +#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 +#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 +#define FTDI_4N_GALAXY_DE_3_PID 0xF3C2 + +/* + * Linx Technologies product ids + */ +#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */ +#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */ +#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */ +#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ +#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ + +/* + * Oceanic product ids + */ +#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */ + +/* + * SUUNTO product ids + */ +#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */ + +/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */ +/* http://www.usbuirt.com/ */ +#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ + +/* CCS Inc. ICDU/ICDU40 product ID - + * the FT232BM is used in an in-circuit-debugger unit for PIC16's/PIC18's */ +#define FTDI_CCSICDU20_0_PID 0xF9D0 +#define FTDI_CCSICDU40_1_PID 0xF9D1 +#define FTDI_CCSMACHX_2_PID 0xF9D2 +#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3 +#define FTDI_CCSICDU64_4_PID 0xF9D4 +#define FTDI_CCSPRIME8_5_PID 0xF9D5 + +/* + * The following are the values for the Matrix Orbital LCD displays, + * which are the FT232BM ( similar to the 8U232AM ) + */ +#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ + +/* + * Home Electronics (www.home-electro.com) USB gadgets + */ +#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */ + +/* Inside Accesso contactless reader (http://www.insidecontactless.com/) */ +#define INSIDE_ACCESSO 0xFAD0 + +/* + * ThorLabs USB motor drivers + */ +#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */ + +/* + * Protego product ids + */ +#define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */ +#define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */ +#define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */ +#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ + +/* + * Sony Ericsson product ids + */ +#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */ +#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */ +#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */ + +/* www.irtrans.de device */ +#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ + +/* + * RM Michaelides CANview USB (http://www.rmcan.com) (FTDI_VID) + * CAN fieldbus interface adapter, added by port GmbH www.port.de) + * Ian Abbott changed the macro names for consistency. + */ +#define FTDI_RM_CANVIEW_PID 0xfd60 /* Product Id */ +/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */ +#define FTDI_TTUSB_PID 0xFF20 /* Product Id */ + +#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 (FTDI_VID) */ + +#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ + +/* + * PCDJ use ftdi based dj-controllers. The following PID is + * for their DAC-2 device http://www.pcdjhardware.com/DAC2.asp + * (the VID is the standard ftdi vid (FTDI_VID), PID sent by Wouter Paesen) + */ +#define FTDI_PCDJ_DAC2_PID 0xFA88 + +#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG (FTDI_VID) */ + +/* + * DIEBOLD BCS SE923 (FTDI_VID) + */ +#define DIEBOLD_BCS_SE923_PID 0xfb99 + +/* www.crystalfontz.com devices + * - thanx for providing free devices for evaluation ! + * they use the ftdi chipset for the USB interface + * and the vendor id is the same + */ +#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */ +#define FTDI_XF_634_PID 0xFC09 /* 634: 20x4 Character Display */ +#define FTDI_XF_547_PID 0xFC0A /* 547: Two line Display */ +#define FTDI_XF_633_PID 0xFC0B /* 633: 16x2 Character Display with Keys */ +#define FTDI_XF_631_PID 0xFC0C /* 631: 20x2 Character Display */ +#define FTDI_XF_635_PID 0xFC0D /* 635: 20x4 Character Display */ +#define FTDI_XF_640_PID 0xFC0E /* 640: Two line Display */ +#define FTDI_XF_642_PID 0xFC0F /* 642: Two line Display */ + +/* + * Video Networks Limited / Homechoice in the UK use an ftdi-based device + * for their 1Mb broadband internet service. The following PID is exhibited + * by the usb device supplied (the VID is the standard ftdi vid (FTDI_VID) + */ +#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */ + +/* AlphaMicro Components AMC-232USB01 device (FTDI_VID) */ +#define FTDI_AMC232_PID 0xFF00 /* Product Id */ + +/* + * IBS elektronik product ids (FTDI_VID) + * Submitted by Thomas Schleusener + */ +#define FTDI_IBS_US485_PID 0xff38 /* IBS US485 (USB<-->RS422/485 interface) */ +#define FTDI_IBS_PICPRO_PID 0xff39 /* IBS PIC-Programmer */ +#define FTDI_IBS_PCMCIA_PID 0xff3a /* IBS Card reader for PCMCIA SRAM-cards */ +#define FTDI_IBS_PK1_PID 0xff3b /* IBS PK1 - Particel counter */ +#define FTDI_IBS_RS232MON_PID 0xff3c /* IBS RS232 - Monitor */ +#define FTDI_IBS_APP70_PID 0xff3d /* APP 70 (dust monitoring system) */ +#define FTDI_IBS_PEDO_PID 0xff3e /* IBS PEDO-Modem (RF modem 868.35 MHz) */ +#define FTDI_IBS_PROD_PID 0xff3f /* future device */ +/* www.canusb.com Lawicel CANUSB device (FTDI_VID) */ +#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ + +/* + * TavIR AVR product ids (FTDI_VID) + */ +#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */ + +/* + * TIAO product ids (FTDI_VID) + * http://www.tiaowiki.com/w/Main_Page + */ +#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */ + + +/********************************/ +/** third-party VID/PID combos **/ +/********************************/ + + + +/* + * Atmel STK541 + */ +#define ATMEL_VID 0x03eb /* Vendor ID */ +#define STK541_PID 0x2109 /* Zigbee Controller */ + +/* + * Blackfin gnICE JTAG + * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice + */ +#define ADI_VID 0x0456 +#define ADI_GNICE_PID 0xF000 +#define ADI_GNICEPLUS_PID 0xF001 + +/* + * Microchip Technology, Inc. + * + * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are + * used by single function CDC ACM class based firmware demo + * applications. The VID/PID has also been used in firmware + * emulating FTDI serial chips by: + * Hornby Elite - Digital Command Control Console + * http://www.hornby.com/hornby-dcc/controllers/ + */ +#define MICROCHIP_VID 0x04D8 +#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */ + +/* + * RATOC REX-USB60F + */ +#define RATOC_VENDOR_ID 0x0584 +#define RATOC_PRODUCT_ID_USB60F 0xb020 + +/* + * Acton Research Corp. + */ +#define ACTON_VID 0x0647 /* Vendor ID */ +#define ACTON_SPECTRAPRO_PID 0x0100 + +/* + * Contec products (http://www.contec.com) + * Submitted by Daniel Sangorrin + */ +#define CONTEC_VID 0x06CE /* Vendor ID */ +#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ + +/* + * Definitions for B&B Electronics products. + */ +#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */ +#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */ +#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */ +#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */ +#define BANDB_USOPTL4_PID 0xAC11 +#define BANDB_USPTL4_PID 0xAC12 +#define BANDB_USO9ML2DR_2_PID 0xAC16 +#define BANDB_USO9ML2DR_PID 0xAC17 +#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */ +#define BANDB_USOPTL4DR_PID 0xAC19 +#define BANDB_485USB9F_2W_PID 0xAC25 +#define BANDB_485USB9F_4W_PID 0xAC26 +#define BANDB_232USB9M_PID 0xAC27 +#define BANDB_485USBTB_2W_PID 0xAC33 +#define BANDB_485USBTB_4W_PID 0xAC34 +#define BANDB_TTL5USB9M_PID 0xAC49 +#define BANDB_TTL3USB9M_PID 0xAC50 +#define BANDB_ZZ_PROG1_USB_PID 0xBA02 + +/* + * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI + */ +#define INTREPID_VID 0x093C +#define INTREPID_VALUECAN_PID 0x0601 +#define INTREPID_NEOVI_PID 0x0701 + +/* + * Definitions for ID TECH (www.idt-net.com) devices + */ +#define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */ +#define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */ + +/* + * Definitions for Omnidirectional Control Technology, Inc. devices + */ +#define OCT_VID 0x0B39 /* OCT vendor ID */ +/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */ +/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */ +/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */ +#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */ +#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */ + +/* + * Definitions for Icom Inc. devices + */ +#define ICOM_VID 0x0C26 /* Icom vendor ID */ +/* Note: ID-1 is a communications tranceiver for HAM-radio operators */ +#define ICOM_ID_1_PID 0x0004 /* ID-1 USB to RS-232 */ +/* Note: OPC is an Optional cable to connect an Icom Tranceiver */ +#define ICOM_OPC_U_UC_PID 0x0018 /* OPC-478UC, OPC-1122U cloning cable */ +/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */ +#define ICOM_ID_RP2C1_PID 0x0009 /* ID-RP2C Asset 1 to RS-232 */ +#define ICOM_ID_RP2C2_PID 0x000A /* ID-RP2C Asset 2 to RS-232 */ +#define ICOM_ID_RP2D_PID 0x000B /* ID-RP2D configuration port*/ +#define ICOM_ID_RP2VT_PID 0x000C /* ID-RP2V Transmit config port */ +#define ICOM_ID_RP2VR_PID 0x000D /* ID-RP2V Receive config port */ +#define ICOM_ID_RP4KVT_PID 0x0010 /* ID-RP4000V Transmit config port */ +#define ICOM_ID_RP4KVR_PID 0x0011 /* ID-RP4000V Receive config port */ +#define ICOM_ID_RP2KVT_PID 0x0012 /* ID-RP2000V Transmit config port */ +#define ICOM_ID_RP2KVR_PID 0x0013 /* ID-RP2000V Receive config port */ + +/* + * GN Otometrics (http://www.otometrics.com) + * Submitted by Ville Sundberg. + */ +#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */ +#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */ + +/* + * The following are the values for the Sealevel SeaLINK+ adapters. + * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and + * removed some PIDs that don't seem to match any existing products.) + */ +#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */ +#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */ +#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */ +#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */ +#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */ +#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */ +#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */ +#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */ +#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */ +#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */ +#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */ +#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */ +#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */ +#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */ +#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */ +#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */ +#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */ +#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */ +#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */ +#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */ +#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */ +#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */ +#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */ +#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */ +#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */ +#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */ +#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */ +#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */ +#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */ +#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */ +#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */ +#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */ +#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */ +#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */ +#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */ +#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */ +#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */ +#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */ +#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */ +#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */ +#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */ +#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */ +#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */ +#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */ +#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */ +#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ +#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ +#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ +#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */ +#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */ +#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */ +#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */ + +/* + * JETI SPECTROMETER SPECBOS 1201 + * http://www.jeti.com/cms/index.php/instruments/other-instruments/specbos-2101 + */ +#define JETI_VID 0x0c6c +#define JETI_SPC1201_PID 0x04b2 + +/* + * FTDI USB UART chips used in construction projects from the + * Elektor Electronics magazine (http://www.elektor.com/) + */ +#define ELEKTOR_VID 0x0C7D +#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */ + +/* + * Posiflex inc retail equipment (http://www.posiflex.com.tw) + */ +#define POSIFLEX_VID 0x0d3a /* Vendor ID */ +#define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */ + +/* + * The following are the values for two KOBIL chipcard terminals. + */ +#define KOBIL_VID 0x0d46 /* KOBIL Vendor ID */ +#define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */ +#define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */ + +#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ +#define FTDI_NF_RIC_PID 0x0001 /* Product Id */ + +/* + * Falcom Wireless Communications GmbH + */ +#define FALCOM_VID 0x0F94 /* Vendor Id */ +#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */ +#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */ + +/* Larsen and Brusgaard AltiTrack/USBtrack */ +#define LARSENBRUSGAARD_VID 0x0FD8 +#define LB_ALTITRACK_PID 0x0001 + +/* + * TTi (Thurlby Thandar Instruments) + */ +#define TTI_VID 0x103E /* Vendor Id */ +#define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */ + +/* Interbiometrics USB I/O Board */ +/* Developed for Interbiometrics by Rudolf Gugler */ +#define INTERBIOMETRICS_VID 0x1209 +#define INTERBIOMETRICS_IOBOARD_PID 0x1002 +#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006 + +/* + * Testo products (http://www.testo.com/) + * Submitted by Colin Leroy + */ +#define TESTO_VID 0x128D +#define TESTO_USB_INTERFACE_PID 0x0001 + +/* + * Mobility Electronics products. + */ +#define MOBILITY_VID 0x1342 +#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */ + +/* + * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3 + * Submitted by Harald Welte <laforge@openmoko.org> + */ +#define FIC_VID 0x1457 +#define FIC_NEO1973_DEBUG_PID 0x5118 + +/* Olimex */ +#define OLIMEX_VID 0x15BA +#define OLIMEX_ARM_USB_OCD_PID 0x0003 +#define OLIMEX_ARM_USB_OCD_H_PID 0x002b + +/* + * Telldus Technologies + */ +#define TELLDUS_VID 0x1781 /* Vendor ID */ +#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */ + +/* + * RT Systems programming cables for various ham radios + */ +#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ +#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ +#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ +#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */ + + +/* + * Physik Instrumente + * http://www.physikinstrumente.com/en/products/ + */ +/* These two devices use the VID of FTDI */ +#define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */ +#define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */ + +#define PI_VID 0x1a72 /* Vendor ID */ +#define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */ +#define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */ +#define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */ +#define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */ +#define PI_C863_PID 0x1007 /* PI C-863 */ +#define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */ +#define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */ +#define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */ +#define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */ +#define PI_100F_PID 0x100F /* PI Digital Piezo Controller */ +#define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */ +#define PI_1012_PID 0x1012 /* PI Motion Controller */ +#define PI_1013_PID 0x1013 /* PI Motion Controller */ +#define PI_1014_PID 0x1014 /* PI Device */ +#define PI_1015_PID 0x1015 /* PI Device */ +#define PI_1016_PID 0x1016 /* PI Digital Servo Module */ + +/* + * Kondo Kagaku Co.Ltd. + * http://www.kondo-robot.com/EN + */ +#define KONDO_VID 0x165c +#define KONDO_USB_SERIAL_PID 0x0002 + +/* + * Bayer Ascensia Contour blood glucose meter USB-converter cable. + * http://winglucofacts.com/cables/ + */ +#define BAYER_VID 0x1A79 +#define BAYER_CONTOUR_CABLE_PID 0x6001 + +/* + * The following are the values for the Matrix Orbital FTDI Range + * Anything in this range will use an FT232RL. + */ +#define MTXORB_VID 0x1B3D +#define MTXORB_FTDI_RANGE_0100_PID 0x0100 +#define MTXORB_FTDI_RANGE_0101_PID 0x0101 +#define MTXORB_FTDI_RANGE_0102_PID 0x0102 +#define MTXORB_FTDI_RANGE_0103_PID 0x0103 +#define MTXORB_FTDI_RANGE_0104_PID 0x0104 +#define MTXORB_FTDI_RANGE_0105_PID 0x0105 +#define MTXORB_FTDI_RANGE_0106_PID 0x0106 +#define MTXORB_FTDI_RANGE_0107_PID 0x0107 +#define MTXORB_FTDI_RANGE_0108_PID 0x0108 +#define MTXORB_FTDI_RANGE_0109_PID 0x0109 +#define MTXORB_FTDI_RANGE_010A_PID 0x010A +#define MTXORB_FTDI_RANGE_010B_PID 0x010B +#define MTXORB_FTDI_RANGE_010C_PID 0x010C +#define MTXORB_FTDI_RANGE_010D_PID 0x010D +#define MTXORB_FTDI_RANGE_010E_PID 0x010E +#define MTXORB_FTDI_RANGE_010F_PID 0x010F +#define MTXORB_FTDI_RANGE_0110_PID 0x0110 +#define MTXORB_FTDI_RANGE_0111_PID 0x0111 +#define MTXORB_FTDI_RANGE_0112_PID 0x0112 +#define MTXORB_FTDI_RANGE_0113_PID 0x0113 +#define MTXORB_FTDI_RANGE_0114_PID 0x0114 +#define MTXORB_FTDI_RANGE_0115_PID 0x0115 +#define MTXORB_FTDI_RANGE_0116_PID 0x0116 +#define MTXORB_FTDI_RANGE_0117_PID 0x0117 +#define MTXORB_FTDI_RANGE_0118_PID 0x0118 +#define MTXORB_FTDI_RANGE_0119_PID 0x0119 +#define MTXORB_FTDI_RANGE_011A_PID 0x011A +#define MTXORB_FTDI_RANGE_011B_PID 0x011B +#define MTXORB_FTDI_RANGE_011C_PID 0x011C +#define MTXORB_FTDI_RANGE_011D_PID 0x011D +#define MTXORB_FTDI_RANGE_011E_PID 0x011E +#define MTXORB_FTDI_RANGE_011F_PID 0x011F +#define MTXORB_FTDI_RANGE_0120_PID 0x0120 +#define MTXORB_FTDI_RANGE_0121_PID 0x0121 +#define MTXORB_FTDI_RANGE_0122_PID 0x0122 +#define MTXORB_FTDI_RANGE_0123_PID 0x0123 +#define MTXORB_FTDI_RANGE_0124_PID 0x0124 +#define MTXORB_FTDI_RANGE_0125_PID 0x0125 +#define MTXORB_FTDI_RANGE_0126_PID 0x0126 +#define MTXORB_FTDI_RANGE_0127_PID 0x0127 +#define MTXORB_FTDI_RANGE_0128_PID 0x0128 +#define MTXORB_FTDI_RANGE_0129_PID 0x0129 +#define MTXORB_FTDI_RANGE_012A_PID 0x012A +#define MTXORB_FTDI_RANGE_012B_PID 0x012B +#define MTXORB_FTDI_RANGE_012C_PID 0x012C +#define MTXORB_FTDI_RANGE_012D_PID 0x012D +#define MTXORB_FTDI_RANGE_012E_PID 0x012E +#define MTXORB_FTDI_RANGE_012F_PID 0x012F +#define MTXORB_FTDI_RANGE_0130_PID 0x0130 +#define MTXORB_FTDI_RANGE_0131_PID 0x0131 +#define MTXORB_FTDI_RANGE_0132_PID 0x0132 +#define MTXORB_FTDI_RANGE_0133_PID 0x0133 +#define MTXORB_FTDI_RANGE_0134_PID 0x0134 +#define MTXORB_FTDI_RANGE_0135_PID 0x0135 +#define MTXORB_FTDI_RANGE_0136_PID 0x0136 +#define MTXORB_FTDI_RANGE_0137_PID 0x0137 +#define MTXORB_FTDI_RANGE_0138_PID 0x0138 +#define MTXORB_FTDI_RANGE_0139_PID 0x0139 +#define MTXORB_FTDI_RANGE_013A_PID 0x013A +#define MTXORB_FTDI_RANGE_013B_PID 0x013B +#define MTXORB_FTDI_RANGE_013C_PID 0x013C +#define MTXORB_FTDI_RANGE_013D_PID 0x013D +#define MTXORB_FTDI_RANGE_013E_PID 0x013E +#define MTXORB_FTDI_RANGE_013F_PID 0x013F +#define MTXORB_FTDI_RANGE_0140_PID 0x0140 +#define MTXORB_FTDI_RANGE_0141_PID 0x0141 +#define MTXORB_FTDI_RANGE_0142_PID 0x0142 +#define MTXORB_FTDI_RANGE_0143_PID 0x0143 +#define MTXORB_FTDI_RANGE_0144_PID 0x0144 +#define MTXORB_FTDI_RANGE_0145_PID 0x0145 +#define MTXORB_FTDI_RANGE_0146_PID 0x0146 +#define MTXORB_FTDI_RANGE_0147_PID 0x0147 +#define MTXORB_FTDI_RANGE_0148_PID 0x0148 +#define MTXORB_FTDI_RANGE_0149_PID 0x0149 +#define MTXORB_FTDI_RANGE_014A_PID 0x014A +#define MTXORB_FTDI_RANGE_014B_PID 0x014B +#define MTXORB_FTDI_RANGE_014C_PID 0x014C +#define MTXORB_FTDI_RANGE_014D_PID 0x014D +#define MTXORB_FTDI_RANGE_014E_PID 0x014E +#define MTXORB_FTDI_RANGE_014F_PID 0x014F +#define MTXORB_FTDI_RANGE_0150_PID 0x0150 +#define MTXORB_FTDI_RANGE_0151_PID 0x0151 +#define MTXORB_FTDI_RANGE_0152_PID 0x0152 +#define MTXORB_FTDI_RANGE_0153_PID 0x0153 +#define MTXORB_FTDI_RANGE_0154_PID 0x0154 +#define MTXORB_FTDI_RANGE_0155_PID 0x0155 +#define MTXORB_FTDI_RANGE_0156_PID 0x0156 +#define MTXORB_FTDI_RANGE_0157_PID 0x0157 +#define MTXORB_FTDI_RANGE_0158_PID 0x0158 +#define MTXORB_FTDI_RANGE_0159_PID 0x0159 +#define MTXORB_FTDI_RANGE_015A_PID 0x015A +#define MTXORB_FTDI_RANGE_015B_PID 0x015B +#define MTXORB_FTDI_RANGE_015C_PID 0x015C +#define MTXORB_FTDI_RANGE_015D_PID 0x015D +#define MTXORB_FTDI_RANGE_015E_PID 0x015E +#define MTXORB_FTDI_RANGE_015F_PID 0x015F +#define MTXORB_FTDI_RANGE_0160_PID 0x0160 +#define MTXORB_FTDI_RANGE_0161_PID 0x0161 +#define MTXORB_FTDI_RANGE_0162_PID 0x0162 +#define MTXORB_FTDI_RANGE_0163_PID 0x0163 +#define MTXORB_FTDI_RANGE_0164_PID 0x0164 +#define MTXORB_FTDI_RANGE_0165_PID 0x0165 +#define MTXORB_FTDI_RANGE_0166_PID 0x0166 +#define MTXORB_FTDI_RANGE_0167_PID 0x0167 +#define MTXORB_FTDI_RANGE_0168_PID 0x0168 +#define MTXORB_FTDI_RANGE_0169_PID 0x0169 +#define MTXORB_FTDI_RANGE_016A_PID 0x016A +#define MTXORB_FTDI_RANGE_016B_PID 0x016B +#define MTXORB_FTDI_RANGE_016C_PID 0x016C +#define MTXORB_FTDI_RANGE_016D_PID 0x016D +#define MTXORB_FTDI_RANGE_016E_PID 0x016E +#define MTXORB_FTDI_RANGE_016F_PID 0x016F +#define MTXORB_FTDI_RANGE_0170_PID 0x0170 +#define MTXORB_FTDI_RANGE_0171_PID 0x0171 +#define MTXORB_FTDI_RANGE_0172_PID 0x0172 +#define MTXORB_FTDI_RANGE_0173_PID 0x0173 +#define MTXORB_FTDI_RANGE_0174_PID 0x0174 +#define MTXORB_FTDI_RANGE_0175_PID 0x0175 +#define MTXORB_FTDI_RANGE_0176_PID 0x0176 +#define MTXORB_FTDI_RANGE_0177_PID 0x0177 +#define MTXORB_FTDI_RANGE_0178_PID 0x0178 +#define MTXORB_FTDI_RANGE_0179_PID 0x0179 +#define MTXORB_FTDI_RANGE_017A_PID 0x017A +#define MTXORB_FTDI_RANGE_017B_PID 0x017B +#define MTXORB_FTDI_RANGE_017C_PID 0x017C +#define MTXORB_FTDI_RANGE_017D_PID 0x017D +#define MTXORB_FTDI_RANGE_017E_PID 0x017E +#define MTXORB_FTDI_RANGE_017F_PID 0x017F +#define MTXORB_FTDI_RANGE_0180_PID 0x0180 +#define MTXORB_FTDI_RANGE_0181_PID 0x0181 +#define MTXORB_FTDI_RANGE_0182_PID 0x0182 +#define MTXORB_FTDI_RANGE_0183_PID 0x0183 +#define MTXORB_FTDI_RANGE_0184_PID 0x0184 +#define MTXORB_FTDI_RANGE_0185_PID 0x0185 +#define MTXORB_FTDI_RANGE_0186_PID 0x0186 +#define MTXORB_FTDI_RANGE_0187_PID 0x0187 +#define MTXORB_FTDI_RANGE_0188_PID 0x0188 +#define MTXORB_FTDI_RANGE_0189_PID 0x0189 +#define MTXORB_FTDI_RANGE_018A_PID 0x018A +#define MTXORB_FTDI_RANGE_018B_PID 0x018B +#define MTXORB_FTDI_RANGE_018C_PID 0x018C +#define MTXORB_FTDI_RANGE_018D_PID 0x018D +#define MTXORB_FTDI_RANGE_018E_PID 0x018E +#define MTXORB_FTDI_RANGE_018F_PID 0x018F +#define MTXORB_FTDI_RANGE_0190_PID 0x0190 +#define MTXORB_FTDI_RANGE_0191_PID 0x0191 +#define MTXORB_FTDI_RANGE_0192_PID 0x0192 +#define MTXORB_FTDI_RANGE_0193_PID 0x0193 +#define MTXORB_FTDI_RANGE_0194_PID 0x0194 +#define MTXORB_FTDI_RANGE_0195_PID 0x0195 +#define MTXORB_FTDI_RANGE_0196_PID 0x0196 +#define MTXORB_FTDI_RANGE_0197_PID 0x0197 +#define MTXORB_FTDI_RANGE_0198_PID 0x0198 +#define MTXORB_FTDI_RANGE_0199_PID 0x0199 +#define MTXORB_FTDI_RANGE_019A_PID 0x019A +#define MTXORB_FTDI_RANGE_019B_PID 0x019B +#define MTXORB_FTDI_RANGE_019C_PID 0x019C +#define MTXORB_FTDI_RANGE_019D_PID 0x019D +#define MTXORB_FTDI_RANGE_019E_PID 0x019E +#define MTXORB_FTDI_RANGE_019F_PID 0x019F +#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0 +#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1 +#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2 +#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3 +#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4 +#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5 +#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6 +#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7 +#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8 +#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9 +#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA +#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB +#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC +#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD +#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE +#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF +#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0 +#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1 +#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2 +#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3 +#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4 +#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5 +#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6 +#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7 +#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8 +#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9 +#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA +#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB +#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC +#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD +#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE +#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF +#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0 +#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1 +#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2 +#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3 +#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4 +#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5 +#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6 +#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7 +#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8 +#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9 +#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA +#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB +#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC +#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD +#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE +#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF +#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0 +#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1 +#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2 +#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3 +#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4 +#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5 +#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6 +#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7 +#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8 +#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9 +#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA +#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB +#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC +#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD +#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE +#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF +#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0 +#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1 +#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2 +#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3 +#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4 +#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5 +#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6 +#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7 +#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8 +#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9 +#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA +#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB +#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC +#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED +#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE +#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF +#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0 +#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1 +#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2 +#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3 +#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4 +#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5 +#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6 +#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7 +#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8 +#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9 +#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA +#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB +#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC +#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD +#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE +#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF + + + +/* + * The Mobility Lab (TML) + * Submitted by Pierre Castella + */ +#define TML_VID 0x1B91 /* Vendor ID */ +#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */ + +/* Alti-2 products http://www.alti-2.com */ +#define ALTI2_VID 0x1BC9 +#define ALTI2_N3_PID 0x6001 /* Neptune 3 */ + +/* + * Ionics PlugComputer + */ +#define IONICS_VID 0x1c0c +#define IONICS_PLUGCOMPUTER_PID 0x0102 + +/* + * Dresden Elektronik Sensor Terminal Board + */ +#define DE_VID 0x1cf1 /* Vendor ID */ +#define STB_PID 0x0001 /* Sensor Terminal Board */ +#define WHT_PID 0x0004 /* Wireless Handheld Terminal */ + +/* + * STMicroelectonics + */ +#define ST_VID 0x0483 +#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */ + +/* + * Papouch products (http://www.papouch.com/) + * Submitted by Folkert van Heusden + */ + +#define PAPOUCH_VID 0x5050 /* Vendor ID */ +#define PAPOUCH_SB485_PID 0x0100 /* Papouch SB485 USB-485/422 Converter */ +#define PAPOUCH_AP485_PID 0x0101 /* AP485 USB-RS485 Converter */ +#define PAPOUCH_SB422_PID 0x0102 /* Papouch SB422 USB-RS422 Converter */ +#define PAPOUCH_SB485_2_PID 0x0103 /* Papouch SB485 USB-485/422 Converter */ +#define PAPOUCH_AP485_2_PID 0x0104 /* AP485 USB-RS485 Converter */ +#define PAPOUCH_SB422_2_PID 0x0105 /* Papouch SB422 USB-RS422 Converter */ +#define PAPOUCH_SB485S_PID 0x0106 /* Papouch SB485S USB-485/422 Converter */ +#define PAPOUCH_SB485C_PID 0x0107 /* Papouch SB485C USB-485/422 Converter */ +#define PAPOUCH_LEC_PID 0x0300 /* LEC USB Converter */ +#define PAPOUCH_SB232_PID 0x0301 /* Papouch SB232 USB-RS232 Converter */ +#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */ +#define PAPOUCH_IRAMP_PID 0x0500 /* Papouch IRAmp Duplex */ +#define PAPOUCH_DRAK5_PID 0x0700 /* Papouch DRAK5 */ +#define PAPOUCH_QUIDO8x8_PID 0x0800 /* Papouch Quido 8/8 Module */ +#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Papouch Quido 4/4 Module */ +#define PAPOUCH_QUIDO2x2_PID 0x0a00 /* Papouch Quido 2/2 Module */ +#define PAPOUCH_QUIDO10x1_PID 0x0b00 /* Papouch Quido 10/1 Module */ +#define PAPOUCH_QUIDO30x3_PID 0x0c00 /* Papouch Quido 30/3 Module */ +#define PAPOUCH_QUIDO60x3_PID 0x0d00 /* Papouch Quido 60(100)/3 Module */ +#define PAPOUCH_QUIDO2x16_PID 0x0e00 /* Papouch Quido 2/16 Module */ +#define PAPOUCH_QUIDO3x32_PID 0x0f00 /* Papouch Quido 3/32 Module */ +#define PAPOUCH_DRAK6_PID 0x1000 /* Papouch DRAK6 */ +#define PAPOUCH_UPSUSB_PID 0x8000 /* Papouch UPS-USB adapter */ +#define PAPOUCH_MU_PID 0x8001 /* MU controller */ +#define PAPOUCH_SIMUKEY_PID 0x8002 /* Papouch SimuKey */ +#define PAPOUCH_AD4USB_PID 0x8003 /* AD4USB Measurement Module */ +#define PAPOUCH_GMUX_PID 0x8004 /* Papouch GOLIATH MUX */ +#define PAPOUCH_GMSR_PID 0x8005 /* Papouch GOLIATH MSR */ + +/* + * Marvell SheevaPlug + */ +#define MARVELL_VID 0x9e88 +#define MARVELL_SHEEVAPLUG_PID 0x9e8f + +/* + * Evolution Robotics products (http://www.evolution.com/). + * Submitted by Shawn M. Lavelle. + */ +#define EVOLUTION_VID 0xDEEE /* Vendor ID */ +#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */ +#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/ +#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/ +#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */ + +/* + * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403) + */ +#define MJSG_GENERIC_PID 0x9378 +#define MJSG_SR_RADIO_PID 0x9379 +#define MJSG_XM_RADIO_PID 0x937A +#define MJSG_HD_RADIO_PID 0x937C + +/* + * D.O.Tec products (http://www.directout.eu) + */ +#define FTDI_DOTEC_PID 0x9868 + +/* + * Xverve Signalyzer tools (http://www.signalyzer.com/) + */ +#define XVERVE_SIGNALYZER_ST_PID 0xBCA0 +#define XVERVE_SIGNALYZER_SLITE_PID 0xBCA1 +#define XVERVE_SIGNALYZER_SH2_PID 0xBCA2 +#define XVERVE_SIGNALYZER_SH4_PID 0xBCA4 + +/* + * Segway Robotic Mobility Platform USB interface (using VID 0x0403) + * Submitted by John G. Rogers + */ +#define SEGWAY_RMP200_PID 0xe729 + + +/* + * Accesio USB Data Acquisition products (http://www.accesio.com/) + */ +#define ACCESIO_COM4SM_PID 0xD578 + +/* www.sciencescope.co.uk educational dataloggers */ +#define FTDI_SCIENCESCOPE_LOGBOOKML_PID 0xFF18 +#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C +#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D + +/* + * Milkymist One JTAG/Serial + */ +#define QIHARDWARE_VID 0x20B7 +#define MILKYMISTONE_JTAGSERIAL_PID 0x0713 + +/* + * CTI GmbH RS485 Converter http://www.cti-lean.com/ + */ +/* USB-485-Mini*/ +#define FTDI_CTI_MINI_PID 0xF608 +/* USB-Nano-485*/ +#define FTDI_CTI_NANO_PID 0xF60B + +/* + * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de + */ +/* TagTracer MIFARE*/ +#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 + +/* + * Rainforest Automation + */ +/* ZigBee controller */ +#define FTDI_RF_R106 0x8A28 + +/* + * Product: HCP HIT GPRS modem + * Manufacturer: HCP d.o.o. + * ATI command output: Cinterion MC55i + */ +#define FTDI_CINTERION_MC55I_PID 0xA951 diff --git a/hw/usb/quirks-pl2303-ids.h b/hw/usb/quirks-pl2303-ids.h new file mode 100644 index 0000000000..8dbdb46ffe --- /dev/null +++ b/hw/usb/quirks-pl2303-ids.h @@ -0,0 +1,150 @@ +/* + * Prolific PL2303 USB to serial adaptor driver header file + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#define BENQ_VENDOR_ID 0x04a5 +#define BENQ_PRODUCT_ID_S81 0x4027 + +#define PL2303_VENDOR_ID 0x067b +#define PL2303_PRODUCT_ID 0x2303 +#define PL2303_PRODUCT_ID_RSAQ2 0x04bb +#define PL2303_PRODUCT_ID_DCU11 0x1234 +#define PL2303_PRODUCT_ID_PHAROS 0xaaa0 +#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 +#define PL2303_PRODUCT_ID_ALDIGA 0x0611 +#define PL2303_PRODUCT_ID_MMX 0x0612 +#define PL2303_PRODUCT_ID_GPRS 0x0609 +#define PL2303_PRODUCT_ID_HCR331 0x331a +#define PL2303_PRODUCT_ID_MOTOROLA 0x0307 + +#define ATEN_VENDOR_ID 0x0557 +#define ATEN_VENDOR_ID2 0x0547 +#define ATEN_PRODUCT_ID 0x2008 + +#define IODATA_VENDOR_ID 0x04bb +#define IODATA_PRODUCT_ID 0x0a03 +#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e + +#define ELCOM_VENDOR_ID 0x056e +#define ELCOM_PRODUCT_ID 0x5003 +#define ELCOM_PRODUCT_ID_UCSGT 0x5004 + +#define ITEGNO_VENDOR_ID 0x0eba +#define ITEGNO_PRODUCT_ID 0x1080 +#define ITEGNO_PRODUCT_ID_2080 0x2080 + +#define MA620_VENDOR_ID 0x0df7 +#define MA620_PRODUCT_ID 0x0620 + +#define RATOC_VENDOR_ID 0x0584 +#define RATOC_PRODUCT_ID 0xb000 + +#define TRIPP_VENDOR_ID 0x2478 +#define TRIPP_PRODUCT_ID 0x2008 + +#define RADIOSHACK_VENDOR_ID 0x1453 +#define RADIOSHACK_PRODUCT_ID 0x4026 + +#define DCU10_VENDOR_ID 0x0731 +#define DCU10_PRODUCT_ID 0x0528 + +#define SITECOM_VENDOR_ID 0x6189 +#define SITECOM_PRODUCT_ID 0x2068 + +/* Alcatel OT535/735 USB cable */ +#define ALCATEL_VENDOR_ID 0x11f7 +#define ALCATEL_PRODUCT_ID 0x02df + +/* Samsung I330 phone cradle */ +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_ID 0x8001 + +#define SIEMENS_VENDOR_ID 0x11f5 +#define SIEMENS_PRODUCT_ID_SX1 0x0001 +#define SIEMENS_PRODUCT_ID_X65 0x0003 +#define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 + +#define SYNTECH_VENDOR_ID 0x0745 +#define SYNTECH_PRODUCT_ID 0x0001 + +/* Nokia CA-42 Cable */ +#define NOKIA_CA42_VENDOR_ID 0x078b +#define NOKIA_CA42_PRODUCT_ID 0x1234 + +/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */ +#define CA_42_CA42_VENDOR_ID 0x10b5 +#define CA_42_CA42_PRODUCT_ID 0xac70 + +#define SAGEM_VENDOR_ID 0x079b +#define SAGEM_PRODUCT_ID 0x0027 + +/* Leadtek GPS 9531 (ID 0413:2101) */ +#define LEADTEK_VENDOR_ID 0x0413 +#define LEADTEK_9531_PRODUCT_ID 0x2101 + +/* USB GSM cable from Speed Dragon Multimedia, Ltd */ +#define SPEEDDRAGON_VENDOR_ID 0x0e55 +#define SPEEDDRAGON_PRODUCT_ID 0x110b + +/* DATAPILOT Universal-2 Phone Cable */ +#define DATAPILOT_U2_VENDOR_ID 0x0731 +#define DATAPILOT_U2_PRODUCT_ID 0x2003 + +/* Belkin "F5U257" Serial Adapter */ +#define BELKIN_VENDOR_ID 0x050d +#define BELKIN_PRODUCT_ID 0x0257 + +/* Alcor Micro Corp. USB 2.0 TO RS-232 */ +#define ALCOR_VENDOR_ID 0x058F +#define ALCOR_PRODUCT_ID 0x9720 + +/* Willcom WS002IN Data Driver (by NetIndex Inc.) */ +#define WS002IN_VENDOR_ID 0x11f6 +#define WS002IN_PRODUCT_ID 0x2001 + +/* Corega CG-USBRS232R Serial Adapter */ +#define COREGA_VENDOR_ID 0x07aa +#define COREGA_PRODUCT_ID 0x002a + +/* Y.C. Cable U.S.A., Inc - USB to RS-232 */ +#define YCCABLE_VENDOR_ID 0x05ad +#define YCCABLE_PRODUCT_ID 0x0fba + +/* "Superial" USB - Serial */ +#define SUPERIAL_VENDOR_ID 0x5372 +#define SUPERIAL_PRODUCT_ID 0x2303 + +/* Hewlett-Packard LD220-HP POS Pole Display */ +#define HP_VENDOR_ID 0x03f0 +#define HP_LD220_PRODUCT_ID 0x3524 + +/* Cressi Edy (diving computer) PC interface */ +#define CRESSI_VENDOR_ID 0x04b8 +#define CRESSI_EDY_PRODUCT_ID 0x0521 + +/* Zeagle dive computer interface */ +#define ZEAGLE_VENDOR_ID 0x04b8 +#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 + +/* Sony, USB data cable for CMD-Jxx mobile phones */ +#define SONY_VENDOR_ID 0x054c +#define SONY_QN3USB_PRODUCT_ID 0x0437 + +/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */ +#define SANWA_VENDOR_ID 0x11ad +#define SANWA_PRODUCT_ID 0x0001 + +/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ +#define ADLINK_VENDOR_ID 0x0b63 +#define ADLINK_ND6530_PRODUCT_ID 0x6530 + +/* SMART USB Serial Adapter */ +#define SMART_VENDOR_ID 0x0b8c +#define SMART_PRODUCT_ID 0x2303 diff --git a/hw/usb/quirks.c b/hw/usb/quirks.c new file mode 100644 index 0000000000..a761a96032 --- /dev/null +++ b/hw/usb/quirks.c @@ -0,0 +1,53 @@ +/* + * USB quirk handling + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Red Hat Authors: + * Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "quirks.h" +#include "hw/usb.h" + +static bool usb_id_match(const struct usb_device_id *ids, + uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol) { + int i; + + for (i = 0; ids[i].vendor_id != -1; i++) { + if (ids[i].vendor_id == vendor_id && + ids[i].product_id == product_id && + (ids[i].interface_class == -1 || + (ids[i].interface_class == interface_class && + ids[i].interface_subclass == interface_subclass && + ids[i].interface_protocol == interface_protocol))) { + return true; + } + } + return false; +} + +int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol) +{ + int quirks = 0; + + if (usb_id_match(usbredir_raw_serial_ids, vendor_id, product_id, + interface_class, interface_subclass, interface_protocol)) { + quirks |= USB_QUIRK_BUFFER_BULK_IN; + } + if (usb_id_match(usbredir_ftdi_serial_ids, vendor_id, product_id, + interface_class, interface_subclass, interface_protocol)) { + quirks |= USB_QUIRK_BUFFER_BULK_IN | USB_QUIRK_IS_FTDI; + } + + return quirks; +} diff --git a/hw/usb/quirks.h b/hw/usb/quirks.h new file mode 100644 index 0000000000..8dc6065527 --- /dev/null +++ b/hw/usb/quirks.h @@ -0,0 +1,910 @@ +/* + * USB quirk handling + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Red Hat Authors: + * Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* 1 on 1 copy of linux/drivers/usb/serial/ftdi_sio_ids.h */ +#include "quirks-ftdi-ids.h" +/* 1 on 1 copy of linux/drivers/usb/serial/pl2303.h */ +#include "quirks-pl2303-ids.h" + +struct usb_device_id { + int vendor_id; + int product_id; + int interface_class; + int interface_subclass; + int interface_protocol; +}; + +#define USB_DEVICE(vendor, product) \ + .vendor_id = vendor, .product_id = product, .interface_class = -1, + +#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, iclass, isubclass, iproto) \ + .vendor_id = vend, .product_id = prod, .interface_class = iclass, \ + .interface_subclass = isubclass, .interface_protocol = iproto + +static const struct usb_device_id usbredir_raw_serial_ids[] = { + /* + * Silicon Laboratories CP210x USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/cp210x.c + * + * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk) + */ + { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ + { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */ + { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ + { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ + { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ + { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ + { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ + { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ + { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ + { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ + { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ + { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ + { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ + { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ + { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ + { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */ + { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */ + { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */ + { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ + { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ + { USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */ + { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */ + { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ + { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */ + { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ + { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */ + { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ + { USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */ + { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ + { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ + { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ + { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ + { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ + { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ + { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ + { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ + { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ + { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ + { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */ + { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ + { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ + { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ + { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */ + { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ + { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ + { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ + { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ + { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ + { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */ + { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */ + { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ + { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ + { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ + { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ + { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ + { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ + { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ + { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ + { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ + { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ + { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ + { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ + { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ + { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ + { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ + { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ + { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ + { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ + { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ + { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ + { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ + { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ + { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ + { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ + { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ + { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ + { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ + { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */ + { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ + { USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */ + { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ + { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ + { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */ + { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ + { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ + { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ + { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ + { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ + { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ + { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ + { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ + { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ + { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */ + { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ + { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ + { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ + + /* + * Prolific pl2303 USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/pl2303.c + * + * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2003 IBM Corp. + */ + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, + { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, + { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, + { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, + { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, + { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, + { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, + { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, + { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, + { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, + { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, + { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, + { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ + { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, + { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, + { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, + { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, + { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, + { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, + { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, + { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, + { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, + { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, + { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, + { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, + { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, + { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, + { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, + { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, + { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, + + { USB_DEVICE(-1, -1) } /* Terminating Entry */ +}; + +static const struct usb_device_id usbredir_ftdi_serial_ids[] = { + /* + * FTDI USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/ftdi_sio.c + * + * Copyright (C) 2009 - 2010 + * Johan Hovold (jhovold@gmail.com) + * Copyright (C) 1999 - 2001 + * Greg Kroah-Hartman (greg@kroah.com) + * Bill Ryder (bryder@sgi.com) + * Copyright (C) 2002 + * Kuba Ober (kuba@mareimbrium.org) + */ + { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) }, + { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, + { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) }, + { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) }, + { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) }, + { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, + { USB_DEVICE(OCT_VID, OCT_US101_PID) }, + { USB_DEVICE(OCT_VID, OCT_DK201_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) }, + { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID) }, + /* + * ELV devices: + */ + { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) }, + { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, + { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, + { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, + { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) }, + { USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) }, + { USB_DEVICE(TTI_VID, TTI_QL355P_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, + { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, + { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) }, + { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, + { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_YS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_IC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_DB9_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_RS232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y9_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) }, + { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) }, + { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) }, + { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, + { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, + { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID) }, + { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, + { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, + { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID) }, + { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID) }, + { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, + { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, + + /* Papouch devices based on FTDI chip */ + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485S_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485C_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_LEC_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB232_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_IRAMP_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK5_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO8x8_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO10x1_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO30x3_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO60x3_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x16_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO3x32_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK6_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_UPSUSB_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_MU_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SIMUKEY_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMUX_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMSR_PID) }, + + { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) }, + { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) }, + { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) }, + { USB_DEVICE(ATMEL_VID, STK541_PID) }, + { USB_DEVICE(DE_VID, STB_PID) }, + { USB_DEVICE(DE_VID, WHT_PID) }, + { USB_DEVICE(ADI_VID, ADI_GNICE_PID) }, + { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID) }, + { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, + 0xff, 0xff, 0x00) }, + { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, + { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID) }, + { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, + { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(FTDI_VID, PI_C865_PID) }, + { USB_DEVICE(FTDI_VID, PI_C857_PID) }, + { USB_DEVICE(PI_VID, PI_C866_PID) }, + { USB_DEVICE(PI_VID, PI_C663_PID) }, + { USB_DEVICE(PI_VID, PI_C725_PID) }, + { USB_DEVICE(PI_VID, PI_E517_PID) }, + { USB_DEVICE(PI_VID, PI_C863_PID) }, + { USB_DEVICE(PI_VID, PI_E861_PID) }, + { USB_DEVICE(PI_VID, PI_C867_PID) }, + { USB_DEVICE(PI_VID, PI_E609_PID) }, + { USB_DEVICE(PI_VID, PI_E709_PID) }, + { USB_DEVICE(PI_VID, PI_100F_PID) }, + { USB_DEVICE(PI_VID, PI_1011_PID) }, + { USB_DEVICE(PI_VID, PI_1012_PID) }, + { USB_DEVICE(PI_VID, PI_1013_PID) }, + { USB_DEVICE(PI_VID, PI_1014_PID) }, + { USB_DEVICE(PI_VID, PI_1015_PID) }, + { USB_DEVICE(PI_VID, PI_1016_PID) }, + { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, + { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, + { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID) }, + { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID) }, + { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, + { USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) }, + { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, + { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) }, + { USB_DEVICE(ST_VID, ST_STMCLT1030_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, + { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, + + { USB_DEVICE(-1, -1) } /* Terminating Entry */ +}; + +#undef USB_DEVICE +#undef USB_DEVICE_AND_INTERFACE_INFO diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 0abe1ff4d1..8c0ead07c5 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -44,18 +44,26 @@ #define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */ #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) +#define USBEP2I(usb_ep) (((usb_ep)->pid == USB_TOKEN_IN) ? \ + ((usb_ep)->nr | 0x10) : ((usb_ep)->nr)) +#define I2USBEP(d, i) (usb_ep_get(&(d)->dev, \ + ((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \ + (i) & 0x0f)) typedef struct USBRedirDevice USBRedirDevice; -/* Struct to hold buffered packets (iso or int input packets) */ +/* Struct to hold buffered packets */ struct buf_packet { uint8_t *data; - int len; - int status; + void *free_on_destroy; + uint16_t len; + uint16_t offset; + uint8_t status; QTAILQ_ENTRY(buf_packet)next; }; struct endp_data { + USBRedirDevice *dev; uint8_t type; uint8_t interval; uint8_t interface; /* bInterfaceNumber this ep belongs to */ @@ -64,11 +72,14 @@ struct endp_data { uint8_t iso_error; /* For reporting iso errors to the HC */ uint8_t interrupt_started; uint8_t interrupt_error; + uint8_t bulk_receiving_enabled; + uint8_t bulk_receiving_started; uint8_t bufpq_prefilled; uint8_t bufpq_dropping_packets; QTAILQ_HEAD(, buf_packet) bufpq; int32_t bufpq_size; int32_t bufpq_target_size; + USBPacket *pending_async_packet; }; struct PacketIdQueueEntry { @@ -102,6 +113,7 @@ struct USBRedirDevice { struct endp_data endpoint[MAX_ENDPOINTS]; struct PacketIdQueue cancelled; struct PacketIdQueue already_in_flight; + void (*buffered_bulk_in_complete)(USBRedirDevice *, USBPacket *, uint8_t); /* Data for device filtering */ struct usb_redir_device_connect_header device_info; struct usb_redir_interface_info_header interface_info; @@ -129,6 +141,8 @@ static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, *interrupt_receiving_status); static void usbredir_bulk_streams_status(void *priv, uint64_t id, struct usb_redir_bulk_streams_status_header *bulk_streams_status); +static void usbredir_bulk_receiving_status(void *priv, uint64_t id, + struct usb_redir_bulk_receiving_status_header *bulk_receiving_status); static void usbredir_control_packet(void *priv, uint64_t id, struct usb_redir_control_packet_header *control_packet, uint8_t *data, int data_len); @@ -141,6 +155,9 @@ static void usbredir_iso_packet(void *priv, uint64_t id, static void usbredir_interrupt_packet(void *priv, uint64_t id, struct usb_redir_interrupt_packet_header *interrupt_header, uint8_t *data, int data_len); +static void usbredir_buffered_bulk_packet(void *priv, uint64_t id, + struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet, + uint8_t *data, int data_len); static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p, int status); @@ -314,12 +331,19 @@ static void packet_id_queue_empty(struct PacketIdQueue *q) static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + int i = USBEP2I(p->ep); if (p->combined) { usb_combined_packet_cancel(udev, p); return; } + if (dev->endpoint[i].pending_async_packet) { + assert(dev->endpoint[i].pending_async_packet == p); + dev->endpoint[i].pending_async_packet = NULL; + return; + } + packet_id_queue_add(&dev->cancelled, p->id); usbredirparser_send_cancel_data_packet(dev->parser, p->id); usbredirparser_do_write(dev->parser); @@ -338,6 +362,11 @@ static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, { static USBPacket *p; + /* async handled packets for bulk receiving eps do not count as inflight */ + if (dev->endpoint[USBEP2I(ep)].bulk_receiving_started) { + return; + } + QTAILQ_FOREACH(p, &ep->queue, queue) { /* Skip combined packets, except for the first */ if (p->combined && p != p->combined->first) { @@ -385,8 +414,8 @@ static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, return p; } -static void bufp_alloc(USBRedirDevice *dev, - uint8_t *data, int len, int status, uint8_t ep) +static void bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len, + uint8_t status, uint8_t ep, void *free_on_destroy) { struct buf_packet *bufp; @@ -410,7 +439,9 @@ static void bufp_alloc(USBRedirDevice *dev, bufp = g_malloc(sizeof(struct buf_packet)); bufp->data = data; bufp->len = len; + bufp->offset = 0; bufp->status = status; + bufp->free_on_destroy = free_on_destroy; QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); dev->endpoint[EP2I(ep)].bufpq_size++; } @@ -420,7 +451,7 @@ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp, { QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); dev->endpoint[EP2I(ep)].bufpq_size--; - free(bufp->data); + free(bufp->free_on_destroy); g_free(bufp); } @@ -571,19 +602,162 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) usbredir_free_bufpq(dev, ep); } +/* + * The usb-host may poll the endpoint faster then our guest, resulting in lots + * of smaller bulkp-s. The below buffered_bulk_in_complete* functions combine + * data from multiple bulkp-s into a single packet, avoiding bufpq overflows. + */ +static void usbredir_buffered_bulk_add_data_to_packet(USBRedirDevice *dev, + struct buf_packet *bulkp, int count, USBPacket *p, uint8_t ep) +{ + usb_packet_copy(p, bulkp->data + bulkp->offset, count); + bulkp->offset += count; + if (bulkp->offset == bulkp->len) { + /* Store status in the last packet with data from this bulkp */ + usbredir_handle_status(dev, p, bulkp->status); + bufp_free(dev, bulkp, ep); + } +} + +static void usbredir_buffered_bulk_in_complete_raw(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + struct buf_packet *bulkp; + int count; + + while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) && + p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) { + count = bulkp->len - bulkp->offset; + if (count > (p->iov.size - p->actual_length)) { + count = p->iov.size - p->actual_length; + } + usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep); + } +} + +static void usbredir_buffered_bulk_in_complete_ftdi(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; + uint8_t header[2] = { 0, 0 }; + struct buf_packet *bulkp; + int count; + + while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) && + p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) { + if (bulkp->len < 2) { + WARNING("malformed ftdi bulk in packet\n"); + bufp_free(dev, bulkp, ep); + continue; + } + + if ((p->actual_length % maxp) == 0) { + usb_packet_copy(p, bulkp->data, 2); + memcpy(header, bulkp->data, 2); + } else { + if (bulkp->data[0] != header[0] || bulkp->data[1] != header[1]) { + break; /* Different header, add to next packet */ + } + } + + if (bulkp->offset == 0) { + bulkp->offset = 2; /* Skip header */ + } + count = bulkp->len - bulkp->offset; + /* Must repeat the header at maxp interval */ + if (count > (maxp - (p->actual_length % maxp))) { + count = maxp - (p->actual_length % maxp); + } + usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep); + } +} + +static void usbredir_buffered_bulk_in_complete(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ + dev->buffered_bulk_in_complete(dev, p, ep); + DPRINTF("bulk-token-in ep %02X status %d len %d id %"PRIu64"\n", + ep, p->status, p->actual_length, p->id); +} + +static void usbredir_handle_buffered_bulk_in_data(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + /* Input bulk endpoint, buffered packet input */ + if (!dev->endpoint[EP2I(ep)].bulk_receiving_started) { + int bpt; + struct usb_redir_start_bulk_receiving_header start = { + .endpoint = ep, + .stream_id = 0, + .no_transfers = 5, + }; + /* Round bytes_per_transfer up to a multiple of max_packet_size */ + bpt = 512 + dev->endpoint[EP2I(ep)].max_packet_size - 1; + bpt /= dev->endpoint[EP2I(ep)].max_packet_size; + bpt *= dev->endpoint[EP2I(ep)].max_packet_size; + start.bytes_per_transfer = bpt; + /* No id, we look at the ep when receiving a status back */ + usbredirparser_send_start_bulk_receiving(dev->parser, 0, &start); + usbredirparser_do_write(dev->parser); + DPRINTF("bulk receiving started bytes/transfer %u count %d ep %02X\n", + start.bytes_per_transfer, start.no_transfers, ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 1; + /* We don't really want to drop bulk packets ever, but + having some upper limit to how much we buffer is good. */ + dev->endpoint[EP2I(ep)].bufpq_target_size = 5000; + dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; + } + + if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) { + DPRINTF("bulk-token-in ep %02X, no bulkp\n", ep); + assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL); + dev->endpoint[EP2I(ep)].pending_async_packet = p; + p->status = USB_RET_ASYNC; + return; + } + usbredir_buffered_bulk_in_complete(dev, p, ep); +} + +static void usbredir_stop_bulk_receiving(USBRedirDevice *dev, uint8_t ep) +{ + struct usb_redir_stop_bulk_receiving_header stop_bulk = { + .endpoint = ep, + .stream_id = 0, + }; + if (dev->endpoint[EP2I(ep)].bulk_receiving_started) { + usbredirparser_send_stop_bulk_receiving(dev->parser, 0, &stop_bulk); + DPRINTF("bulk receiving stopped ep %02X\n", ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 0; + } + usbredir_free_bufpq(dev, ep); +} + static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { struct usb_redir_bulk_packet_header bulk_packet; size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; - - DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id); + const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; if (usbredir_already_in_flight(dev, p->id)) { p->status = USB_RET_ASYNC; return; } + if (dev->endpoint[EP2I(ep)].bulk_receiving_enabled) { + if (size != 0 && (size % maxp) == 0) { + usbredir_handle_buffered_bulk_in_data(dev, p, ep); + return; + } + WARNING("bulk recv invalid size %zd ep %02x, disabling\n", size, ep); + assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL); + usbredir_stop_bulk_receiving(dev, ep); + dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0; + } + + DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id); + bulk_packet.endpoint = ep; bulk_packet.length = size; bulk_packet.stream_id = 0; @@ -720,9 +894,6 @@ static void usbredir_handle_data(USBDevice *udev, USBPacket *p) ERROR("handle_data called for control transfer on ep %02X\n", ep); p->status = USB_RET_NAK; break; - case USB_ENDPOINT_XFER_ISOC: - usbredir_handle_iso_data(dev, p, ep); - break; case USB_ENDPOINT_XFER_BULK: if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN && p->ep->pipeline) { @@ -731,6 +902,9 @@ static void usbredir_handle_data(USBDevice *udev, USBPacket *p) } usbredir_handle_bulk_data(dev, p, ep); break; + case USB_ENDPOINT_XFER_ISOC: + usbredir_handle_iso_data(dev, p, ep); + break; case USB_ENDPOINT_XFER_INT: if (ep & USB_DIR_IN) { usbredir_handle_interrupt_in_data(dev, p, ep); @@ -752,6 +926,36 @@ static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) } } +static void usbredir_stop_ep(USBRedirDevice *dev, int i) +{ + uint8_t ep = I2EP(i); + + switch (dev->endpoint[i].type) { + case USB_ENDPOINT_XFER_BULK: + if (ep & USB_DIR_IN) { + usbredir_stop_bulk_receiving(dev, ep); + } + break; + case USB_ENDPOINT_XFER_ISOC: + usbredir_stop_iso_stream(dev, ep); + break; + case USB_ENDPOINT_XFER_INT: + if (ep & USB_DIR_IN) { + usbredir_stop_interrupt_receiving(dev, ep); + } + break; + } + usbredir_free_bufpq(dev, ep); +} + +static void usbredir_ep_stopped(USBDevice *udev, USBEndpoint *uep) +{ + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + + usbredir_stop_ep(dev, USBEP2I(uep)); + usbredirparser_do_write(dev->parser); +} + static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p, int config) { @@ -761,17 +965,7 @@ static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p, DPRINTF("set config %d id %"PRIu64"\n", config, p->id); for (i = 0; i < MAX_ENDPOINTS; i++) { - switch (dev->endpoint[i].type) { - case USB_ENDPOINT_XFER_ISOC: - usbredir_stop_iso_stream(dev, I2EP(i)); - break; - case USB_ENDPOINT_XFER_INT: - if (i & 0x10) { - usbredir_stop_interrupt_receiving(dev, I2EP(i)); - } - break; - } - usbredir_free_bufpq(dev, I2EP(i)); + usbredir_stop_ep(dev, i); } set_config.configuration = config; @@ -799,17 +993,7 @@ static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, for (i = 0; i < MAX_ENDPOINTS; i++) { if (dev->endpoint[i].interface == interface) { - switch (dev->endpoint[i].type) { - case USB_ENDPOINT_XFER_ISOC: - usbredir_stop_iso_stream(dev, I2EP(i)); - break; - case USB_ENDPOINT_XFER_INT: - if (i & 0x10) { - usbredir_stop_interrupt_receiving(dev, I2EP(i)); - } - break; - } - usbredir_free_bufpq(dev, I2EP(i)); + usbredir_stop_ep(dev, i); } } @@ -931,10 +1115,12 @@ static void usbredir_create_parser(USBRedirDevice *dev) dev->parser->interrupt_receiving_status_func = usbredir_interrupt_receiving_status; dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; + dev->parser->bulk_receiving_status_func = usbredir_bulk_receiving_status; dev->parser->control_packet_func = usbredir_control_packet; dev->parser->bulk_packet_func = usbredir_bulk_packet; dev->parser->iso_packet_func = usbredir_iso_packet; dev->parser->interrupt_packet_func = usbredir_interrupt_packet; + dev->parser->buffered_bulk_packet_func = usbredir_buffered_bulk_packet; dev->read_buf = NULL; dev->read_buf_size = 0; @@ -943,6 +1129,7 @@ static void usbredir_create_parser(USBRedirDevice *dev) usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length); + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving); if (runstate_check(RUN_STATE_INMIGRATE)) { flags |= usbredirparser_fl_no_hello; @@ -970,6 +1157,8 @@ static void usbredir_do_attach(void *opaque) usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_ep_info_max_packet_size) && usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_32bits_bulk_length) && + usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_64bits_ids))) { ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n"); usbredir_reject_device(dev); @@ -1051,6 +1240,18 @@ static void usbredir_vm_state_change(void *priv, int running, RunState state) } } +static void usbredir_init_endpoints(USBRedirDevice *dev) +{ + int i; + + usb_ep_init(&dev->dev); + memset(dev->endpoint, 0, sizeof(dev->endpoint)); + for (i = 0; i < MAX_ENDPOINTS; i++) { + dev->endpoint[i].dev = dev; + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +} + static int usbredir_initfn(USBDevice *udev) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); @@ -1077,9 +1278,7 @@ static int usbredir_initfn(USBDevice *udev) packet_id_queue_init(&dev->cancelled, dev, "cancelled"); packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } + usbredir_init_endpoints(dev); /* We'll do the attach once we receive the speed from the usb-host */ udev->auto_attach = 0; @@ -1169,6 +1368,52 @@ error: return -1; } +static void usbredir_check_bulk_receiving(USBRedirDevice *dev) +{ + int i, j, quirks; + + if (!usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_bulk_receiving)) { + return; + } + + for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) { + dev->endpoint[i].bulk_receiving_enabled = 0; + } + for (i = 0; i < dev->interface_info.interface_count; i++) { + quirks = usb_get_quirks(dev->device_info.vendor_id, + dev->device_info.product_id, + dev->interface_info.interface_class[i], + dev->interface_info.interface_subclass[i], + dev->interface_info.interface_protocol[i]); + if (!(quirks & USB_QUIRK_BUFFER_BULK_IN)) { + continue; + } + if (quirks & USB_QUIRK_IS_FTDI) { + dev->buffered_bulk_in_complete = + usbredir_buffered_bulk_in_complete_ftdi; + } else { + dev->buffered_bulk_in_complete = + usbredir_buffered_bulk_in_complete_raw; + } + + for (j = EP2I(USB_DIR_IN); j < MAX_ENDPOINTS; j++) { + if (dev->endpoint[j].interface == + dev->interface_info.interface[i] && + dev->endpoint[j].type == USB_ENDPOINT_XFER_BULK && + dev->endpoint[j].max_packet_size != 0) { + dev->endpoint[j].bulk_receiving_enabled = 1; + /* + * With buffering pipelining is not necessary. Also packet + * combining and bulk in buffering don't play nice together! + */ + I2USBEP(dev, j)->pipeline = false; + break; /* Only buffer for the first ep of each intf */ + } + } + } +} + /* * usbredirparser packet complete callbacks */ @@ -1277,13 +1522,13 @@ static void usbredir_device_connect(void *priv, return; } + usbredir_check_bulk_receiving(dev); qemu_mod_timer(dev->attach_timer, dev->next_attach_time); } static void usbredir_device_disconnect(void *priv) { USBRedirDevice *dev = priv; - int i; /* Stop any pending attaches */ qemu_del_timer(dev->attach_timer); @@ -1300,11 +1545,7 @@ static void usbredir_device_disconnect(void *priv) /* Reset state so that the next dev connected starts with a clean slate */ usbredir_cleanup_device_queues(dev); - memset(dev->endpoint, 0, sizeof(dev->endpoint)); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } - usb_ep_init(&dev->dev); + usbredir_init_endpoints(dev); dev->interface_info.interface_count = NO_INTERFACE_INFO; dev->dev.addr = 0; dev->dev.speed = 0; @@ -1320,9 +1561,10 @@ static void usbredir_interface_info(void *priv, /* * If we receive interface info after the device has already been - * connected (ie on a set_config), re-check the filter. + * connected (ie on a set_config), re-check interface dependent things. */ if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { + usbredir_check_bulk_receiving(dev); if (usbredir_check_filter(dev)) { ERROR("Device no longer matches filter after interface info " "change, disconnecting!\n"); @@ -1354,11 +1596,10 @@ static void usbredir_set_pipeline(USBRedirDevice *dev, struct USBEndpoint *uep) static void usbredir_setup_usb_eps(USBRedirDevice *dev) { struct USBEndpoint *usb_ep; - int i, pid; + int i; for (i = 0; i < MAX_ENDPOINTS; i++) { - pid = (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT; - usb_ep = usb_ep_get(&dev->dev, pid, i & 0x0f); + usb_ep = I2USBEP(dev, i); usb_ep->type = dev->endpoint[i].type; usb_ep->ifnum = dev->endpoint[i].interface; usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; @@ -1424,6 +1665,7 @@ static void usbredir_ep_info(void *priv, return; } usbredir_setup_usb_eps(dev); + usbredir_check_bulk_receiving(dev); } static void usbredir_configuration_status(void *priv, uint64_t id, @@ -1514,6 +1756,25 @@ static void usbredir_bulk_streams_status(void *priv, uint64_t id, { } +static void usbredir_bulk_receiving_status(void *priv, uint64_t id, + struct usb_redir_bulk_receiving_status_header *bulk_receiving_status) +{ + USBRedirDevice *dev = priv; + uint8_t ep = bulk_receiving_status->endpoint; + + DPRINTF("bulk recv status %d ep %02X id %"PRIu64"\n", + bulk_receiving_status->status, ep, id); + + if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].bulk_receiving_started) { + return; + } + + if (bulk_receiving_status->status == usb_redir_stall) { + DPRINTF("bulk receiving stopped by peer ep %02X\n", ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 0; + } +} + static void usbredir_control_packet(void *priv, uint64_t id, struct usb_redir_control_packet_header *control_packet, uint8_t *data, int data_len) @@ -1619,7 +1880,7 @@ static void usbredir_iso_packet(void *priv, uint64_t id, } /* bufp_alloc also adds the packet to the ep queue */ - bufp_alloc(dev, data, data_len, iso_packet->status, ep); + bufp_alloc(dev, data, data_len, iso_packet->status, ep, data); } static void usbredir_interrupt_packet(void *priv, uint64_t id, @@ -1650,7 +1911,7 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, } /* bufp_alloc also adds the packet to the ep queue */ - bufp_alloc(dev, data, data_len, interrupt_packet->status, ep); + bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data); } else { /* * We report output interrupt packets as completed directly upon @@ -1663,6 +1924,52 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, } } +static void usbredir_buffered_bulk_packet(void *priv, uint64_t id, + struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet, + uint8_t *data, int data_len) +{ + USBRedirDevice *dev = priv; + uint8_t status, ep = buffered_bulk_packet->endpoint; + void *free_on_destroy; + int i, len; + + DPRINTF("buffered-bulk-in status %d ep %02X len %d id %"PRIu64"\n", + buffered_bulk_packet->status, ep, data_len, id); + + if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_BULK) { + ERROR("received buffered-bulk packet for non bulk ep %02X\n", ep); + free(data); + return; + } + + if (dev->endpoint[EP2I(ep)].bulk_receiving_started == 0) { + DPRINTF("received buffered-bulk packet on not started ep %02X\n", ep); + free(data); + return; + } + + /* Data must be in maxp chunks for buffered_bulk_add_*_data_to_packet */ + len = dev->endpoint[EP2I(ep)].max_packet_size; + status = usb_redir_success; + free_on_destroy = NULL; + for (i = 0; i < data_len; i += len) { + if (len >= (data_len - i)) { + len = data_len - i; + status = buffered_bulk_packet->status; + free_on_destroy = data; + } + /* bufp_alloc also adds the packet to the ep queue */ + bufp_alloc(dev, data + i, len, status, ep, free_on_destroy); + } + + if (dev->endpoint[EP2I(ep)].pending_async_packet) { + USBPacket *p = dev->endpoint[EP2I(ep)].pending_async_packet; + dev->endpoint[EP2I(ep)].pending_async_packet = NULL; + usbredir_buffered_bulk_in_complete(dev, p, ep); + usb_packet_complete(&dev->dev, p); + } +} + /* * Migration code */ @@ -1697,6 +2004,7 @@ static int usbredir_post_load(void *priv, int version_id) dev->dev.speedmask = (1 << dev->dev.speed); usbredir_setup_usb_eps(dev); + usbredir_check_bulk_receiving(dev); return 0; } @@ -1768,22 +2076,27 @@ static const VMStateInfo usbredir_parser_vmstate_info = { static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) { struct endp_data *endp = priv; + USBRedirDevice *dev = endp->dev; struct buf_packet *bufp; - int remain = endp->bufpq_size; + int len, i = 0; qemu_put_be32(f, endp->bufpq_size); QTAILQ_FOREACH(bufp, &endp->bufpq, next) { - qemu_put_be32(f, bufp->len); + len = bufp->len - bufp->offset; + DPRINTF("put_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, + len, bufp->status); + qemu_put_be32(f, len); qemu_put_be32(f, bufp->status); - qemu_put_buffer(f, bufp->data, bufp->len); - remain--; + qemu_put_buffer(f, bufp->data + bufp->offset, len); + i++; } - assert(remain == 0); + assert(i == endp->bufpq_size); } static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) { struct endp_data *endp = priv; + USBRedirDevice *dev = endp->dev; struct buf_packet *bufp; int i; @@ -1792,9 +2105,13 @@ static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) bufp = g_malloc(sizeof(struct buf_packet)); bufp->len = qemu_get_be32(f); bufp->status = qemu_get_be32(f); + bufp->offset = 0; bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ + bufp->free_on_destroy = bufp->data; qemu_get_buffer(f, bufp->data, bufp->len); QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); + DPRINTF("get_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, + bufp->len, bufp->status); } return 0; } @@ -1807,6 +2124,23 @@ static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { /* For endp_data migration */ +static const VMStateDescription usbredir_bulk_receiving_vmstate = { + .name = "usb-redir-ep/bulk-receiving", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(bulk_receiving_started, struct endp_data), + VMSTATE_END_OF_LIST() + } +}; + +static bool usbredir_bulk_receiving_needed(void *priv) +{ + struct endp_data *endp = priv; + + return endp->bulk_receiving_started; +} + static const VMStateDescription usbredir_ep_vmstate = { .name = "usb-redir-ep", .version_id = 1, @@ -1833,6 +2167,14 @@ static const VMStateDescription usbredir_ep_vmstate = { }, VMSTATE_INT32(bufpq_target_size, struct endp_data), VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &usbredir_bulk_receiving_vmstate, + .needed = usbredir_bulk_receiving_needed, + }, { + /* empty */ + } } }; @@ -1994,11 +2336,12 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usbredir_handle_data; uc->handle_control = usbredir_handle_control; uc->flush_ep_queue = usbredir_flush_ep_queue; + uc->ep_stopped = usbredir_ep_stopped; dc->vmsd = &usbredir_vmstate; dc->props = usbredir_properties; } -static TypeInfo usbredir_dev_info = { +static const TypeInfo usbredir_dev_info = { .name = "usb-redir", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBRedirDevice), diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 1f4d66934c..9d991599cf 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -119,7 +119,7 @@ static void versatile_pci_host_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_PROCESSOR_CO; } -static TypeInfo versatile_pci_host_info = { +static const TypeInfo versatile_pci_host_info = { .name = "versatile_pci_host", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -133,7 +133,7 @@ static void pci_vpb_class_init(ObjectClass *klass, void *data) sdc->init = pci_vpb_init; } -static TypeInfo pci_vpb_info = { +static const TypeInfo pci_vpb_info = { .name = "versatile_pci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PCIVPBState), @@ -147,7 +147,7 @@ static void pci_realview_class_init(ObjectClass *klass, void *data) sdc->init = pci_realview_init; } -static TypeInfo pci_realview_info = { +static const TypeInfo pci_realview_info = { .name = "realview_pci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PCIVPBState), diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 5e89e747a2..bf72ebb305 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -386,7 +386,7 @@ static void vpb_sic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_vpb_sic; } -static TypeInfo vpb_sic_info = { +static const TypeInfo vpb_sic_info = { .name = "versatilepb_sic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(vpb_sic_state), diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 28c83031d0..c51ae6761b 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -562,8 +562,8 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix) return ret; } -static int vfio_msix_vector_use(PCIDevice *pdev, - unsigned int nr, MSIMessage msg) +static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, + MSIMessage *msg, IOHandler *handler) { VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); VFIOMSIVector *vector; @@ -587,7 +587,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev, * Attempt to enable route through KVM irqchip, * default to userspace handling if unavailable. */ - vector->virq = kvm_irqchip_add_msi_route(kvm_state, msg); + vector->virq = msg ? kvm_irqchip_add_msi_route(kvm_state, *msg) : -1; if (vector->virq < 0 || kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt, vector->virq) < 0) { @@ -596,7 +596,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev, vector->virq = -1; } qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), - vfio_msi_interrupt, NULL, vector); + handler, NULL, vector); } /* @@ -639,6 +639,12 @@ static int vfio_msix_vector_use(PCIDevice *pdev, return 0; } +static int vfio_msix_vector_use(PCIDevice *pdev, + unsigned int nr, MSIMessage msg) +{ + return vfio_msix_vector_do_use(pdev, nr, &msg, vfio_msi_interrupt); +} + static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) { VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); @@ -697,6 +703,22 @@ static void vfio_enable_msix(VFIODevice *vdev) vdev->interrupt = VFIO_INT_MSIX; + /* + * Some communication channels between VF & PF or PF & fw rely on the + * physical state of the device and expect that enabling MSI-X from the + * guest enables the same on the host. When our guest is Linux, the + * guest driver call to pci_enable_msix() sets the enabling bit in the + * MSI-X capability, but leaves the vector table masked. We therefore + * can't rely on a vector_use callback (from request_irq() in the guest) + * to switch the physical device into MSI-X mode because that may come a + * long time after pci_enable_msix(). This code enables vector 0 with + * triggering to userspace, then immediately release the vector, leaving + * the physical device with no vectors enabled, but MSI-X enabled, just + * like the guest view. + */ + vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); + vfio_msix_vector_release(&vdev->pdev, 0); + if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, vfio_msix_vector_release, NULL)) { error_report("vfio: msix_set_vector_notifiers failed\n"); @@ -1815,13 +1837,13 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) error_report("Warning, device %s does not support reset\n", name); } - if (dev_info.num_regions != VFIO_PCI_NUM_REGIONS) { + if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) { error_report("vfio: unexpected number of io regions %u\n", dev_info.num_regions); goto error; } - if (dev_info.num_irqs != VFIO_PCI_NUM_IRQS) { + if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) { error_report("vfio: unexpected number of irqs %u\n", dev_info.num_irqs); goto error; } diff --git a/hw/vga-isa.c b/hw/vga-isa.c index cbe7b05a7e..762e45aaeb 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -86,7 +86,7 @@ static void vga_class_initfn(ObjectClass *klass, void *data) dc->props = vga_isa_properties; } -static TypeInfo vga_info = { +static const TypeInfo vga_info = { .name = "isa-vga", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAVGAState), diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 87c7c0648d..c491af20e4 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -200,7 +200,7 @@ static void vga_class_init(ObjectClass *klass, void *data) dc->props = vga_pci_properties; } -static TypeInfo vga_info = { +static const TypeInfo vga_info = { .name = "VGA", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIVGAState), diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 002b028b99..46072a086f 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -142,7 +142,7 @@ static void virtconsole_class_init(ObjectClass *klass, void *data) dc->props = virtconsole_properties; } -static TypeInfo virtconsole_info = { +static const TypeInfo virtconsole_info = { .name = "virtconsole", .parent = TYPE_VIRTIO_SERIAL_PORT, .instance_size = sizeof(VirtConsole), @@ -166,7 +166,7 @@ static void virtserialport_class_init(ObjectClass *klass, void *data) dc->props = virtserialport_properties; } -static TypeInfo virtserialport_info = { +static const TypeInfo virtserialport_info = { .name = "virtserialport", .parent = TYPE_VIRTIO_SERIAL_PORT, .instance_size = sizeof(VirtConsole), diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 1f35922f65..0b49739946 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -1110,7 +1110,7 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data) dc->props = virtio_blk_properties; } -static TypeInfo virtio_blk_info = { +static const TypeInfo virtio_blk_info = { .name = "virtio-blk-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1144,7 +1144,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) dc->props = virtio_net_properties; } -static TypeInfo virtio_net_info = { +static const TypeInfo virtio_net_info = { .name = "virtio-net-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1175,7 +1175,7 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data) dc->props = virtio_serial_properties; } -static TypeInfo virtio_serial_info = { +static const TypeInfo virtio_serial_info = { .name = "virtio-serial-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1203,7 +1203,7 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data) dc->props = virtio_balloon_properties; } -static TypeInfo virtio_balloon_info = { +static const TypeInfo virtio_balloon_info = { .name = "virtio-balloon-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1246,7 +1246,7 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data) dc->props = virtio_rng_properties; } -static TypeInfo virtio_rng_info = { +static const TypeInfo virtio_rng_info = { .name = "virtio-rng-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1304,7 +1304,7 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) dc->props = virtio_scsi_properties; } -static TypeInfo virtio_scsi_info = { +static const TypeInfo virtio_scsi_info = { .name = "virtio-scsi-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index bfe1860505..0715865489 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -565,6 +565,10 @@ static void virtio_scsi_reset(VirtIODevice *vdev) { VirtIOSCSI *s = (VirtIOSCSI *)vdev; + s->resetting++; + qbus_reset_all(&s->bus.qbus); + s->resetting--; + s->sense_size = VIRTIO_SCSI_SENSE_SIZE; s->cdb_size = VIRTIO_SCSI_CDB_SIZE; s->events_dropped = false; diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 7272bfd5fe..aa7d0d7fc7 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -1058,7 +1058,7 @@ static void virtio_serial_port_class_init(ObjectClass *klass, void *data) k->props = virtser_props; } -static TypeInfo virtio_serial_port_type_info = { +static const TypeInfo virtio_serial_port_type_info = { .name = TYPE_VIRTIO_SERIAL_PORT, .parent = TYPE_DEVICE, .instance_size = sizeof(VirtIOSerialPort), diff --git a/hw/vmmouse.c b/hw/vmmouse.c index 004d09851c..b9afc2c4e8 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -286,7 +286,7 @@ static void vmmouse_class_initfn(ObjectClass *klass, void *data) dc->props = vmmouse_properties; } -static TypeInfo vmmouse_info = { +static const TypeInfo vmmouse_info = { .name = "vmmouse", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(VMMouseState), diff --git a/hw/vmport.c b/hw/vmport.c index 7d425237ac..faead3a955 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -155,7 +155,7 @@ static void vmport_class_initfn(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo vmport_info = { +static const TypeInfo vmport_info = { .name = "vmport", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(VMPortState), diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index b0e772f863..62771bb7b5 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1244,7 +1244,7 @@ static void vmsvga_class_init(ObjectClass *klass, void *data) dc->props = vga_vmware_properties; } -static TypeInfo vmsvga_info = { +static const TypeInfo vmsvga_info = { .name = "vmware-svga", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(struct pci_vmsvga_state_s), diff --git a/hw/vt82c686.c b/hw/vt82c686.c index d3469d49f1..2d8e3988db 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -284,7 +284,7 @@ static void via_ac97_class_init(ObjectClass *klass, void *data) dc->desc = "AC97"; } -static TypeInfo via_ac97_info = { +static const TypeInfo via_ac97_info = { .name = "VT82C686B_AC97", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686AC97State), @@ -325,7 +325,7 @@ static void via_mc97_class_init(ObjectClass *klass, void *data) dc->desc = "MC97"; } -static TypeInfo via_mc97_info = { +static const TypeInfo via_mc97_info = { .name = "VT82C686B_MC97", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686MC97State), @@ -404,7 +404,7 @@ static void via_pm_class_init(ObjectClass *klass, void *data) dc->props = via_pm_properties; } -static TypeInfo via_pm_info = { +static const TypeInfo via_pm_info = { .name = "VT82C686B_PM", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686PMState), @@ -471,7 +471,7 @@ static void via_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_via; } -static TypeInfo via_info = { +static const TypeInfo via_info = { .name = "VT82C686B", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT82C686BState), diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 54f0665135..37ce362811 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -439,7 +439,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_i6300esb; } -static TypeInfo i6300esb_info = { +static const TypeInfo i6300esb_info = { .name = "i6300esb", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(I6300State), diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index 4475f7b862..599a86f5f6 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -129,7 +129,7 @@ static void wdt_ib700_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_ib700; } -static TypeInfo wdt_ib700_info = { +static const TypeInfo wdt_ib700_info = { .name = "ib700", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(IB700State), diff --git a/hw/wm8750.c b/hw/wm8750.c index 44f138fd51..bb85064c9b 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -701,7 +701,7 @@ static void wm8750_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_wm8750; } -static TypeInfo wm8750_info = { +static const TypeInfo wm8750_info = { .name = "wm8750", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(WM8750State), diff --git a/hw/xen_apic.c b/hw/xen_apic.c index a6632fe798..1d1d15c289 100644 --- a/hw/xen_apic.c +++ b/hw/xen_apic.c @@ -80,7 +80,7 @@ static void xen_apic_class_init(ObjectClass *klass, void *data) k->external_nmi = xen_apic_external_nmi; } -static TypeInfo xen_apic_info = { +static const TypeInfo xen_apic_info = { .name = "xen-apic", .parent = TYPE_APIC_COMMON, .instance_size = sizeof(APICCommonState), diff --git a/hw/xen_platform.c b/hw/xen_platform.c index e7611bb353..ca66047d82 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -420,7 +420,7 @@ static void xen_platform_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xen_platform; } -static TypeInfo xen_platform_info = { +static const TypeInfo xen_platform_info = { .name = "xen-platform", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIXenPlatformState), diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 6fd8433a2d..9db5f6e964 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -829,7 +829,7 @@ static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data) dc->props = xen_pci_passthrough_properties; }; -static TypeInfo xen_pci_passthrough_info = { +static const TypeInfo xen_pci_passthrough_info = { .name = "xen-pci-passthrough", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(XenPCIPassthroughState), diff --git a/hw/xgmac.c b/hw/xgmac.c index 9639b6141b..00dae7789c 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -418,7 +418,7 @@ static void xgmac_enet_class_init(ObjectClass *klass, void *data) dc->props = xgmac_properties; } -static TypeInfo xgmac_enet_info = { +static const TypeInfo xgmac_enet_info = { .name = "xgmac", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct XgmacState), diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c index ce02764b3f..d0ee566a28 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -503,7 +503,7 @@ static void axidma_class_init(ObjectClass *klass, void *data) ssc->push = axidma_push; } -static TypeInfo axidma_info = { +static const TypeInfo axidma_info = { .name = "xlnx.axi-dma", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct XilinxAXIDMA), diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index 09e49b0aee..51c2896e44 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -893,7 +893,7 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data) ssc->push = axienet_stream_push; } -static TypeInfo xilinx_enet_info = { +static const TypeInfo xilinx_enet_info = { .name = "xlnx.axi-ethernet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct XilinxAXIEnet), diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 4de4a53a0b..2254851f0a 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -243,7 +243,7 @@ static void xilinx_ethlite_class_init(ObjectClass *klass, void *data) dc->props = xilinx_ethlite_properties; } -static TypeInfo xilinx_ethlite_info = { +static const TypeInfo xilinx_ethlite_info = { .name = "xlnx.xps-ethernetlite", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct xlx_ethlite), diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index 7765079802..0c34149c27 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -175,7 +175,7 @@ static void xilinx_intc_class_init(ObjectClass *klass, void *data) dc->props = xilinx_intc_properties; } -static TypeInfo xilinx_intc_info = { +static const TypeInfo xilinx_intc_info = { .name = "xlnx.xps-intc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct xlx_pic), diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c index 77f9178008..be581c2ac5 100644 --- a/hw/xilinx_spi.c +++ b/hw/xilinx_spi.c @@ -370,7 +370,7 @@ static void xilinx_spi_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xilinx_spi; } -static TypeInfo xilinx_spi_info = { +static const TypeInfo xilinx_spi_info = { .name = "xlnx.xps-spi", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(XilinxSPI), diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index 69294bb83c..aa162efaad 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -240,7 +240,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data) dc->props = xilinx_timer_properties; } -static TypeInfo xilinx_timer_info = { +static const TypeInfo xilinx_timer_info = { .name = "xlnx.xps-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct timerblock), diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index abd256ae00..9963982ef6 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -216,7 +216,7 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) sdc->init = xilinx_uartlite_init; } -static TypeInfo xilinx_uartlite_info = { +static const TypeInfo xilinx_uartlite_info = { .name = "xlnx.xps-uartlite", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof (struct xlx_uartlite), diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 2dcd46bff1..7f00bc8256 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -193,7 +193,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data) dc->props = xio3130_downstream_properties; } -static TypeInfo xio3130_downstream_info = { +static const TypeInfo xio3130_downstream_info = { .name = "xio3130-downstream", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIESlot), diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index 713caf2dda..70b15d37c8 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -167,7 +167,7 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data) dc->props = xio3130_upstream_properties; } -static TypeInfo xio3130_upstream_info = { +static const TypeInfo xio3130_upstream_info = { .name = "x3130-upstream", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIEPort), @@ -185,7 +185,7 @@ static void zipit_lcd_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_zipit_lcd_state; } -static TypeInfo zipit_lcd_info = { +static const TypeInfo zipit_lcd_info = { .name = "zipit-lcd", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ZipitLCD), @@ -288,7 +288,7 @@ static void aer915_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_aer915_state; } -static TypeInfo aer915_info = { +static const TypeInfo aer915_info = { .name = "aer915", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(AER915State), diff --git a/hw/zaurus.c b/hw/zaurus.c index d77b34ecce..2defe3b48d 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -236,7 +236,7 @@ static void scoop_sysbus_class_init(ObjectClass *klass, void *data) dc->props = scoop_sysbus_properties; } -static TypeInfo scoop_sysbus_info = { +static const TypeInfo scoop_sysbus_info = { .name = "scoop", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ScoopInfo), diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c index 143a7cf436..4d6f8d9001 100644 --- a/hw/zynq_slcr.c +++ b/hw/zynq_slcr.c @@ -521,7 +521,7 @@ static void zynq_slcr_class_init(ObjectClass *klass, void *data) dc->reset = zynq_slcr_reset; } -static TypeInfo zynq_slcr_info = { +static const TypeInfo zynq_slcr_info = { .class_init = zynq_slcr_class_init, .name = "xilinx,zynq_slcr", .parent = TYPE_SYS_BUS_DEVICE, diff --git a/include/libfdt_env.h b/include/libfdt_env.h index 7938d73fae..3667d4cb3a 100644 --- a/include/libfdt_env.h +++ b/include/libfdt_env.h @@ -22,15 +22,15 @@ #include "qemu/bswap.h" #ifdef HOST_WORDS_BIGENDIAN -#define fdt32_to_cpu(x) (x) -#define cpu_to_fdt32(x) (x) -#define fdt64_to_cpu(x) (x) -#define cpu_to_fdt64(x) (x) +#define fdt32_to_cpu(x) (x) +#define cpu_to_fdt32(x) (x) +#define fdt64_to_cpu(x) (x) +#define cpu_to_fdt64(x) (x) #else -#define fdt32_to_cpu(x) (bswap_32((x))) -#define cpu_to_fdt32(x) (bswap_32((x))) -#define fdt64_to_cpu(x) (bswap_64((x))) -#define cpu_to_fdt64(x) (bswap_64((x))) +#define fdt32_to_cpu(x) bswap32(x) +#define cpu_to_fdt32(x) bswap32(x) +#define fdt64_to_cpu(x) bswap64(x) +#define cpu_to_fdt64(x) bswap64(x) #endif #endif /* _LIBFDT_ENV_H */ diff --git a/include/qemu-common.h b/include/qemu-common.h index 2b83de395c..ca464bb367 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -288,7 +288,9 @@ struct qemu_work_item { }; #ifdef CONFIG_USER_ONLY -#define qemu_init_vcpu(env) do { } while (0) +static inline void qemu_init_vcpu(void *env) +{ +} #else void qemu_init_vcpu(void *env); #endif diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 2006fcd621..be9b035353 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -7,48 +7,11 @@ #include "fpu/softfloat.h" #ifdef CONFIG_MACHINE_BSWAP_H -#include <sys/endian.h> -#include <sys/types.h> -#include <machine/bswap.h> -#else - -#ifdef CONFIG_BYTESWAP_H -#include <byteswap.h> -#else - -#define bswap_16(x) \ -({ \ - uint16_t __x = (x); \ - ((uint16_t)( \ - (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ - (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ -}) - -#define bswap_32(x) \ -({ \ - uint32_t __x = (x); \ - ((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ -}) - -#define bswap_64(x) \ -({ \ - uint64_t __x = (x); \ - ((uint64_t)( \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ -}) - -#endif /* !CONFIG_BYTESWAP_H */ +# include <sys/endian.h> +# include <sys/types.h> +# include <machine/bswap.h> +#elif defined(CONFIG_BYTESWAP_H) +# include <byteswap.h> static inline uint16_t bswap16(uint16_t x) { @@ -64,7 +27,32 @@ static inline uint64_t bswap64(uint64_t x) { return bswap_64(x); } +# else +static inline uint16_t bswap16(uint16_t x) +{ + return (((x & 0x00ff) << 8) | + ((x & 0xff00) >> 8)); +} + +static inline uint32_t bswap32(uint32_t x) +{ + return (((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24)); +} +static inline uint64_t bswap64(uint64_t x) +{ + return (((x & 0x00000000000000ffULL) << 56) | + ((x & 0x000000000000ff00ULL) << 40) | + ((x & 0x0000000000ff0000ULL) << 24) | + ((x & 0x00000000ff000000ULL) << 8) | + ((x & 0x000000ff00000000ULL) >> 8) | + ((x & 0x0000ff0000000000ULL) >> 24) | + ((x & 0x00ff000000000000ULL) >> 40) | + ((x & 0xff00000000000000ULL) >> 56)); +} #endif /* ! CONFIG_MACHINE_BSWAP_H */ static inline void bswap16s(uint16_t *s) @@ -133,111 +121,14 @@ CPU_CONVERT(le, 16, uint16_t) CPU_CONVERT(le, 32, uint32_t) CPU_CONVERT(le, 64, uint64_t) -/* unaligned versions (optimized for frequent unaligned accesses)*/ - -#if defined(__i386__) || defined(_ARCH_PPC) - -#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) -#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) -#define le16_to_cpupu(p) le16_to_cpup(p) -#define le32_to_cpupu(p) le32_to_cpup(p) -#define be32_to_cpupu(p) be32_to_cpup(p) - -#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) -#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) -#define cpu_to_be64wu(p, v) cpu_to_be64w(p, v) - -#else - -static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v & 0xff; - p1[1] = v >> 8; -} - -static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v & 0xff; - p1[1] = v >> 8; - p1[2] = v >> 16; - p1[3] = v >> 24; -} - -static inline uint16_t le16_to_cpupu(const uint16_t *p) -{ - const uint8_t *p1 = (const uint8_t *)p; - return p1[0] | (p1[1] << 8); -} - -static inline uint32_t le32_to_cpupu(const uint32_t *p) -{ - const uint8_t *p1 = (const uint8_t *)p; - return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); -} - -static inline uint32_t be32_to_cpupu(const uint32_t *p) -{ - const uint8_t *p1 = (const uint8_t *)p; - return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24); -} - -static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v >> 8; - p1[1] = v & 0xff; -} - -static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v >> 24; - p1[1] = v >> 16; - p1[2] = v >> 8; - p1[3] = v & 0xff; -} - -static inline void cpu_to_be64wu(uint64_t *p, uint64_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v >> 56; - p1[1] = v >> 48; - p1[2] = v >> 40; - p1[3] = v >> 32; - p1[4] = v >> 24; - p1[5] = v >> 16; - p1[6] = v >> 8; - p1[7] = v & 0xff; -} - -#endif - -#ifdef HOST_WORDS_BIGENDIAN -#define cpu_to_32wu cpu_to_be32wu -#define leul_to_cpu(v) glue(glue(le,HOST_LONG_BITS),_to_cpu)(v) -#else -#define cpu_to_32wu cpu_to_le32wu -#define leul_to_cpu(v) (v) -#endif - -#undef le_bswap -#undef be_bswap -#undef le_bswaps -#undef be_bswaps - /* len must be one of 1, 2, 4 */ static inline uint32_t qemu_bswap_len(uint32_t value, int len) { return bswap32(value) >> (32 - 8 * len); } +/* Unions for reinterpreting between floats and integers. */ + typedef union { float32 f; uint32_t l; @@ -321,10 +212,11 @@ typedef union { * q: 64 bits * * endian is: - * (empty): 8 bit access + * (empty): host endian * be : big endian * le : little endian */ + static inline int ldub_p(const void *ptr) { return *(uint8_t *)ptr; @@ -340,304 +232,173 @@ static inline void stb_p(void *ptr, int v) *(uint8_t *)ptr = v; } -/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the - kernel handles unaligned load/stores may give better results, but - it is a system wide setting : bad */ -#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) - -/* conservative code for little endian unaligned accesses */ -static inline int lduw_le_p(const void *ptr) -{ -#ifdef _ARCH_PPC - int val; - __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return val; -#else - const uint8_t *p = ptr; - return p[0] | (p[1] << 8); -#endif -} - -static inline int ldsw_le_p(const void *ptr) -{ -#ifdef _ARCH_PPC - int val; - __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return (int16_t)val; -#else - const uint8_t *p = ptr; - return (int16_t)(p[0] | (p[1] << 8)); -#endif -} - -static inline int ldl_le_p(const void *ptr) -{ -#ifdef _ARCH_PPC - int val; - __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return val; -#else - const uint8_t *p = ptr; - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -#endif -} +/* Any compiler worth its salt will turn these memcpy into native unaligned + operations. Thus we don't need to play games with packed attributes, or + inline byte-by-byte stores. */ -static inline uint64_t ldq_le_p(const void *ptr) +static inline int lduw_p(const void *ptr) { - const uint8_t *p = ptr; - uint32_t v1, v2; - v1 = ldl_le_p(p); - v2 = ldl_le_p(p + 4); - return v1 | ((uint64_t)v2 << 32); + uint16_t r; + memcpy(&r, ptr, sizeof(r)); + return r; } -static inline void stw_le_p(void *ptr, int v) +static inline int ldsw_p(const void *ptr) { -#ifdef _ARCH_PPC - __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); -#else - uint8_t *p = ptr; - p[0] = v; - p[1] = v >> 8; -#endif + int16_t r; + memcpy(&r, ptr, sizeof(r)); + return r; } -static inline void stl_le_p(void *ptr, int v) +static inline void stw_p(void *ptr, uint16_t v) { -#ifdef _ARCH_PPC - __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); -#else - uint8_t *p = ptr; - p[0] = v; - p[1] = v >> 8; - p[2] = v >> 16; - p[3] = v >> 24; -#endif + memcpy(ptr, &v, sizeof(v)); } -static inline void stq_le_p(void *ptr, uint64_t v) +static inline int ldl_p(const void *ptr) { - uint8_t *p = ptr; - stl_le_p(p, (uint32_t)v); - stl_le_p(p + 4, v >> 32); + int32_t r; + memcpy(&r, ptr, sizeof(r)); + return r; } -/* float access */ - -static inline float32 ldfl_le_p(const void *ptr) +static inline void stl_p(void *ptr, uint32_t v) { - union { - float32 f; - uint32_t i; - } u; - u.i = ldl_le_p(ptr); - return u.f; + memcpy(ptr, &v, sizeof(v)); } -static inline void stfl_le_p(void *ptr, float32 v) +static inline uint64_t ldq_p(const void *ptr) { - union { - float32 f; - uint32_t i; - } u; - u.f = v; - stl_le_p(ptr, u.i); + uint64_t r; + memcpy(&r, ptr, sizeof(r)); + return r; } -static inline float64 ldfq_le_p(const void *ptr) +static inline void stq_p(void *ptr, uint64_t v) { - CPU_DoubleU u; - u.l.lower = ldl_le_p(ptr); - u.l.upper = ldl_le_p(ptr + 4); - return u.d; -} - -static inline void stfq_le_p(void *ptr, float64 v) -{ - CPU_DoubleU u; - u.d = v; - stl_le_p(ptr, u.l.lower); - stl_le_p(ptr + 4, u.l.upper); + memcpy(ptr, &v, sizeof(v)); } -#else - static inline int lduw_le_p(const void *ptr) { - return *(uint16_t *)ptr; + return (uint16_t)le_bswap(lduw_p(ptr), 16); } static inline int ldsw_le_p(const void *ptr) { - return *(int16_t *)ptr; + return (int16_t)le_bswap(lduw_p(ptr), 16); } static inline int ldl_le_p(const void *ptr) { - return *(uint32_t *)ptr; + return le_bswap(ldl_p(ptr), 32); } static inline uint64_t ldq_le_p(const void *ptr) { - return *(uint64_t *)ptr; + return le_bswap(ldq_p(ptr), 64); } static inline void stw_le_p(void *ptr, int v) { - *(uint16_t *)ptr = v; + stw_p(ptr, le_bswap(v, 16)); } static inline void stl_le_p(void *ptr, int v) { - *(uint32_t *)ptr = v; + stl_p(ptr, le_bswap(v, 32)); } static inline void stq_le_p(void *ptr, uint64_t v) { - *(uint64_t *)ptr = v; + stq_p(ptr, le_bswap(v, 64)); } /* float access */ static inline float32 ldfl_le_p(const void *ptr) { - return *(float32 *)ptr; + CPU_FloatU u; + u.l = ldl_le_p(ptr); + return u.f; } -static inline float64 ldfq_le_p(const void *ptr) +static inline void stfl_le_p(void *ptr, float32 v) { - return *(float64 *)ptr; + CPU_FloatU u; + u.f = v; + stl_le_p(ptr, u.l); } -static inline void stfl_le_p(void *ptr, float32 v) +static inline float64 ldfq_le_p(const void *ptr) { - *(float32 *)ptr = v; + CPU_DoubleU u; + u.ll = ldq_le_p(ptr); + return u.d; } static inline void stfq_le_p(void *ptr, float64 v) { - *(float64 *)ptr = v; + CPU_DoubleU u; + u.d = v; + stq_le_p(ptr, u.ll); } -#endif - -#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) static inline int lduw_be_p(const void *ptr) { -#if defined(__i386__) - int val; - asm volatile ("movzwl %1, %0\n" - "xchgb %b0, %h0\n" - : "=q" (val) - : "m" (*(uint16_t *)ptr)); - return val; -#else - const uint8_t *b = ptr; - return ((b[0] << 8) | b[1]); -#endif + return (uint16_t)be_bswap(lduw_p(ptr), 16); } static inline int ldsw_be_p(const void *ptr) { -#if defined(__i386__) - int val; - asm volatile ("movzwl %1, %0\n" - "xchgb %b0, %h0\n" - : "=q" (val) - : "m" (*(uint16_t *)ptr)); - return (int16_t)val; -#else - const uint8_t *b = ptr; - return (int16_t)((b[0] << 8) | b[1]); -#endif + return (int16_t)be_bswap(lduw_p(ptr), 16); } static inline int ldl_be_p(const void *ptr) { -#if defined(__i386__) || defined(__x86_64__) - int val; - asm volatile ("movl %1, %0\n" - "bswap %0\n" - : "=r" (val) - : "m" (*(uint32_t *)ptr)); - return val; -#else - const uint8_t *b = ptr; - return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; -#endif + return be_bswap(ldl_p(ptr), 32); } static inline uint64_t ldq_be_p(const void *ptr) { - uint32_t a,b; - a = ldl_be_p(ptr); - b = ldl_be_p((uint8_t *)ptr + 4); - return (((uint64_t)a<<32)|b); + return be_bswap(ldq_p(ptr), 64); } static inline void stw_be_p(void *ptr, int v) { -#if defined(__i386__) - asm volatile ("xchgb %b0, %h0\n" - "movw %w0, %1\n" - : "=q" (v) - : "m" (*(uint16_t *)ptr), "0" (v)); -#else - uint8_t *d = (uint8_t *) ptr; - d[0] = v >> 8; - d[1] = v; -#endif + stw_p(ptr, be_bswap(v, 16)); } static inline void stl_be_p(void *ptr, int v) { -#if defined(__i386__) || defined(__x86_64__) - asm volatile ("bswap %0\n" - "movl %0, %1\n" - : "=r" (v) - : "m" (*(uint32_t *)ptr), "0" (v)); -#else - uint8_t *d = (uint8_t *) ptr; - d[0] = v >> 24; - d[1] = v >> 16; - d[2] = v >> 8; - d[3] = v; -#endif + stl_p(ptr, be_bswap(v, 32)); } static inline void stq_be_p(void *ptr, uint64_t v) { - stl_be_p(ptr, v >> 32); - stl_be_p((uint8_t *)ptr + 4, v); + stq_p(ptr, be_bswap(v, 64)); } /* float access */ static inline float32 ldfl_be_p(const void *ptr) { - union { - float32 f; - uint32_t i; - } u; - u.i = ldl_be_p(ptr); + CPU_FloatU u; + u.l = ldl_be_p(ptr); return u.f; } static inline void stfl_be_p(void *ptr, float32 v) { - union { - float32 f; - uint32_t i; - } u; + CPU_FloatU u; u.f = v; - stl_be_p(ptr, u.i); + stl_be_p(ptr, u.l); } static inline float64 ldfq_be_p(const void *ptr) { CPU_DoubleU u; - u.l.upper = ldl_be_p(ptr); - u.l.lower = ldl_be_p((uint8_t *)ptr + 4); + u.ll = ldq_be_p(ptr); return u.d; } @@ -645,69 +406,64 @@ static inline void stfq_be_p(void *ptr, float64 v) { CPU_DoubleU u; u.d = v; - stl_be_p(ptr, u.l.upper); - stl_be_p((uint8_t *)ptr + 4, u.l.lower); + stq_be_p(ptr, u.ll); } -#else - -static inline int lduw_be_p(const void *ptr) -{ - return *(uint16_t *)ptr; -} +/* Legacy unaligned versions. Note that we never had a complete set. */ -static inline int ldsw_be_p(const void *ptr) +static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) { - return *(int16_t *)ptr; + stw_le_p(p, v); } -static inline int ldl_be_p(const void *ptr) +static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) { - return *(uint32_t *)ptr; + stl_le_p(p, v); } -static inline uint64_t ldq_be_p(const void *ptr) +static inline uint16_t le16_to_cpupu(const uint16_t *p) { - return *(uint64_t *)ptr; + return lduw_le_p(p); } -static inline void stw_be_p(void *ptr, int v) +static inline uint32_t le32_to_cpupu(const uint32_t *p) { - *(uint16_t *)ptr = v; + return ldl_le_p(p); } -static inline void stl_be_p(void *ptr, int v) +static inline uint32_t be32_to_cpupu(const uint32_t *p) { - *(uint32_t *)ptr = v; + return ldl_be_p(p); } -static inline void stq_be_p(void *ptr, uint64_t v) +static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) { - *(uint64_t *)ptr = v; + stw_be_p(p, v); } -/* float access */ - -static inline float32 ldfl_be_p(const void *ptr) +static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) { - return *(float32 *)ptr; + stl_be_p(p, v); } -static inline float64 ldfq_be_p(const void *ptr) +static inline void cpu_to_be64wu(uint64_t *p, uint64_t v) { - return *(float64 *)ptr; + stq_be_p(p, v); } -static inline void stfl_be_p(void *ptr, float32 v) +static inline void cpu_to_32wu(uint32_t *p, uint32_t v) { - *(float32 *)ptr = v; + stl_p(p, v); } -static inline void stfq_be_p(void *ptr, float64 v) +static inline unsigned long leul_to_cpu(unsigned long v) { - *(float64 *)ptr = v; + return le_bswap(v, HOST_LONG_BITS); } -#endif +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps #endif /* BSWAP_H */ diff --git a/include/qemu/config-file.h b/include/qemu/config-file.h index 486c77cad4..ccfccae2b4 100644 --- a/include/qemu/config-file.h +++ b/include/qemu/config-file.h @@ -6,11 +6,6 @@ #include "qapi/error.h" #include "qemu/option.h" -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); void qemu_add_opts(QemuOptsList *list); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 3e9fc3aca5..fbacb2756b 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -20,7 +20,7 @@ #ifndef QEMU_CPU_H #define QEMU_CPU_H -#include "qom/object.h" +#include "hw/qdev-core.h" #include "qemu/thread.h" /** @@ -46,7 +46,7 @@ typedef struct CPUState CPUState; */ typedef struct CPUClass { /*< private >*/ - ObjectClass parent_class; + DeviceClass parent_class; /*< public >*/ void (*reset)(CPUState *cpu); @@ -66,7 +66,7 @@ struct kvm_run; */ struct CPUState { /*< private >*/ - Object parent_obj; + DeviceState parent_obj; /*< public >*/ struct QemuThread *thread; diff --git a/include/qom/object.h b/include/qom/object.h index abe9691cb7..d43b289a40 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -65,7 +65,7 @@ typedef struct InterfaceInfo InterfaceInfo; * int reg0, reg1, reg2; * } MyDevice; * - * static TypeInfo my_device_info = { + * static const TypeInfo my_device_info = { * .name = TYPE_MY_DEVICE, * .parent = TYPE_DEVICE, * .instance_size = sizeof(MyDevice), @@ -138,7 +138,7 @@ typedef struct InterfaceInfo InterfaceInfo; * dc->reset = my_device_reset; * } * - * static TypeInfo my_device_info = { + * static const TypeInfo my_device_info = { * .name = TYPE_MY_DEVICE, * .parent = TYPE_DEVICE, * .instance_size = sizeof(MyDevice), @@ -163,7 +163,7 @@ typedef struct InterfaceInfo InterfaceInfo; * void (*frobnicate) (MyDevice *obj); * } MyDeviceClass; * - * static TypeInfo my_device_info = { + * static const TypeInfo my_device_info = { * .name = TYPE_MY_DEVICE, * .parent = TYPE_DEVICE, * .instance_size = sizeof(MyDevice), diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 28a783e2be..c07d4ee458 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -183,4 +183,12 @@ char *get_boot_devices_list(uint32_t *size); bool usb_enabled(bool default_usb); +extern QemuOptsList qemu_drive_opts; +extern QemuOptsList qemu_chardev_opts; +extern QemuOptsList qemu_device_opts; +extern QemuOptsList qemu_netdev_opts; +extern QemuOptsList qemu_net_opts; +extern QemuOptsList qemu_global_opts; +extern QemuOptsList qemu_mon_opts; + #endif diff --git a/trace.h b/include/trace.h index c15f498128..c15f498128 100644 --- a/trace.h +++ b/include/trace.h diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 3c05c83a7c..016fd87726 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -6,7 +6,14 @@ #ifndef QEMU_PIXMAN_H #define QEMU_PIXMAN_H +/* pixman-0.16.0 headers have a redundant declaration */ +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif #include <pixman.h> +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +#pragma GCC diagnostic error "-Wredundant-decls" +#endif #include "console.h" diff --git a/libcacard/Makefile b/libcacard/Makefile index c26aac65c3..47827a0eb8 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -1,63 +1,49 @@ --include ../config-host.mak --include $(SRC_PATH)/rules.mak --include $(SRC_PATH)/Makefile.objs - libcacard_includedir=$(includedir)/cacard -$(call set-vpath, $(SRC_PATH)) +TOOLS += vscclient$(EXESUF) # objects linked into a shared library, built with libtool with -fPIC if required -QEMU_OBJS=$(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) $(stub-obj-y) -QEMU_OBJS_LIB=$(patsubst %.o,%.lo,$(QEMU_OBJS)) - -QEMU_CFLAGS+=-I../ - -libcacard.lib-y=$(patsubst %.o,%.lo,$(libcacard-y)) +libcacard-obj-y = $(stub-obj-y) $(libcacard-y) +libcacard-obj-y += util/osdep.o util/cutils.o util/qemu-timer-common.o util/error.o +libcacard-obj-$(CONFIG_WIN32) += util/oslib-win32.o util/qemu-thread-win32.o +libcacard-obj-$(CONFIG_POSIX) += util/oslib-posix.o util/qemu-thread-posix.o +libcacard-obj-y += $(filter trace/%, $(util-obj-y)) -vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o cutils.o - $(call quiet-command,$(CC) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@") +libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y)) -clean: - rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo */*.lo .libs/* */.libs/* *.la */*.la *.pc - rm -Rf .libs */.libs +# libtool will build the .o files, too +$(libcacard-obj-y): | $(libcacard-lobj-y) all: libcacard.la libcacard.pc -# Dummy command so that make thinks it has done something - @true + +vscclient$(EXESUF): libcacard/vscclient.o libcacard.la + $(call LINK,$^) ######################################################################### # Rules for building libcacard standalone library -ifeq ($(LIBTOOL),) -libcacard.la: - @echo "libtool is missing, please install and rerun configure"; exit 1 - -install-libcacard: - @echo "libtool is missing, please install and rerun configure"; exit 1 -else -libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB) - $(call quiet-command,$(LIBTOOL) --mode=link --quiet --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs)," lt LINK $@") +libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined \ + -export-syms $(SRC_PATH)/libcacard/libcacard.syms +libcacard.la: LIBS += $(libcacard_libs) +libcacard.la: $(libcacard-lobj-y) + $(call LINK,$^) -libcacard_srcpath=$(SRC_PATH)/libcacard -libcacard.pc: $(libcacard_srcpath)/libcacard.pc.in +libcacard.pc: $(SRC_PATH)/libcacard/libcacard.pc.in $(call quiet-command,sed -e 's|@LIBDIR@|$(libdir)|' \ -e 's|@INCLUDEDIR@|$(libcacard_includedir)|' \ -e 's|@VERSION@|$(shell cat $(SRC_PATH)/VERSION)|' \ - -e 's|@PREFIX@|$(prefix)|' \ - < $(libcacard_srcpath)/libcacard.pc.in > libcacard.pc,\ + -e 's|@PREFIX@|$(prefix)|' $< > libcacard.pc,\ " GEN $@") .PHONY: install-libcacard -install-libcacard: libcacard.pc libcacard.la vscclient +install: install-libcacard +install-libcacard: libcacard.pc libcacard.la $(INSTALL_DIR) "$(DESTDIR)$(libdir)" $(INSTALL_DIR) "$(DESTDIR)$(libdir)/pkgconfig" $(INSTALL_DIR) "$(DESTDIR)$(libcacard_includedir)" - $(INSTALL_DIR) "$(DESTDIR)$(bindir)" - $(LIBTOOL) --mode=install $(INSTALL_PROG) vscclient "$(DESTDIR)$(bindir)" - $(LIBTOOL) --mode=install $(INSTALL_DATA) libcacard.la "$(DESTDIR)$(libdir)" - $(LIBTOOL) --mode=install $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig" - for inc in *.h; do \ - $(LIBTOOL) --mode=install $(INSTALL_DATA) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \ + $(INSTALL_LIB) libcacard.la "$(DESTDIR)$(libdir)" + $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig" + for inc in $(SRC_PATH)/libcacard/*.h; do \ + $(INSTALL_DATA) $$inc "$(DESTDIR)$(libcacard_includedir)"; \ done -endif diff --git a/libcacard/libcacard.syms b/libcacard/libcacard.syms new file mode 100644 index 0000000000..1697515a7f --- /dev/null +++ b/libcacard/libcacard.syms @@ -0,0 +1,77 @@ +cac_card_init +cac_is_cac_card +vcard_add_applet +vcard_apdu_delete +vcard_apdu_new +vcard_applet_get_aid +vcard_buffer_response_delete +vcard_buffer_response_new +vcard_delete_applet +vcard_emul_delete_key +vcard_emul_force_card_insert +vcard_emul_force_card_remove +vcard_emul_get_atr +vcard_emul_get_login_count +vcard_emul_init +vcard_emul_login +vcard_emul_options +vcard_emul_replay_insertion_events +vcard_emul_reset +vcard_emul_rsa_op +vcard_emul_type_from_string +vcard_emul_type_select +vcard_emul_usage +vcard_find_applet +vcard_free +vcard_get_atr +vcard_get_buffer_response +vcard_get_current_applet_private +vcard_get_private +vcard_get_type +vcard_init +vcard_make_response +vcard_new +vcard_new_applet +vcard_process_apdu +vcard_process_applet_apdu +vcard_reference +vcard_reset +vcard_response_delete +vcard_response_new +vcard_response_new_bytes +vcard_response_new_data +vcard_response_new_status_bytes +vcard_select_applet +vcard_set_applet_private +vcard_set_atr_func +vcard_set_buffer_response +vcard_set_type +vevent_delete +vevent_get_next_vevent +vevent_new +vevent_queue_init +vevent_queue_vevent +vevent_wait_next_vevent +vreader_add_reader +vreader_card_is_present +vreader_free +vreader_get_id +vreader_get_name +vreader_get_private +vreader_get_reader_by_id +vreader_get_reader_by_name +vreader_get_reader_list +vreader_init +vreader_insert_card +vreader_list_delete +vreader_list_get_first +vreader_list_get_next +vreader_list_get_reader +vreader_new +vreader_power_off +vreader_power_on +vreader_queue_card_event +vreader_reference +vreader_remove_reader +vreader_set_id +vreader_xfr_bytes diff --git a/linux-headers/asm-powerpc/epapr_hcalls.h b/linux-headers/asm-powerpc/epapr_hcalls.h new file mode 100644 index 0000000000..06f724786a --- /dev/null +++ b/linux-headers/asm-powerpc/epapr_hcalls.h @@ -0,0 +1,98 @@ +/* + * ePAPR hcall interface + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Author: Timur Tabi <timur@freescale.com> + * + * This file is provided under a dual BSD/GPL license. When using or + * redistributing this file, you may do so under either license. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_POWERPC_EPAPR_HCALLS_H +#define _ASM_POWERPC_EPAPR_HCALLS_H + +#define EV_BYTE_CHANNEL_SEND 1 +#define EV_BYTE_CHANNEL_RECEIVE 2 +#define EV_BYTE_CHANNEL_POLL 3 +#define EV_INT_SET_CONFIG 4 +#define EV_INT_GET_CONFIG 5 +#define EV_INT_SET_MASK 6 +#define EV_INT_GET_MASK 7 +#define EV_INT_IACK 9 +#define EV_INT_EOI 10 +#define EV_INT_SEND_IPI 11 +#define EV_INT_SET_TASK_PRIORITY 12 +#define EV_INT_GET_TASK_PRIORITY 13 +#define EV_DOORBELL_SEND 14 +#define EV_MSGSND 15 +#define EV_IDLE 16 + +/* vendor ID: epapr */ +#define EV_LOCAL_VENDOR_ID 0 /* for private use */ +#define EV_EPAPR_VENDOR_ID 1 +#define EV_FSL_VENDOR_ID 2 /* Freescale Semiconductor */ +#define EV_IBM_VENDOR_ID 3 /* IBM */ +#define EV_GHS_VENDOR_ID 4 /* Green Hills Software */ +#define EV_ENEA_VENDOR_ID 5 /* Enea */ +#define EV_WR_VENDOR_ID 6 /* Wind River Systems */ +#define EV_AMCC_VENDOR_ID 7 /* Applied Micro Circuits */ +#define EV_KVM_VENDOR_ID 42 /* KVM */ + +/* The max number of bytes that a byte channel can send or receive per call */ +#define EV_BYTE_CHANNEL_MAX_BYTES 16 + + +#define _EV_HCALL_TOKEN(id, num) (((id) << 16) | (num)) +#define EV_HCALL_TOKEN(hcall_num) _EV_HCALL_TOKEN(EV_EPAPR_VENDOR_ID, hcall_num) + +/* epapr return codes */ +#define EV_SUCCESS 0 +#define EV_EPERM 1 /* Operation not permitted */ +#define EV_ENOENT 2 /* Entry Not Found */ +#define EV_EIO 3 /* I/O error occured */ +#define EV_EAGAIN 4 /* The operation had insufficient + * resources to complete and should be + * retried + */ +#define EV_ENOMEM 5 /* There was insufficient memory to + * complete the operation */ +#define EV_EFAULT 6 /* Bad guest address */ +#define EV_ENODEV 7 /* No such device */ +#define EV_EINVAL 8 /* An argument supplied to the hcall + was out of range or invalid */ +#define EV_INTERNAL 9 /* An internal error occured */ +#define EV_CONFIG 10 /* A configuration error was detected */ +#define EV_INVALID_STATE 11 /* The object is in an invalid state */ +#define EV_UNIMPLEMENTED 12 /* Unimplemented hypercall */ +#define EV_BUFFER_OVERFLOW 13 /* Caller-supplied buffer too small */ + +#endif /* _ASM_POWERPC_EPAPR_HCALLS_H */ diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 1bea4d8ea6..2fba8a66fb 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -221,6 +221,12 @@ struct kvm_sregs { __u32 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */ __u32 dbcr[3]; + /* + * iac/dac registers are 64bit wide, while this API + * interface provides only lower 32 bits on 64 bit + * processors. ONE_REG interface is added for 64bit + * iac/dac registers. + */ __u32 iac[4]; __u32 dac[2]; __u32 dvc[2]; @@ -325,6 +331,86 @@ struct kvm_book3e_206_tlb_params { __u32 reserved[8]; }; +/* For KVM_PPC_GET_HTAB_FD */ +struct kvm_get_htab_fd { + __u64 flags; + __u64 start_index; + __u64 reserved[2]; +}; + +/* Values for kvm_get_htab_fd.flags */ +#define KVM_GET_HTAB_BOLTED_ONLY ((__u64)0x1) +#define KVM_GET_HTAB_WRITE ((__u64)0x2) + +/* + * Data read on the file descriptor is formatted as a series of + * records, each consisting of a header followed by a series of + * `n_valid' HPTEs (16 bytes each), which are all valid. Following + * those valid HPTEs there are `n_invalid' invalid HPTEs, which + * are not represented explicitly in the stream. The same format + * is used for writing. + */ +struct kvm_get_htab_header { + __u32 index; + __u16 n_valid; + __u16 n_invalid; +}; + #define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1) +#define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2) +#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3) +#define KVM_REG_PPC_IAC3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x4) +#define KVM_REG_PPC_IAC4 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5) +#define KVM_REG_PPC_DAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6) +#define KVM_REG_PPC_DAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7) +#define KVM_REG_PPC_DABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8) +#define KVM_REG_PPC_DSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9) +#define KVM_REG_PPC_PURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa) +#define KVM_REG_PPC_SPURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb) +#define KVM_REG_PPC_DAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc) +#define KVM_REG_PPC_DSISR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd) +#define KVM_REG_PPC_AMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xe) +#define KVM_REG_PPC_UAMOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xf) + +#define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10) +#define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11) +#define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12) + +#define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18) +#define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19) +#define KVM_REG_PPC_PMC3 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1a) +#define KVM_REG_PPC_PMC4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1b) +#define KVM_REG_PPC_PMC5 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1c) +#define KVM_REG_PPC_PMC6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1d) +#define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e) +#define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f) + +/* 32 floating-point registers */ +#define KVM_REG_PPC_FPR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20) +#define KVM_REG_PPC_FPR(n) (KVM_REG_PPC_FPR0 + (n)) +#define KVM_REG_PPC_FPR31 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f) + +/* 32 VMX/Altivec vector registers */ +#define KVM_REG_PPC_VR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40) +#define KVM_REG_PPC_VR(n) (KVM_REG_PPC_VR0 + (n)) +#define KVM_REG_PPC_VR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f) + +/* 32 double-width FP registers for VSX */ +/* High-order halves overlap with FP regs */ +#define KVM_REG_PPC_VSR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60) +#define KVM_REG_PPC_VSR(n) (KVM_REG_PPC_VSR0 + (n)) +#define KVM_REG_PPC_VSR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f) + +/* FP and vector status/control registers */ +#define KVM_REG_PPC_FPSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80) +#define KVM_REG_PPC_VSCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81) + +/* Virtual processor areas */ +/* For SLB & DTL, address in high (first) half, length in low half */ +#define KVM_REG_PPC_VPA_ADDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x82) +#define KVM_REG_PPC_VPA_SLB (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x83) +#define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84) + +#define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85) #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h index 5e04383a1d..7e64f575f6 100644 --- a/linux-headers/asm-powerpc/kvm_para.h +++ b/linux-headers/asm-powerpc/kvm_para.h @@ -17,8 +17,8 @@ * Authors: Hollis Blanchard <hollisb@us.ibm.com> */ -#ifndef _UAPI__POWERPC_KVM_PARA_H__ -#define _UAPI__POWERPC_KVM_PARA_H__ +#ifndef __POWERPC_KVM_PARA_H__ +#define __POWERPC_KVM_PARA_H__ #include <linux/types.h> @@ -75,9 +75,10 @@ struct kvm_vcpu_arch_shared { }; #define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */ -#define HC_VENDOR_KVM (42 << 16) -#define HC_EV_SUCCESS 0 -#define HC_EV_UNIMPLEMENTED 12 + +#define KVM_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num) + +#include <asm/epapr_hcalls.h> #define KVM_FEATURE_MAGIC_PAGE 1 @@ -87,4 +88,4 @@ struct kvm_vcpu_arch_shared { #define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1) -#endif /* _UAPI__POWERPC_KVM_PARA_H__ */ +#endif /* __POWERPC_KVM_PARA_H__ */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 81d2feb7ab..bfdbf4d1ad 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -167,10 +167,15 @@ struct kvm_pit_config { #define KVM_EXIT_OSI 18 #define KVM_EXIT_PAPR_HCALL 19 #define KVM_EXIT_S390_UCONTROL 20 +#define KVM_EXIT_WATCHDOG 21 /* For KVM_EXIT_INTERNAL_ERROR */ -#define KVM_INTERNAL_ERROR_EMULATION 1 -#define KVM_INTERNAL_ERROR_SIMUL_EX 2 +/* Emulate instruction failed. */ +#define KVM_INTERNAL_ERROR_EMULATION 1 +/* Encounter unexpected simultaneous exceptions. */ +#define KVM_INTERNAL_ERROR_SIMUL_EX 2 +/* Encounter unexpected vm-exit due to delivery event. */ +#define KVM_INTERNAL_ERROR_DELIVERY_EV 3 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ struct kvm_run { @@ -477,6 +482,8 @@ struct kvm_ppc_smmu_info { struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ]; }; +#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0) + #define KVMIO 0xAE /* machine type bits, to be used as argument to KVM_CREATE_VM */ @@ -626,6 +633,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_READONLY_MEM 81 #endif #define KVM_CAP_IRQFD_RESAMPLE 82 +#define KVM_CAP_PPC_BOOKE_WATCHDOG 83 +#define KVM_CAP_PPC_HTAB_FD 84 #ifdef KVM_CAP_IRQ_ROUTING @@ -848,6 +857,11 @@ struct kvm_s390_ucas_mapping { #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) +#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce) +/* Available with KVM_CAP_RMA */ +#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma) +/* Available with KVM_CAP_PPC_HTAB_FD */ +#define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd) /* * ioctls for vcpu fds @@ -911,9 +925,6 @@ struct kvm_s390_ucas_mapping { /* Available with KVM_CAP_XCRS */ #define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs) #define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs) -#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce) -/* Available with KVM_CAP_RMA */ -#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma) /* Available with KVM_CAP_SW_TLB */ #define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb) /* Available with KVM_CAP_ONE_REG */ diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h index cea2c5c72d..7bdcf93c1d 100644 --- a/linux-headers/linux/kvm_para.h +++ b/linux-headers/linux/kvm_para.h @@ -1,5 +1,5 @@ -#ifndef _UAPI__LINUX_KVM_PARA_H -#define _UAPI__LINUX_KVM_PARA_H +#ifndef __LINUX_KVM_PARA_H +#define __LINUX_KVM_PARA_H /* * This header file provides a method for making a hypercall to the host @@ -25,4 +25,4 @@ */ #include <asm/kvm_para.h> -#endif /* _UAPI__LINUX_KVM_PARA_H */ +#endif /* __LINUX_KVM_PARA_H */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 4758d1bfcf..f787b727a9 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -8,8 +8,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef _UAPIVFIO_H -#define _UAPIVFIO_H +#ifndef VFIO_H +#define VFIO_H #include <linux/types.h> #include <linux/ioctl.h> @@ -365,4 +365,4 @@ struct vfio_iommu_type1_dma_unmap { #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14) -#endif /* _UAPIVFIO_H */ +#endif /* VFIO_H */ diff --git a/linux-headers/linux/virtio_config.h b/linux-headers/linux/virtio_config.h index b7cda390fd..4f51d8f3af 100644 --- a/linux-headers/linux/virtio_config.h +++ b/linux-headers/linux/virtio_config.h @@ -1,5 +1,5 @@ -#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H -#define _UAPI_LINUX_VIRTIO_CONFIG_H +#ifndef _LINUX_VIRTIO_CONFIG_H +#define _LINUX_VIRTIO_CONFIG_H /* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so * anyone can use the definitions to implement compatible drivers/servers. * @@ -51,4 +51,4 @@ * suppressed them? */ #define VIRTIO_F_NOTIFY_ON_EMPTY 24 -#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */ +#endif /* _LINUX_VIRTIO_CONFIG_H */ diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h index 921694a084..1b333e2536 100644 --- a/linux-headers/linux/virtio_ring.h +++ b/linux-headers/linux/virtio_ring.h @@ -1,5 +1,5 @@ -#ifndef _UAPI_LINUX_VIRTIO_RING_H -#define _UAPI_LINUX_VIRTIO_RING_H +#ifndef _LINUX_VIRTIO_RING_H +#define _LINUX_VIRTIO_RING_H /* An interface for efficient virtio implementation, currently for use by KVM * and lguest, but hopefully others soon. Do NOT change this since it will * break existing servers and clients. @@ -160,4 +160,4 @@ static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old); } -#endif /* _UAPI_LINUX_VIRTIO_RING_H */ +#endif /* _LINUX_VIRTIO_RING_H */ diff --git a/linux-user/main.c b/linux-user/main.c index f6c4c8d7a3..0181bc2112 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -57,7 +57,12 @@ int have_guest_base; * This way we will never overlap with our own libraries or binaries or stack * or anything else that QEMU maps. */ +# ifdef TARGET_MIPS +/* MIPS only supports 31 bits of virtual address space for user space */ +unsigned long reserved_va = 0x77000000; +# else unsigned long reserved_va = 0xf7000000; +# endif #else unsigned long reserved_va; #endif @@ -2933,71 +2938,115 @@ void cpu_loop(CPUAlphaState *env) #ifdef TARGET_S390X void cpu_loop(CPUS390XState *env) { - int trapnr; + int trapnr, n, sig; target_siginfo_t info; + target_ulong addr; while (1) { - trapnr = cpu_s390x_exec (env); - + trapnr = cpu_s390x_exec(env); switch (trapnr) { case EXCP_INTERRUPT: - /* just indicate that signals should be handled asap */ + /* Just indicate that signals should be handled asap. */ break; - case EXCP_DEBUG: - { - int sig; - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } + case EXCP_SVC: + n = env->int_svc_code; + if (!n) { + /* syscalls > 255 */ + n = env->regs[1]; } + env->psw.addr += env->int_svc_ilen; + env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3], + env->regs[4], env->regs[5], + env->regs[6], env->regs[7], 0, 0); break; - case EXCP_SVC: - { - int n = env->int_svc_code; - if (!n) { - /* syscalls > 255 */ - n = env->regs[1]; - } - env->psw.addr += env->int_svc_ilc; - env->regs[2] = do_syscall(env, n, - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5], - env->regs[6], - env->regs[7], - 0, 0); + + case EXCP_DEBUG: + sig = gdb_handlesig(env, TARGET_SIGTRAP); + if (sig) { + n = TARGET_TRAP_BRKPT; + goto do_signal_pc; } break; - case EXCP_ADDR: - { - info.si_signo = SIGSEGV; - info.si_errno = 0; + case EXCP_PGM: + n = env->int_pgm_code; + switch (n) { + case PGM_OPERATION: + case PGM_PRIVILEGED: + sig = SIGILL; + n = TARGET_ILL_ILLOPC; + goto do_signal_pc; + case PGM_PROTECTION: + case PGM_ADDRESSING: + sig = SIGSEGV; /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); + n = TARGET_SEGV_MAPERR; + addr = env->__excp_addr; + goto do_signal; + case PGM_EXECUTE: + case PGM_SPECIFICATION: + case PGM_SPECIAL_OP: + case PGM_OPERAND: + do_sigill_opn: + sig = SIGILL; + n = TARGET_ILL_ILLOPN; + goto do_signal_pc; + + case PGM_FIXPT_OVERFLOW: + sig = SIGFPE; + n = TARGET_FPE_INTOVF; + goto do_signal_pc; + case PGM_FIXPT_DIVIDE: + sig = SIGFPE; + n = TARGET_FPE_INTDIV; + goto do_signal_pc; + + case PGM_DATA: + n = (env->fpc >> 8) & 0xff; + if (n == 0xff) { + /* compare-and-trap */ + goto do_sigill_opn; + } else { + /* An IEEE exception, simulated or otherwise. */ + if (n & 0x80) { + n = TARGET_FPE_FLTINV; + } else if (n & 0x40) { + n = TARGET_FPE_FLTDIV; + } else if (n & 0x20) { + n = TARGET_FPE_FLTOVF; + } else if (n & 0x10) { + n = TARGET_FPE_FLTUND; + } else if (n & 0x08) { + n = TARGET_FPE_FLTRES; + } else { + /* ??? Quantum exception; BFP, DFP error. */ + goto do_sigill_opn; + } + sig = SIGFPE; + goto do_signal_pc; + } + + default: + fprintf(stderr, "Unhandled program exception: %#x\n", n); + cpu_dump_state(env, stderr, fprintf, 0); + exit(1); } break; - case EXCP_SPEC: - { - fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPC; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); - } + + do_signal_pc: + addr = env->psw.addr; + do_signal: + info.si_signo = sig; + info.si_errno = 0; + info.si_code = n; + info._sifields._sigfault._addr = addr; + queue_signal(env, info.si_signo, &info); break; + default: - printf ("Unhandled trap: 0x%x\n", trapnr); + fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); - exit (1); + exit(1); } process_pending_signals (env); } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 8a3538c631..31a220af81 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -287,36 +287,39 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size) (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0; } -/* NOTE __get_user and __put_user use host pointers and don't check access. */ -/* These are usually used to access struct data members once the - * struct has been locked - usually with lock_user_struct(). - */ -#define __put_user(x, hptr)\ -({ __typeof(*hptr) pu_ = (x);\ - switch(sizeof(*hptr)) {\ - case 1: break;\ - case 2: pu_ = tswap16(pu_); break; \ - case 4: pu_ = tswap32(pu_); break; \ - case 8: pu_ = tswap64(pu_); break; \ - default: abort();\ - }\ - memcpy(hptr, &pu_, sizeof(pu_)); \ - 0;\ -}) - -#define __get_user(x, hptr) \ -({ __typeof(*hptr) gu_; \ - memcpy(&gu_, hptr, sizeof(gu_)); \ - switch(sizeof(*hptr)) {\ - case 1: break; \ - case 2: gu_ = tswap16(gu_); break; \ - case 4: gu_ = tswap32(gu_); break; \ - case 8: gu_ = tswap64(gu_); break; \ - default: abort();\ - }\ - (x) = gu_; \ - 0;\ -}) +/* NOTE __get_user and __put_user use host pointers and don't check access. + These are usually used to access struct data members once the struct has + been locked - usually with lock_user_struct. */ + +/* Tricky points: + - Use __builtin_choose_expr to avoid type promotion from ?:, + - Invalid sizes result in a compile time error stemming from + the fact that abort has no parameters. + - It's easier to use the endian-specific unaligned load/store + functions than host-endian unaligned load/store plus tswapN. */ + +#define __put_user_e(x, hptr, e) \ + (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort)))) \ + ((hptr), (x)), 0) + +#define __get_user_e(x, hptr, e) \ + ((x) = \ + __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort)))) \ + (hptr), 0) + +#ifdef TARGET_WORDS_BIGENDIAN +# define __put_user(x, hptr) __put_user_e(x, hptr, be) +# define __get_user(x, hptr) __get_user_e(x, hptr, be) +#else +# define __put_user(x, hptr) __put_user_e(x, hptr, le) +# define __get_user(x, hptr) __get_user_e(x, hptr, le) +#endif /* put_user()/get_user() take a guest address and check access */ /* These are usually used to access an atomic data type, such as an int, diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index c2ea151ea5..e4603b79c3 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -16,7 +16,7 @@ struct target_pt_regs { target_psw_t psw; abi_ulong gprs[TARGET_NUM_GPRS]; abi_ulong orig_gpr2; - unsigned short ilc; + unsigned short ilen; unsigned short trap; }; diff --git a/linux-user/signal.c b/linux-user/signal.c index 95e2ffa007..67c23118a0 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -607,28 +607,22 @@ int do_sigaction(int sig, const struct target_sigaction *act, sig, act, oact); #endif if (oact) { - oact->_sa_handler = tswapal(k->_sa_handler); -#if defined(TARGET_MIPS) || defined (TARGET_ALPHA) - oact->sa_flags = bswap32(k->sa_flags); -#else - oact->sa_flags = tswapal(k->sa_flags); -#endif + __put_user(k->_sa_handler, &oact->_sa_handler); + __put_user(k->sa_flags, &oact->sa_flags); #if !defined(TARGET_MIPS) - oact->sa_restorer = tswapal(k->sa_restorer); + __put_user(k->sa_restorer, &oact->sa_restorer); #endif + /* Not swapped. */ oact->sa_mask = k->sa_mask; } if (act) { /* FIXME: This is not threadsafe. */ - k->_sa_handler = tswapal(act->_sa_handler); -#if defined(TARGET_MIPS) || defined (TARGET_ALPHA) - k->sa_flags = bswap32(act->sa_flags); -#else - k->sa_flags = tswapal(act->sa_flags); -#endif + __get_user(k->_sa_handler, &act->_sa_handler); + __get_user(k->sa_flags, &act->sa_flags); #if !defined(TARGET_MIPS) - k->sa_restorer = tswapal(act->sa_restorer); + __get_user(k->sa_restorer, &act->sa_restorer); #endif + /* To be swapped in target_to_host_sigset. */ k->sa_mask = act->sa_mask; /* we update the host linux signal state */ @@ -4584,7 +4578,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, signal = current_exec_domain_sig(sig); - err |= __put_user(h2g(ka->_sa_handler), &sc->handler); + err |= __put_user(ka->_sa_handler, &sc->handler); err |= __put_user(set->sig[0], &sc->oldmask); #if defined(TARGET_PPC64) err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]); @@ -4606,7 +4600,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, /* Create a stack frame for the caller of the handler. */ newsp = frame_addr - SIGNAL_FRAMESIZE; - err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp); + err |= put_user(env->gpr[1], newsp, target_ulong); if (err) goto sigsegv; @@ -4614,7 +4608,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, /* Set up registers for signal handler. */ env->gpr[1] = newsp; env->gpr[3] = signal; - env->gpr[4] = (target_ulong) h2g(sc); + env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx); env->nip = (target_ulong) ka->_sa_handler; /* Signal handlers are entered in big-endian mode. */ env->msr &= ~MSR_LE; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index d4589e7906..f8f553915d 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -544,7 +544,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, struct target_old_sigaction { abi_ulong _sa_handler; abi_ulong sa_mask; - abi_ulong sa_flags; + int32_t sa_flags; }; struct target_rt_sigaction { diff --git a/main-loop.c b/main-loop.c index 54f38ae1ae..6f52ac39bc 100644 --- a/main-loop.c +++ b/main-loop.c @@ -330,7 +330,7 @@ void qemu_fd_register(int fd) static int os_host_main_loop_wait(uint32_t timeout) { GMainContext *context = g_main_context_default(); - int ret, i; + int select_ret, g_poll_ret, ret, i; PollingEntry *pe; WaitObjects *w = &wait_objects; gint poll_timeout; @@ -345,13 +345,6 @@ static int os_host_main_loop_wait(uint32_t timeout) return ret; } - if (nfds >= 0) { - ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); - if (ret != 0) { - timeout = 0; - } - } - g_main_context_prepare(context, &max_priority); n_poll_fds = g_main_context_query(context, max_priority, &poll_timeout, poll_fds, ARRAY_SIZE(poll_fds)); @@ -367,9 +360,9 @@ static int os_host_main_loop_wait(uint32_t timeout) } qemu_mutex_unlock_iothread(); - ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout); + g_poll_ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout); qemu_mutex_lock_iothread(); - if (ret > 0) { + if (g_poll_ret > 0) { for (i = 0; i < w->num; i++) { w->revents[i] = poll_fds[n_poll_fds + i].revents; } @@ -384,12 +377,18 @@ static int os_host_main_loop_wait(uint32_t timeout) g_main_context_dispatch(context); } - /* If an edge-triggered socket event occurred, select will return a - * positive result on the next iteration. We do not need to do anything - * here. + /* Call select after g_poll to avoid a useless iteration and therefore + * improve socket latency. */ - return ret; + if (nfds >= 0) { + select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); + if (select_ret != 0) { + timeout = 0; + } + } + + return select_ret || g_poll_ret; } #endif @@ -270,6 +270,7 @@ static void monitor_puts(Monitor *mon, const char *str) char c; for(;;) { + assert(mon->outbuf_index < sizeof(mon->outbuf) - 1); c = *str++; if (c == '\0') break; @@ -4790,3 +4791,25 @@ int monitor_read_block_device_key(Monitor *mon, const char *device, return monitor_read_bdrv_key_start(mon, bs, completion_cb, opaque); } + +QemuOptsList qemu_mon_opts = { + .name = "mon", + .implied_opt_name = "chardev", + .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head), + .desc = { + { + .name = "mode", + .type = QEMU_OPT_STRING, + },{ + .name = "chardev", + .type = QEMU_OPT_STRING, + },{ + .name = "default", + .type = QEMU_OPT_BOOL, + },{ + .name = "pretty", + .type = QEMU_OPT_BOOL, + }, + { /* end of list */ } + }, +}; @@ -1054,3 +1054,29 @@ unsigned compute_mcast_idx(const uint8_t *ep) } return crc >> 26; } + +QemuOptsList qemu_netdev_opts = { + .name = "netdev", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), + .desc = { + /* + * no elements => accept any params + * validation will happen later + */ + { /* end of list */ } + }, +}; + +QemuOptsList qemu_net_opts = { + .name = "net", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), + .desc = { + /* + * no elements => accept any params + * validation will happen later + */ + { /* end of list */ } + }, +}; diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs index f9bd3b9910..1f9c97342c 100644 --- a/qapi/Makefile.objs +++ b/qapi/Makefile.objs @@ -1,5 +1,5 @@ -qapi-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o -qapi-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o -qapi-obj-y += string-input-visitor.o string-output-visitor.o +util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o +util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o +util-obj-y += string-input-visitor.o string-output-visitor.o -common-obj-y += opts-visitor.o +util-obj-y += opts-visitor.o diff --git a/qemu-char.c b/qemu-char.c index f41788c9ef..3be4970423 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2924,3 +2924,75 @@ CharDriverState *qemu_char_get_next_serial(void) return serial_hds[next_serial++]; } +QemuOptsList qemu_chardev_opts = { + .name = "chardev", + .implied_opt_name = "backend", + .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head), + .desc = { + { + .name = "backend", + .type = QEMU_OPT_STRING, + },{ + .name = "path", + .type = QEMU_OPT_STRING, + },{ + .name = "host", + .type = QEMU_OPT_STRING, + },{ + .name = "port", + .type = QEMU_OPT_STRING, + },{ + .name = "localaddr", + .type = QEMU_OPT_STRING, + },{ + .name = "localport", + .type = QEMU_OPT_STRING, + },{ + .name = "to", + .type = QEMU_OPT_NUMBER, + },{ + .name = "ipv4", + .type = QEMU_OPT_BOOL, + },{ + .name = "ipv6", + .type = QEMU_OPT_BOOL, + },{ + .name = "wait", + .type = QEMU_OPT_BOOL, + },{ + .name = "server", + .type = QEMU_OPT_BOOL, + },{ + .name = "delay", + .type = QEMU_OPT_BOOL, + },{ + .name = "telnet", + .type = QEMU_OPT_BOOL, + },{ + .name = "width", + .type = QEMU_OPT_NUMBER, + },{ + .name = "height", + .type = QEMU_OPT_NUMBER, + },{ + .name = "cols", + .type = QEMU_OPT_NUMBER, + },{ + .name = "rows", + .type = QEMU_OPT_NUMBER, + },{ + .name = "mux", + .type = QEMU_OPT_BOOL, + },{ + .name = "signal", + .type = QEMU_OPT_BOOL, + },{ + .name = "name", + .type = QEMU_OPT_STRING, + },{ + .name = "debug", + .type = QEMU_OPT_NUMBER, + }, + { /* end of list */ } + }, +}; diff --git a/qemu-config.c b/qemu-config.c deleted file mode 100644 index 2188c3e5ec..0000000000 --- a/qemu-config.c +++ /dev/null @@ -1,894 +0,0 @@ -#include "qemu-common.h" -#include "qemu/error-report.h" -#include "qemu/option.h" -#include "qemu/config-file.h" -#include "hw/qdev.h" -#include "qapi/error.h" - -static QemuOptsList qemu_drive_opts = { - .name = "drive", - .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head), - .desc = { - { - .name = "bus", - .type = QEMU_OPT_NUMBER, - .help = "bus number", - },{ - .name = "unit", - .type = QEMU_OPT_NUMBER, - .help = "unit number (i.e. lun for scsi)", - },{ - .name = "if", - .type = QEMU_OPT_STRING, - .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)", - },{ - .name = "index", - .type = QEMU_OPT_NUMBER, - .help = "index number", - },{ - .name = "cyls", - .type = QEMU_OPT_NUMBER, - .help = "number of cylinders (ide disk geometry)", - },{ - .name = "heads", - .type = QEMU_OPT_NUMBER, - .help = "number of heads (ide disk geometry)", - },{ - .name = "secs", - .type = QEMU_OPT_NUMBER, - .help = "number of sectors (ide disk geometry)", - },{ - .name = "trans", - .type = QEMU_OPT_STRING, - .help = "chs translation (auto, lba. none)", - },{ - .name = "media", - .type = QEMU_OPT_STRING, - .help = "media type (disk, cdrom)", - },{ - .name = "snapshot", - .type = QEMU_OPT_BOOL, - .help = "enable/disable snapshot mode", - },{ - .name = "file", - .type = QEMU_OPT_STRING, - .help = "disk image", - },{ - .name = "cache", - .type = QEMU_OPT_STRING, - .help = "host cache usage (none, writeback, writethrough, " - "directsync, unsafe)", - },{ - .name = "aio", - .type = QEMU_OPT_STRING, - .help = "host AIO implementation (threads, native)", - },{ - .name = "format", - .type = QEMU_OPT_STRING, - .help = "disk format (raw, qcow2, ...)", - },{ - .name = "serial", - .type = QEMU_OPT_STRING, - .help = "disk serial number", - },{ - .name = "rerror", - .type = QEMU_OPT_STRING, - .help = "read error action", - },{ - .name = "werror", - .type = QEMU_OPT_STRING, - .help = "write error action", - },{ - .name = "addr", - .type = QEMU_OPT_STRING, - .help = "pci address (virtio only)", - },{ - .name = "readonly", - .type = QEMU_OPT_BOOL, - .help = "open drive file as read-only", - },{ - .name = "iops", - .type = QEMU_OPT_NUMBER, - .help = "limit total I/O operations per second", - },{ - .name = "iops_rd", - .type = QEMU_OPT_NUMBER, - .help = "limit read operations per second", - },{ - .name = "iops_wr", - .type = QEMU_OPT_NUMBER, - .help = "limit write operations per second", - },{ - .name = "bps", - .type = QEMU_OPT_NUMBER, - .help = "limit total bytes per second", - },{ - .name = "bps_rd", - .type = QEMU_OPT_NUMBER, - .help = "limit read bytes per second", - },{ - .name = "bps_wr", - .type = QEMU_OPT_NUMBER, - .help = "limit write bytes per second", - },{ - .name = "copy-on-read", - .type = QEMU_OPT_BOOL, - .help = "copy read data from backing file into image file", - },{ - .name = "boot", - .type = QEMU_OPT_BOOL, - .help = "(deprecated, ignored)", - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_iscsi_opts = { - .name = "iscsi", - .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), - .desc = { - { - .name = "user", - .type = QEMU_OPT_STRING, - .help = "username for CHAP authentication to target", - },{ - .name = "password", - .type = QEMU_OPT_STRING, - .help = "password for CHAP authentication to target", - },{ - .name = "header-digest", - .type = QEMU_OPT_STRING, - .help = "HeaderDigest setting. " - "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", - },{ - .name = "initiator-name", - .type = QEMU_OPT_STRING, - .help = "Initiator iqn name to use when connecting", - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_chardev_opts = { - .name = "chardev", - .implied_opt_name = "backend", - .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head), - .desc = { - { - .name = "backend", - .type = QEMU_OPT_STRING, - },{ - .name = "path", - .type = QEMU_OPT_STRING, - },{ - .name = "host", - .type = QEMU_OPT_STRING, - },{ - .name = "port", - .type = QEMU_OPT_STRING, - },{ - .name = "localaddr", - .type = QEMU_OPT_STRING, - },{ - .name = "localport", - .type = QEMU_OPT_STRING, - },{ - .name = "to", - .type = QEMU_OPT_NUMBER, - },{ - .name = "ipv4", - .type = QEMU_OPT_BOOL, - },{ - .name = "ipv6", - .type = QEMU_OPT_BOOL, - },{ - .name = "wait", - .type = QEMU_OPT_BOOL, - },{ - .name = "server", - .type = QEMU_OPT_BOOL, - },{ - .name = "delay", - .type = QEMU_OPT_BOOL, - },{ - .name = "telnet", - .type = QEMU_OPT_BOOL, - },{ - .name = "width", - .type = QEMU_OPT_NUMBER, - },{ - .name = "height", - .type = QEMU_OPT_NUMBER, - },{ - .name = "cols", - .type = QEMU_OPT_NUMBER, - },{ - .name = "rows", - .type = QEMU_OPT_NUMBER, - },{ - .name = "mux", - .type = QEMU_OPT_BOOL, - },{ - .name = "signal", - .type = QEMU_OPT_BOOL, - },{ - .name = "name", - .type = QEMU_OPT_STRING, - },{ - .name = "debug", - .type = QEMU_OPT_NUMBER, - }, - { /* end of list */ } - }, -}; - -QemuOptsList qemu_fsdev_opts = { - .name = "fsdev", - .implied_opt_name = "fsdriver", - .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head), - .desc = { - { - .name = "fsdriver", - .type = QEMU_OPT_STRING, - }, { - .name = "path", - .type = QEMU_OPT_STRING, - }, { - .name = "security_model", - .type = QEMU_OPT_STRING, - }, { - .name = "writeout", - .type = QEMU_OPT_STRING, - }, { - .name = "readonly", - .type = QEMU_OPT_BOOL, - - }, { - .name = "socket", - .type = QEMU_OPT_STRING, - }, { - .name = "sock_fd", - .type = QEMU_OPT_NUMBER, - }, - - { /*End of list */ } - }, -}; - -QemuOptsList qemu_virtfs_opts = { - .name = "virtfs", - .implied_opt_name = "fsdriver", - .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head), - .desc = { - { - .name = "fsdriver", - .type = QEMU_OPT_STRING, - }, { - .name = "path", - .type = QEMU_OPT_STRING, - }, { - .name = "mount_tag", - .type = QEMU_OPT_STRING, - }, { - .name = "security_model", - .type = QEMU_OPT_STRING, - }, { - .name = "writeout", - .type = QEMU_OPT_STRING, - }, { - .name = "readonly", - .type = QEMU_OPT_BOOL, - }, { - .name = "socket", - .type = QEMU_OPT_STRING, - }, { - .name = "sock_fd", - .type = QEMU_OPT_NUMBER, - }, - - { /*End of list */ } - }, -}; - -static QemuOptsList qemu_device_opts = { - .name = "device", - .implied_opt_name = "driver", - .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head), - .desc = { - /* - * no elements => accept any - * sanity checking will happen later - * when setting device properties - */ - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_netdev_opts = { - .name = "netdev", - .implied_opt_name = "type", - .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), - .desc = { - /* - * no elements => accept any params - * validation will happen later - */ - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_net_opts = { - .name = "net", - .implied_opt_name = "type", - .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), - .desc = { - /* - * no elements => accept any params - * validation will happen later - */ - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_rtc_opts = { - .name = "rtc", - .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head), - .desc = { - { - .name = "base", - .type = QEMU_OPT_STRING, - },{ - .name = "clock", - .type = QEMU_OPT_STRING, - },{ - .name = "driftfix", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_global_opts = { - .name = "global", - .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head), - .desc = { - { - .name = "driver", - .type = QEMU_OPT_STRING, - },{ - .name = "property", - .type = QEMU_OPT_STRING, - },{ - .name = "value", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -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", - .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head), - .desc = { - { - .name = "mode", - .type = QEMU_OPT_STRING, - },{ - .name = "chardev", - .type = QEMU_OPT_STRING, - },{ - .name = "default", - .type = QEMU_OPT_BOOL, - },{ - .name = "pretty", - .type = QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_trace_opts = { - .name = "trace", - .implied_opt_name = "trace", - .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head), - .desc = { - { - .name = "events", - .type = QEMU_OPT_STRING, - },{ - .name = "file", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -QemuOptsList qemu_spice_opts = { - .name = "spice", - .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), - .desc = { - { - .name = "port", - .type = QEMU_OPT_NUMBER, - },{ - .name = "tls-port", - .type = QEMU_OPT_NUMBER, - },{ - .name = "addr", - .type = QEMU_OPT_STRING, - },{ - .name = "ipv4", - .type = QEMU_OPT_BOOL, - },{ - .name = "ipv6", - .type = QEMU_OPT_BOOL, - },{ - .name = "password", - .type = QEMU_OPT_STRING, - },{ - .name = "disable-ticketing", - .type = QEMU_OPT_BOOL, - },{ - .name = "disable-copy-paste", - .type = QEMU_OPT_BOOL, - },{ - .name = "sasl", - .type = QEMU_OPT_BOOL, - },{ - .name = "x509-dir", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-key-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-key-password", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-cert-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-cacert-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-dh-key-file", - .type = QEMU_OPT_STRING, - },{ - .name = "tls-ciphers", - .type = QEMU_OPT_STRING, - },{ - .name = "tls-channel", - .type = QEMU_OPT_STRING, - },{ - .name = "plaintext-channel", - .type = QEMU_OPT_STRING, - },{ - .name = "image-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "jpeg-wan-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "zlib-glz-wan-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "streaming-video", - .type = QEMU_OPT_STRING, - },{ - .name = "agent-mouse", - .type = QEMU_OPT_BOOL, - },{ - .name = "playback-compression", - .type = QEMU_OPT_BOOL, - }, { - .name = "seamless-migration", - .type = QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -}; - -QemuOptsList qemu_option_rom_opts = { - .name = "option-rom", - .implied_opt_name = "romfile", - .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head), - .desc = { - { - .name = "bootindex", - .type = QEMU_OPT_NUMBER, - }, { - .name = "romfile", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_machine_opts = { - .name = "machine", - .implied_opt_name = "type", - .merge_lists = true, - .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head), - .desc = { - { - .name = "type", - .type = QEMU_OPT_STRING, - .help = "emulated machine" - }, { - .name = "accel", - .type = QEMU_OPT_STRING, - .help = "accelerator list", - }, { - .name = "kernel_irqchip", - .type = QEMU_OPT_BOOL, - .help = "use KVM in-kernel irqchip", - }, { - .name = "kvm_shadow_mem", - .type = QEMU_OPT_SIZE, - .help = "KVM shadow MMU size", - }, { - .name = "kernel", - .type = QEMU_OPT_STRING, - .help = "Linux kernel image file", - }, { - .name = "initrd", - .type = QEMU_OPT_STRING, - .help = "Linux initial ramdisk file", - }, { - .name = "append", - .type = QEMU_OPT_STRING, - .help = "Linux kernel command line", - }, { - .name = "dtb", - .type = QEMU_OPT_STRING, - .help = "Linux kernel device tree file", - }, { - .name = "dumpdtb", - .type = QEMU_OPT_STRING, - .help = "Dump current dtb to a file and quit", - }, { - .name = "phandle_start", - .type = QEMU_OPT_STRING, - .help = "The first phandle ID we may generate dynamically", - }, { - .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", - }, { - .name = "mem-merge", - .type = QEMU_OPT_BOOL, - .help = "enable/disable memory merge support", - },{ - .name = "usb", - .type = QEMU_OPT_BOOL, - .help = "Set on/off to enable/disable usb", - }, { - .name = "nvram", - .type = QEMU_OPT_STRING, - .help = "Drive backing persistent NVRAM", - }, - { /* End of list */ } - }, -}; - -QemuOptsList qemu_boot_opts = { - .name = "boot-opts", - .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head), - .desc = { - /* the three names below are not used now */ - { - .name = "order", - .type = QEMU_OPT_STRING, - }, { - .name = "once", - .type = QEMU_OPT_STRING, - }, { - .name = "menu", - .type = QEMU_OPT_STRING, - /* following are really used */ - }, { - .name = "splash", - .type = QEMU_OPT_STRING, - }, { - .name = "splash-time", - .type = QEMU_OPT_STRING, - }, { - .name = "reboot-timeout", - .type = QEMU_OPT_STRING, - }, - { /*End of list */ } - }, -}; - -static QemuOptsList qemu_add_fd_opts = { - .name = "add-fd", - .head = QTAILQ_HEAD_INITIALIZER(qemu_add_fd_opts.head), - .desc = { - { - .name = "fd", - .type = QEMU_OPT_NUMBER, - .help = "file descriptor of which a duplicate is added to fd set", - },{ - .name = "set", - .type = QEMU_OPT_NUMBER, - .help = "ID of the fd set to add fd to", - },{ - .name = "opaque", - .type = QEMU_OPT_STRING, - .help = "free-form string used to describe fd", - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_object_opts = { - .name = "object", - .implied_opt_name = "qom-type", - .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head), - .desc = { - { } - }, -}; - -static QemuOptsList *vm_config_groups[32] = { - &qemu_drive_opts, - &qemu_chardev_opts, - &qemu_device_opts, - &qemu_netdev_opts, - &qemu_net_opts, - &qemu_rtc_opts, - &qemu_global_opts, - &qemu_mon_opts, - &qemu_trace_opts, - &qemu_option_rom_opts, - &qemu_machine_opts, - &qemu_boot_opts, - &qemu_iscsi_opts, - &qemu_sandbox_opts, - &qemu_add_fd_opts, - &qemu_object_opts, - NULL, -}; - -static QemuOptsList *find_list(QemuOptsList **lists, const char *group, - Error **errp) -{ - int i; - - for (i = 0; lists[i] != NULL; i++) { - if (strcmp(lists[i]->name, group) == 0) - break; - } - if (lists[i] == NULL) { - error_set(errp, QERR_INVALID_OPTION_GROUP, group); - } - return lists[i]; -} - -QemuOptsList *qemu_find_opts(const char *group) -{ - QemuOptsList *ret; - Error *local_err = NULL; - - ret = find_list(vm_config_groups, group, &local_err); - if (error_is_set(&local_err)) { - error_report("%s\n", error_get_pretty(local_err)); - error_free(local_err); - } - - return ret; -} - -QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) -{ - return find_list(vm_config_groups, group, errp); -} - -void qemu_add_opts(QemuOptsList *list) -{ - int entries, i; - - entries = ARRAY_SIZE(vm_config_groups); - entries--; /* keep list NULL terminated */ - for (i = 0; i < entries; i++) { - if (vm_config_groups[i] == NULL) { - vm_config_groups[i] = list; - return; - } - } - fprintf(stderr, "ran out of space in vm_config_groups"); - abort(); -} - -int qemu_set_option(const char *str) -{ - char group[64], id[64], arg[64]; - QemuOptsList *list; - QemuOpts *opts; - int rc, offset; - - rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset); - if (rc < 3 || str[offset] != '=') { - error_report("can't parse: \"%s\"", str); - return -1; - } - - list = qemu_find_opts(group); - if (list == NULL) { - return -1; - } - - opts = qemu_opts_find(list, id); - if (!opts) { - error_report("there is no %s \"%s\" defined", - list->name, id); - return -1; - } - - if (qemu_opt_set(opts, arg, str+offset+1) == -1) { - return -1; - } - return 0; -} - -int qemu_global_option(const char *str) -{ - char driver[64], property[64]; - QemuOpts *opts; - int rc, offset; - - rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); - if (rc < 2 || str[offset] != '=') { - error_report("can't parse: \"%s\"", str); - return -1; - } - - opts = qemu_opts_create_nofail(&qemu_global_opts); - qemu_opt_set(opts, "driver", driver); - qemu_opt_set(opts, "property", property); - qemu_opt_set(opts, "value", str+offset+1); - return 0; -} - -struct ConfigWriteData { - QemuOptsList *list; - FILE *fp; -}; - -static int config_write_opt(const char *name, const char *value, void *opaque) -{ - struct ConfigWriteData *data = opaque; - - fprintf(data->fp, " %s = \"%s\"\n", name, value); - return 0; -} - -static int config_write_opts(QemuOpts *opts, void *opaque) -{ - struct ConfigWriteData *data = opaque; - const char *id = qemu_opts_id(opts); - - if (id) { - fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id); - } else { - fprintf(data->fp, "[%s]\n", data->list->name); - } - qemu_opt_foreach(opts, config_write_opt, data, 0); - fprintf(data->fp, "\n"); - return 0; -} - -void qemu_config_write(FILE *fp) -{ - struct ConfigWriteData data = { .fp = fp }; - QemuOptsList **lists = vm_config_groups; - int i; - - fprintf(fp, "# qemu config file\n\n"); - for (i = 0; lists[i] != NULL; i++) { - data.list = lists[i]; - qemu_opts_foreach(data.list, config_write_opts, &data, 0); - } -} - -int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) -{ - char line[1024], group[64], id[64], arg[64], value[1024]; - Location loc; - QemuOptsList *list = NULL; - Error *local_err = NULL; - QemuOpts *opts = NULL; - int res = -1, lno = 0; - - loc_push_none(&loc); - while (fgets(line, sizeof(line), fp) != NULL) { - loc_set_file(fname, ++lno); - if (line[0] == '\n') { - /* skip empty lines */ - continue; - } - if (line[0] == '#') { - /* comment */ - continue; - } - if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) { - /* group with id */ - list = find_list(lists, group, &local_err); - if (error_is_set(&local_err)) { - error_report("%s\n", error_get_pretty(local_err)); - error_free(local_err); - goto out; - } - opts = qemu_opts_create(list, id, 1, NULL); - continue; - } - if (sscanf(line, "[%63[^]]]", group) == 1) { - /* group without id */ - list = find_list(lists, group, &local_err); - if (error_is_set(&local_err)) { - error_report("%s\n", error_get_pretty(local_err)); - error_free(local_err); - goto out; - } - opts = qemu_opts_create_nofail(list); - continue; - } - if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) { - /* arg = value */ - if (opts == NULL) { - error_report("no group defined"); - goto out; - } - if (qemu_opt_set(opts, arg, value) != 0) { - goto out; - } - continue; - } - error_report("parse error"); - goto out; - } - if (ferror(fp)) { - error_report("error reading file"); - goto out; - } - res = 0; -out: - loc_pop(&loc); - return res; -} - -int qemu_read_config_file(const char *filename) -{ - FILE *f = fopen(filename, "r"); - int ret; - - if (f == NULL) { - return -errno; - } - - ret = qemu_config_parse(f, vm_config_groups, filename); - fclose(f); - - if (ret == 0) { - return 0; - } else { - return -EINVAL; - } -} diff --git a/qemu-tool.c b/qemu-tool.c deleted file mode 100644 index 1a474c45bc..0000000000 --- a/qemu-tool.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Compatibility for qemu-img/qemu-nbd - * - * Copyright IBM, Corp. 2008 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu-common.h" -#include "monitor/monitor.h" -#include "qemu/timer.h" -#include "qemu/log.h" -#include "migration/migration.h" -#include "qemu/main-loop.h" -#include "sysemu/sysemu.h" -#include "qemu/sockets.h" -#include "slirp/libslirp.h" - -#include <sys/time.h> - -struct QEMUBH -{ - QEMUBHFunc *cb; - void *opaque; -}; - -const char *qemu_get_vm_name(void) -{ - return NULL; -} - -Monitor *cur_mon; - -void vm_stop(RunState state) -{ - abort(); -} - -int monitor_cur_is_qmp(void) -{ - return 0; -} - -void monitor_set_error(Monitor *mon, QError *qerror) -{ -} - -void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) -{ -} - -void monitor_printf(Monitor *mon, const char *fmt, ...) -{ -} - -void monitor_print_filename(Monitor *mon, const char *filename) -{ -} - -void monitor_protocol_event(MonitorEvent event, QObject *data) -{ -} - -int64_t cpu_get_clock(void) -{ - return get_clock_realtime(); -} - -int64_t cpu_get_icount(void) -{ - abort(); -} - -void qemu_mutex_lock_iothread(void) -{ -} - -void qemu_mutex_unlock_iothread(void) -{ -} - -int use_icount; - -void qemu_clock_warp(QEMUClock *clock) -{ -} - -void slirp_update_timeout(uint32_t *timeout) -{ -} - -void slirp_select_fill(int *pnfds, fd_set *readfds, - fd_set *writefds, fd_set *xfds) -{ -} - -void slirp_select_poll(fd_set *readfds, fd_set *writefds, - fd_set *xfds, int select_error) -{ -} - -void migrate_add_blocker(Error *reason) -{ -} - -void migrate_del_blocker(Error *reason) -{ -} diff --git a/qemu-user.c b/qemu-user.c deleted file mode 100644 index f8b450c03d..0000000000 --- a/qemu-user.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Stubs for QEMU user emulation - * - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see - * <http://www.gnu.org/licenses/gpl-2.0.html> - */ - -#include "qemu-common.h" -#include "monitor/monitor.h" - -Monitor *cur_mon; - -int monitor_cur_is_qmp(void) -{ - return 0; -} - -void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) -{ -} - -void monitor_set_error(Monitor *mon, QError *qerror) -{ -} diff --git a/qga/channel-posix.c b/qga/channel-posix.c index d4fd628907..ca9e4aaaf9 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -4,6 +4,7 @@ #include <unistd.h> #include <fcntl.h> #include <stdlib.h> +#include <string.h> #include "qemu/osdep.h" #include "qemu/sockets.h" #include "qga/channel.h" diff --git a/qga/commands-posix.c b/qga/commands-posix.c index a657201e7a..77f6ee7d5f 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -46,10 +46,29 @@ extern char **environ; #endif #endif +static void ga_wait_child(pid_t pid, int *status, Error **err) +{ + pid_t rpid; + + *status = 0; + + do { + rpid = waitpid(pid, status, 0); + } while (rpid == -1 && errno == EINTR); + + if (rpid == -1) { + error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid); + return; + } + + g_assert(rpid == pid); +} + void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) { const char *shutdown_flag; - pid_t rpid, pid; + Error *local_err = NULL; + pid_t pid; int status; slog("guest-shutdown called, mode: %s", mode); @@ -60,8 +79,8 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) } else if (strcmp(mode, "reboot") == 0) { shutdown_flag = "-r"; } else { - error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode", - "halt|powerdown|reboot"); + error_setg(err, + "mode is invalid (valid values are: halt|powerdown|reboot"); return; } @@ -77,18 +96,27 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) "hypervisor initiated shutdown", (char*)NULL, environ); _exit(EXIT_FAILURE); } else if (pid < 0) { - goto exit_err; + error_setg_errno(err, errno, "failed to create child process"); + return; } - do { - rpid = waitpid(pid, &status, 0); - } while (rpid == -1 && errno == EINTR); - if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return; + } + + if (!WIFEXITED(status)) { + error_setg(err, "child process has terminated abnormally"); + return; + } + + if (WEXITSTATUS(status)) { + error_setg(err, "child process has failed to shutdown"); return; } -exit_err: - error_set(err, QERR_UNDEFINED_ERROR); + /* succeded */ } typedef struct GuestFileHandle { @@ -111,7 +139,7 @@ static void guest_file_handle_add(FILE *fh) QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); } -static GuestFileHandle *guest_file_handle_find(int64_t id) +static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err) { GuestFileHandle *gfh; @@ -122,6 +150,7 @@ static GuestFileHandle *guest_file_handle_find(int64_t id) } } + error_setg(err, "handle '%" PRId64 "' has not been found", id); return NULL; } @@ -137,7 +166,8 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E slog("guest-file-open called, filepath: %s, mode: %s", path, mode); fh = fopen(path, mode); if (!fh) { - error_set(err, QERR_OPEN_FILE_FAILED, path); + error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')", + path, mode); return -1; } @@ -148,7 +178,8 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E ret = fcntl(fd, F_GETFL); ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK); if (ret == -1) { - error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed"); + error_setg_errno(err, errno, "failed to make file '%s' non-blocking", + path); fclose(fh); return -1; } @@ -160,18 +191,17 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E void qmp_guest_file_close(int64_t handle, Error **err) { - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); int ret; slog("guest-file-close called, handle: %ld", handle); if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return; } ret = fclose(gfh->fh); - if (ret == -1) { - error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed"); + if (ret == EOF) { + error_setg_errno(err, errno, "failed to close handle"); return; } @@ -182,21 +212,21 @@ void qmp_guest_file_close(int64_t handle, Error **err) struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, int64_t count, Error **err) { - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); GuestFileRead *read_data = NULL; guchar *buf; FILE *fh; size_t read_count; if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return NULL; } if (!has_count) { count = QGA_READ_COUNT_DEFAULT; } else if (count < 0) { - error_set(err, QERR_INVALID_PARAMETER, "count"); + error_setg(err, "value '%" PRId64 "' is invalid for argument count", + count); return NULL; } @@ -204,8 +234,8 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, buf = g_malloc0(count+1); read_count = fread(buf, 1, count, fh); if (ferror(fh)) { + error_setg_errno(err, errno, "failed to read file"); slog("guest-file-read failed, handle: %ld", handle); - error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed"); } else { buf[read_count] = 0; read_data = g_malloc0(sizeof(GuestFileRead)); @@ -228,11 +258,10 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, guchar *buf; gsize buf_len; int write_count; - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); FILE *fh; if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return NULL; } @@ -242,15 +271,16 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, if (!has_count) { count = buf_len; } else if (count < 0 || count > buf_len) { + error_setg(err, "value '%" PRId64 "' is invalid for argument count", + count); g_free(buf); - error_set(err, QERR_INVALID_PARAMETER, "count"); return NULL; } write_count = fwrite(buf, 1, count, fh); if (ferror(fh)) { + error_setg_errno(err, errno, "failed to write to file"); slog("guest-file-write failed, handle: %ld", handle); - error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error"); } else { write_data = g_malloc0(sizeof(GuestFileWrite)); write_data->count = write_count; @@ -265,20 +295,19 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, int64_t whence, Error **err) { - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); GuestFileSeek *seek_data = NULL; FILE *fh; int ret; if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return NULL; } fh = gfh->fh; ret = fseek(fh, offset, whence); if (ret == -1) { - error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno)); + error_setg_errno(err, errno, "failed to seek file"); } else { seek_data = g_malloc0(sizeof(GuestFileRead)); seek_data->position = ftell(fh); @@ -291,19 +320,18 @@ struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, void qmp_guest_file_flush(int64_t handle, Error **err) { - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); FILE *fh; int ret; if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return; } fh = gfh->fh; ret = fflush(fh); if (ret == EOF) { - error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno)); + error_setg_errno(err, errno, "failed to flush file"); } } @@ -343,7 +371,7 @@ static void free_fs_mount_list(FsMountList *mounts) /* * Walk the mount table and build a list of local file systems */ -static int build_fs_mount_list(FsMountList *mounts) +static void build_fs_mount_list(FsMountList *mounts, Error **err) { struct mntent *ment; FsMount *mount; @@ -352,8 +380,8 @@ static int build_fs_mount_list(FsMountList *mounts) fp = setmntent(mtab, "r"); if (!fp) { - g_warning("fsfreeze: unable to read mtab"); - return -1; + error_setg(err, "failed to open mtab file: '%s'", mtab); + return; } while ((ment = getmntent(fp))) { @@ -377,13 +405,71 @@ static int build_fs_mount_list(FsMountList *mounts) } endmntent(fp); - - return 0; } #endif #if defined(CONFIG_FSFREEZE) +typedef enum { + FSFREEZE_HOOK_THAW = 0, + FSFREEZE_HOOK_FREEZE, +} FsfreezeHookArg; + +const char *fsfreeze_hook_arg_string[] = { + "thaw", + "freeze", +}; + +static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err) +{ + int status; + pid_t pid; + const char *hook; + const char *arg_str = fsfreeze_hook_arg_string[arg]; + Error *local_err = NULL; + + hook = ga_fsfreeze_hook(ga_state); + if (!hook) { + return; + } + if (access(hook, X_OK) != 0) { + error_setg_errno(err, errno, "can't access fsfreeze hook '%s'", hook); + return; + } + + slog("executing fsfreeze hook with arg '%s'", arg_str); + pid = fork(); + if (pid == 0) { + setsid(); + reopen_fd_to_null(0); + reopen_fd_to_null(1); + reopen_fd_to_null(2); + + execle(hook, hook, arg_str, NULL, environ); + _exit(EXIT_FAILURE); + } else if (pid < 0) { + error_setg_errno(err, errno, "failed to create child process"); + return; + } + + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return; + } + + if (!WIFEXITED(status)) { + error_setg(err, "fsfreeze hook has terminated abnormally"); + return; + } + + status = WEXITSTATUS(status); + if (status) { + error_setg(err, "fsfreeze hook has failed with status %d", status); + return; + } +} + /* * Return status of freeze/thaw */ @@ -405,15 +491,22 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) int ret = 0, i = 0; FsMountList mounts; struct FsMount *mount; + Error *local_err = NULL; int fd; - char err_msg[512]; slog("guest-fsfreeze called"); + execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return -1; + } + QTAILQ_INIT(&mounts); - ret = build_fs_mount_list(&mounts); - if (ret < 0) { - return ret; + build_fs_mount_list(&mounts, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return -1; } /* cannot risk guest agent blocking itself on a write in this state */ @@ -422,9 +515,7 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) QTAILQ_FOREACH(mount, &mounts, next) { fd = qemu_open(mount->dirname, O_RDONLY); if (fd == -1) { - sprintf(err_msg, "failed to open %s, %s", mount->dirname, - strerror(errno)); - error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(err, errno, "failed to open %s", mount->dirname); goto error; } @@ -440,9 +531,8 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) ret = ioctl(fd, FIFREEZE); if (ret == -1) { if (errno != EOPNOTSUPP) { - sprintf(err_msg, "failed to freeze %s, %s", - mount->dirname, strerror(errno)); - error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(err, errno, "failed to freeze %s", + mount->dirname); close(fd); goto error; } @@ -470,12 +560,12 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) FsMountList mounts; FsMount *mount; int fd, i = 0, logged; + Error *local_err = NULL; QTAILQ_INIT(&mounts); - ret = build_fs_mount_list(&mounts); - if (ret) { - error_set(err, QERR_QGA_COMMAND_FAILED, - "failed to enumerate filesystems"); + build_fs_mount_list(&mounts, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); return 0; } @@ -513,6 +603,9 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) ga_unset_frozen(ga_state); free_fs_mount_list(&mounts); + + execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err); + return i; } @@ -540,7 +633,7 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) FsMountList mounts; struct FsMount *mount; int fd; - char err_msg[512]; + Error *local_err = NULL; struct fstrim_range r = { .start = 0, .len = -1, @@ -550,17 +643,16 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) slog("guest-fstrim called"); QTAILQ_INIT(&mounts); - ret = build_fs_mount_list(&mounts); - if (ret < 0) { + build_fs_mount_list(&mounts, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); return; } QTAILQ_FOREACH(mount, &mounts, next) { fd = qemu_open(mount->dirname, O_RDONLY); if (fd == -1) { - sprintf(err_msg, "failed to open %s, %s", mount->dirname, - strerror(errno)); - error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(err, errno, "failed to open %s", mount->dirname); goto error; } @@ -573,9 +665,8 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) ret = ioctl(fd, FITRIM, &r); if (ret == -1) { if (errno != ENOTTY && errno != EOPNOTSUPP) { - sprintf(err_msg, "failed to trim %s, %s", - mount->dirname, strerror(errno)); - error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(err, errno, "failed to trim %s", + mount->dirname); close(fd); goto error; } @@ -596,8 +687,9 @@ error: static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, const char *sysfile_str, Error **err) { + Error *local_err = NULL; char *pmutils_path; - pid_t pid, rpid; + pid_t pid; int status; pmutils_path = g_find_program_in_path(pmutils_bin); @@ -642,38 +734,46 @@ static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, } _exit(SUSPEND_NOT_SUPPORTED); + } else if (pid < 0) { + error_setg_errno(err, errno, "failed to create child process"); + goto out; } - g_free(pmutils_path); + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + goto out; + } - if (pid < 0) { - goto undef_err; + if (!WIFEXITED(status)) { + error_setg(err, "child process has terminated abnormally"); + goto out; } - do { - rpid = waitpid(pid, &status, 0); - } while (rpid == -1 && errno == EINTR); - if (rpid == pid && WIFEXITED(status)) { - switch (WEXITSTATUS(status)) { - case SUSPEND_SUPPORTED: - return; - case SUSPEND_NOT_SUPPORTED: - error_set(err, QERR_UNSUPPORTED); - return; - default: - goto undef_err; - } + switch (WEXITSTATUS(status)) { + case SUSPEND_SUPPORTED: + goto out; + case SUSPEND_NOT_SUPPORTED: + error_setg(err, + "the requested suspend mode is not supported by the guest"); + goto out; + default: + error_setg(err, + "the helper program '%s' returned an unexpected exit status" + " code (%d)", pmutils_path, WEXITSTATUS(status)); + goto out; } -undef_err: - error_set(err, QERR_UNDEFINED_ERROR); +out: + g_free(pmutils_path); } static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, Error **err) { + Error *local_err = NULL; char *pmutils_path; - pid_t rpid, pid; + pid_t pid; int status; pmutils_path = g_find_program_in_path(pmutils_bin); @@ -711,23 +811,29 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, } _exit(EXIT_SUCCESS); + } else if (pid < 0) { + error_setg_errno(err, errno, "failed to create child process"); + goto out; } - g_free(pmutils_path); + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + goto out; + } - if (pid < 0) { - goto exit_err; + if (!WIFEXITED(status)) { + error_setg(err, "child process has terminated abnormally"); + goto out; } - do { - rpid = waitpid(pid, &status, 0); - } while (rpid == -1 && errno == EINTR); - if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { - return; + if (WEXITSTATUS(status)) { + error_setg(err, "child process has failed to suspend"); + goto out; } -exit_err: - error_set(err, QERR_UNDEFINED_ERROR); +out: + g_free(pmutils_path); } void qmp_guest_suspend_disk(Error **err) @@ -780,12 +886,9 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) { GuestNetworkInterfaceList *head = NULL, *cur_item = NULL; struct ifaddrs *ifap, *ifa; - char err_msg[512]; if (getifaddrs(&ifap) < 0) { - snprintf(err_msg, sizeof(err_msg), - "getifaddrs failed: %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "getifaddrs failed"); goto error; } @@ -821,20 +924,16 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) /* we haven't obtained HW address yet */ sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) { - snprintf(err_msg, sizeof(err_msg), - "failed to create socket: %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "failed to create socket"); goto error; } memset(&ifr, 0, sizeof(ifr)); pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name); if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { - snprintf(err_msg, sizeof(err_msg), - "failed to get MAC address of %s: %s", - ifa->ifa_name, - strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, + "failed to get MAC address of %s", + ifa->ifa_name); goto error; } @@ -845,9 +944,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) (int) mac_addr[0], (int) mac_addr[1], (int) mac_addr[2], (int) mac_addr[3], (int) mac_addr[4], (int) mac_addr[5]) == -1) { - snprintf(err_msg, sizeof(err_msg), - "failed to format MAC: %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "failed to format MAC"); goto error; } @@ -862,9 +959,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) address_item->value = g_malloc0(sizeof(*address_item->value)); p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { - snprintf(err_msg, sizeof(err_msg), - "inet_ntop failed : %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "inet_ntop failed"); goto error; } @@ -884,9 +979,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) address_item->value = g_malloc0(sizeof(*address_item->value)); p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { - snprintf(err_msg, sizeof(err_msg), - "inet_ntop failed : %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "inet_ntop failed"); goto error; } diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index 8934163375..3354598362 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -34,6 +34,7 @@ void ga_set_response_delimited(GAState *s); bool ga_is_frozen(GAState *s); void ga_set_frozen(GAState *s); void ga_unset_frozen(GAState *s); +const char *ga_fsfreeze_hook(GAState *s); #ifndef _WIN32 void reopen_fd_to_null(int fd); diff --git a/qga/main.c b/qga/main.c index ba5fa1c778..a9b968c507 100644 --- a/qga/main.c +++ b/qga/main.c @@ -34,6 +34,12 @@ #include "qga/service-win32.h" #include <windows.h> #endif +#ifdef __linux__ +#include <linux/fs.h> +#ifdef FIFREEZE +#define CONFIG_FSFREEZE +#endif +#endif #ifndef _WIN32 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0" @@ -42,6 +48,9 @@ #endif #define QGA_STATEDIR_DEFAULT CONFIG_QEMU_LOCALSTATEDIR "/run" #define QGA_PIDFILE_DEFAULT QGA_STATEDIR_DEFAULT "/qemu-ga.pid" +#ifdef CONFIG_FSFREEZE +#define QGA_FSFREEZE_HOOK_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze-hook" +#endif #define QGA_SENTINEL_BYTE 0xFF struct GAState { @@ -64,6 +73,9 @@ struct GAState { const char *log_filepath; const char *pid_filepath; } deferred_options; +#ifdef CONFIG_FSFREEZE + const char *fsfreeze_hook; +#endif }; struct GAState *ga_state; @@ -153,6 +165,16 @@ static void usage(const char *cmd) " %s)\n" " -l, --logfile set logfile path, logs to stderr by default\n" " -f, --pidfile specify pidfile (default is %s)\n" +#ifdef CONFIG_FSFREEZE +" -F, --fsfreeze-hook\n" +" enable fsfreeze hook. Accepts an optional argument that\n" +" specifies script to run on freeze/thaw. Script will be\n" +" called with 'freeze'/'thaw' arguments accordingly.\n" +" (default is %s)\n" +" If using -F with an argument, do not follow -F with a\n" +" space.\n" +" (for example: -F/var/run/fsfreezehook.sh)\n" +#endif " -t, --statedir specify dir to store state information (absolute paths\n" " only, default is %s)\n" " -v, --verbose log extra debugging information\n" @@ -167,6 +189,9 @@ static void usage(const char *cmd) "\n" "Report bugs to <mdroth@linux.vnet.ibm.com>\n" , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT, +#ifdef CONFIG_FSFREEZE + QGA_FSFREEZE_HOOK_DEFAULT, +#endif QGA_STATEDIR_DEFAULT); } @@ -401,6 +426,13 @@ void ga_unset_frozen(GAState *s) } } +#ifdef CONFIG_FSFREEZE +const char *ga_fsfreeze_hook(GAState *s) +{ + return s->fsfreeze_hook; +} +#endif + static void become_daemon(const char *pidfile) { #ifndef _WIN32 @@ -678,10 +710,13 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[]) int main(int argc, char **argv) { - const char *sopt = "hVvdm:p:l:f:b:s:t:"; + const char *sopt = "hVvdm:p:l:f:F::b:s:t:"; const char *method = NULL, *path = NULL; const char *log_filepath = NULL; const char *pid_filepath = QGA_PIDFILE_DEFAULT; +#ifdef CONFIG_FSFREEZE + const char *fsfreeze_hook = NULL; +#endif const char *state_dir = QGA_STATEDIR_DEFAULT; #ifdef _WIN32 const char *service = NULL; @@ -691,6 +726,9 @@ int main(int argc, char **argv) { "version", 0, NULL, 'V' }, { "logfile", 1, NULL, 'l' }, { "pidfile", 1, NULL, 'f' }, +#ifdef CONFIG_FSFREEZE + { "fsfreeze-hook", 2, NULL, 'F' }, +#endif { "verbose", 0, NULL, 'v' }, { "method", 1, NULL, 'm' }, { "path", 1, NULL, 'p' }, @@ -723,6 +761,11 @@ int main(int argc, char **argv) case 'f': pid_filepath = optarg; break; +#ifdef CONFIG_FSFREEZE + case 'F': + fsfreeze_hook = optarg ? optarg : QGA_FSFREEZE_HOOK_DEFAULT; + break; +#endif case 't': state_dir = optarg; break; @@ -786,6 +829,9 @@ int main(int argc, char **argv) s = g_malloc0(sizeof(GAState)); s->log_level = log_level; s->log_file = stderr; +#ifdef CONFIG_FSFREEZE + s->fsfreeze_hook = fsfreeze_hook; +#endif g_log_set_default_handler(ga_log, s); g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR); ga_enable_logging(s); diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs new file mode 100644 index 0000000000..c9ff59c6cc --- /dev/null +++ b/qobject/Makefile.objs @@ -0,0 +1,3 @@ +util-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o +util-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o +util-obj-y += qerror.o diff --git a/json-lexer.c b/qobject/json-lexer.c index 440df60392..440df60392 100644 --- a/json-lexer.c +++ b/qobject/json-lexer.c diff --git a/json-parser.c b/qobject/json-parser.c index 05279c11eb..05279c11eb 100644 --- a/json-parser.c +++ b/qobject/json-parser.c diff --git a/json-streamer.c b/qobject/json-streamer.c index 1b2f9b1d10..1b2f9b1d10 100644 --- a/json-streamer.c +++ b/qobject/json-streamer.c diff --git a/qbool.c b/qobject/qbool.c index a3d2afa827..a3d2afa827 100644 --- a/qbool.c +++ b/qobject/qbool.c diff --git a/qdict.c b/qobject/qdict.c index 7543ccc10f..7543ccc10f 100644 --- a/qdict.c +++ b/qobject/qdict.c diff --git a/qerror.c b/qobject/qerror.c index 3aee1cf6a6..3aee1cf6a6 100644 --- a/qerror.c +++ b/qobject/qerror.c diff --git a/qfloat.c b/qobject/qfloat.c index 7de0992dba..7de0992dba 100644 --- a/qfloat.c +++ b/qobject/qfloat.c diff --git a/qint.c b/qobject/qint.c index 86b9b04f0b..86b9b04f0b 100644 --- a/qint.c +++ b/qobject/qint.c diff --git a/qjson.c b/qobject/qjson.c index 83a6b4f7c1..83a6b4f7c1 100644 --- a/qjson.c +++ b/qobject/qjson.c diff --git a/qlist.c b/qobject/qlist.c index 1ced0de58e..1ced0de58e 100644 --- a/qlist.c +++ b/qobject/qlist.c diff --git a/qstring.c b/qobject/qstring.c index 5f7376c336..5f7376c336 100644 --- a/qstring.c +++ b/qobject/qstring.c diff --git a/qom/Makefile.objs b/qom/Makefile.objs index 5ef060a401..1899a4ce42 100644 --- a/qom/Makefile.objs +++ b/qom/Makefile.objs @@ -1,4 +1,2 @@ -qom-obj-y = object.o container.o qom-qobject.o -qom-obj-twice-y = cpu.o -common-obj-y = $(qom-obj-twice-y) -user-obj-y = $(qom-obj-twice-y) +universal-obj-y = object.o container.o qom-qobject.o +universal-obj-y += cpu.o diff --git a/qom/container.c b/qom/container.c index 5270a5ee9c..62b1648add 100644 --- a/qom/container.c +++ b/qom/container.c @@ -14,7 +14,7 @@ #include "qemu/module.h" #include <assert.h> -static TypeInfo container_info = { +static const TypeInfo container_info = { .name = "container", .instance_size = sizeof(Object), .parent = TYPE_OBJECT, @@ -36,14 +36,16 @@ static void cpu_common_reset(CPUState *cpu) static void cpu_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); CPUClass *k = CPU_CLASS(klass); k->reset = cpu_common_reset; + dc->no_user = 1; } -static TypeInfo cpu_type_info = { +static const TypeInfo cpu_type_info = { .name = TYPE_CPU, - .parent = TYPE_OBJECT, + .parent = TYPE_DEVICE, .instance_size = sizeof(CPUState), .abstract = true, .class_size = sizeof(CPUClass), diff --git a/readline.c b/readline.c index 5fc9643c2b..a0c9638e4d 100644 --- a/readline.c +++ b/readline.c @@ -248,8 +248,8 @@ static void readline_hist_add(ReadLineState *rs, const char *cmdline) if (idx == READLINE_MAX_CMDS) { /* Need to get one free slot */ free(rs->history[0]); - memcpy(rs->history, &rs->history[1], - (READLINE_MAX_CMDS - 1) * sizeof(char *)); + memmove(rs->history, &rs->history[1], + (READLINE_MAX_CMDS - 1) * sizeof(char *)); rs->history[READLINE_MAX_CMDS - 1] = NULL; idx = READLINE_MAX_CMDS - 1; } @@ -21,20 +21,35 @@ QEMU_CFLAGS += -I$(<D) -I$(@D) $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CC $(TARGET_DIR)$@") ifeq ($(LIBTOOL),) -%.lo: %.c - @echo "missing libtool. please install and rerun configure"; exit 1 +LIBTOOL = /bin/false +LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ + $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-obj-y) \ + $(LIBS)," LINK $(TARGET_DIR)$@") else +LIBTOOL += $(if $(V),,--quiet) %.lo: %.c - $(call quiet-command,$(LIBTOOL) --mode=compile --quiet --tag=CC $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," lt CC $@") + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," lt CC $@") +%.lo: %.dtrace + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN $(TARGET_DIR)$@") + +LINK = $(call quiet-command,\ + $(if $(filter %.lo %.la,$^),$(LIBTOOL) --mode=link --tag=CC \ + )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ + $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-obj-y) \ + $(LIBS),$(if $(filter %.lo %.la,$^),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") endif -%.o: %.S - $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@") +%.asm: %.S + $(call quiet-command,$(CPP) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -o $@ $<," CPP $(TARGET_DIR)$@") + +%.o: %.asm + $(call quiet-command,$(AS) $(ASFLAGS) -o $@ $<," AS $(TARGET_DIR)$@") %.o: %.m $(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 $(filter %.o, $1)) $(filter-out %.o, $1) $(LIBS)," LINK $(TARGET_DIR)$@") +%.o: %.dtrace + $(call quiet-command,dtrace -o $@ -G -s $<, " GEN $(TARGET_DIR)$@") %$(EXESUF): %.o $(call LINK,$^) @@ -23,15 +23,6 @@ */ #include "config-host.h" - -#ifndef _WIN32 -#include <arpa/inet.h> -#endif - -#ifdef _WIN32 -#include <windows.h> -#endif - #include "qemu-common.h" #include "hw/hw.h" #include "hw/qdev.h" @@ -2093,13 +2084,8 @@ void do_savevm(Monitor *mon, const QDict *qdict) QEMUFile *f; int saved_vm_running; uint64_t vm_state_size; -#ifdef _WIN32 - struct _timeb tb; - struct tm *ptm; -#else - struct timeval tv; + qemu_timeval tv; struct tm tm; -#endif const char *name = qdict_get_try_str(qdict, "name"); /* Verify if there is a device that doesn't support snapshots and is writable */ @@ -2129,15 +2115,9 @@ void do_savevm(Monitor *mon, const QDict *qdict) memset(sn, 0, sizeof(*sn)); /* fill auxiliary fields */ -#ifdef _WIN32 - _ftime(&tb); - sn->date_sec = tb.time; - sn->date_nsec = tb.millitm * 1000000; -#else - gettimeofday(&tv, NULL); + qemu_gettimeofday(&tv); sn->date_sec = tv.tv_sec; sn->date_nsec = tv.tv_usec * 1000; -#endif sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); if (name) { @@ -2149,15 +2129,9 @@ void do_savevm(Monitor *mon, const QDict *qdict) pstrcpy(sn->name, sizeof(sn->name), name); } } else { -#ifdef _WIN32 - time_t t = tb.time; - ptm = localtime(&t); - strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm); -#else /* cast below needed for OpenBSD where tv_sec is still 'long' */ localtime_r((const time_t *)&tv.tv_sec, &tm); strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm); -#endif } /* Delete old snapshots of the same name */ diff --git a/scripts/qemu-guest-agent/fsfreeze-hook b/scripts/qemu-guest-agent/fsfreeze-hook new file mode 100755 index 0000000000..c27b29f282 --- /dev/null +++ b/scripts/qemu-guest-agent/fsfreeze-hook @@ -0,0 +1,33 @@ +#!/bin/sh + +# This script is executed when a guest agent receives fsfreeze-freeze and +# fsfreeze-thaw command, if it is specified in --fsfreeze-hook (-F) +# option of qemu-ga or placed in default path (/etc/qemu/fsfreeze-hook). +# When the agent receives fsfreeze-freeze request, this script is issued with +# "freeze" argument before the filesystem is frozen. And for fsfreeze-thaw +# request, it is issued with "thaw" argument after filesystem is thawed. + +LOGFILE=/var/log/qga-fsfreeze-hook.log +FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d + +# Check whether file $1 is a backup or rpm-generated file and should be ignored +is_ignored_file() { + case "$1" in + *~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave | *.sample) + return 0 ;; + esac + return 1 +} + +# Iterate executables in directory "fsfreeze-hook.d" with the specified args +[ ! -d "$FSFREEZE_D" ] && exit 0 +for file in "$FSFREEZE_D"/* ; do + is_ignored_file "$file" && continue + [ -x "$file" ] || continue + printf "$(date): execute $file $@\n" >>$LOGFILE + "$file" "$@" >>$LOGFILE 2>&1 + STATUS=$? + printf "$(date): $file finished with status=$STATUS\n" >>$LOGFILE +done + +exit 0 diff --git a/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample b/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample new file mode 100755 index 0000000000..2b4fa3aeb1 --- /dev/null +++ b/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample @@ -0,0 +1,56 @@ +#!/bin/sh + +# Flush MySQL tables to the disk before the filesystem is frozen. +# At the same time, this keeps a read lock in order to avoid write accesses +# from the other clients until the filesystem is thawed. + +MYSQL="/usr/bin/mysql" +MYSQL_OPTS="-uroot" #"-prootpassword" +FIFO=/var/run/mysql-flush.fifo + +# Check mysql is installed and the server running +[ -x "$MYSQL" ] && "$MYSQL" $MYSQL_OPTS < /dev/null || exit 0 + +flush_and_wait() { + printf "FLUSH TABLES WITH READ LOCK \\G\n" + trap 'printf "$(date): $0 is killed\n">&2' HUP INT QUIT ALRM TERM + read < $FIFO + printf "UNLOCK TABLES \\G\n" + rm -f $FIFO +} + +case "$1" in + freeze) + mkfifo $FIFO || exit 1 + flush_and_wait | "$MYSQL" $MYSQL_OPTS & + # wait until every block is flushed + while [ "$(echo 'SHOW STATUS LIKE "Key_blocks_not_flushed"' |\ + "$MYSQL" $MYSQL_OPTS | tail -1 | cut -f 2)" -gt 0 ]; do + sleep 1 + done + # for InnoDB, wait until every log is flushed + INNODB_STATUS=$(mktemp /tmp/mysql-flush.XXXXXX) + [ $? -ne 0 ] && exit 2 + trap "rm -f $INNODB_STATUS; exit 1" HUP INT QUIT ALRM TERM + while :; do + printf "SHOW ENGINE INNODB STATUS \\G" |\ + "$MYSQL" $MYSQL_OPTS > $INNODB_STATUS + LOG_CURRENT=$(grep 'Log sequence number' $INNODB_STATUS |\ + tr -s ' ' | cut -d' ' -f4) + LOG_FLUSHED=$(grep 'Log flushed up to' $INNODB_STATUS |\ + tr -s ' ' | cut -d' ' -f5) + [ "$LOG_CURRENT" = "$LOG_FLUSHED" ] && break + sleep 1 + done + rm -f $INNODB_STATUS + ;; + + thaw) + [ ! -p $FIFO ] && exit 1 + echo > $FIFO + ;; + + *) + exit 1 + ;; +esac diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index 4c7b566fdf..120a694313 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -54,6 +54,9 @@ for arch in $ARCHLIST; do if [ $arch = x86 ]; then cp "$tmpdir/include/asm/hyperv.h" "$output/linux-headers/asm-x86" fi + if [ $arch = powerpc ]; then + cp "$tmpdir/include/asm/epapr_hcalls.h" "$output/linux-headers/asm-powerpc/" + fi done rm -rf "$output/linux-headers/linux" diff --git a/slirp/slirp.h b/slirp/slirp.h index dfc3e3a2b8..fe0e65d0ee 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -215,7 +215,6 @@ struct Slirp { char client_hostname[33]; int restricted; - struct timeval tt; struct ex_list *exec_list; /* mbuf states */ diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 035b29a1f3..a2603947db 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -1,8 +1,24 @@ stub-obj-y += arch-query-cpu-def.o +stub-obj-y += clock-warp.o +stub-obj-y += cpu-get-clock.o +stub-obj-y += cpu-get-icount.o stub-obj-y += fdset-add-fd.o stub-obj-y += fdset-find-fd.o stub-obj-y += fdset-get-fd.o stub-obj-y += fdset-remove-fd.o stub-obj-y += get-fd.o +stub-obj-y += get-vm-name.o +stub-obj-y += iothread-lock.o +stub-obj-y += migr-blocker.o +stub-obj-y += mon-is-qmp.o +stub-obj-y += mon-printf.o +stub-obj-y += mon-print-filename.o +stub-obj-y += mon-protocol-event.o +stub-obj-y += mon-set-error.o +stub-obj-y += reset.o stub-obj-y += set-fd-handler.o +stub-obj-y += slirp.o +stub-obj-y += sysbus.o +stub-obj-y += vm-stop.o +stub-obj-y += vmstate.o stub-obj-$(CONFIG_WIN32) += fd-register.o diff --git a/stubs/clock-warp.c b/stubs/clock-warp.c new file mode 100644 index 0000000000..b64c462e73 --- /dev/null +++ b/stubs/clock-warp.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "qemu/timer.h" + +void qemu_clock_warp(QEMUClock *clock) +{ +} + diff --git a/stubs/cpu-get-clock.c b/stubs/cpu-get-clock.c new file mode 100644 index 0000000000..5b34c976d9 --- /dev/null +++ b/stubs/cpu-get-clock.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "qemu/timer.h" + +int64_t cpu_get_clock(void) +{ + return get_clock_realtime(); +} diff --git a/stubs/cpu-get-icount.c b/stubs/cpu-get-icount.c new file mode 100644 index 0000000000..d68585965f --- /dev/null +++ b/stubs/cpu-get-icount.c @@ -0,0 +1,9 @@ +#include "qemu-common.h" +#include "qemu/timer.h" + +int use_icount; + +int64_t cpu_get_icount(void) +{ + abort(); +} diff --git a/stubs/get-vm-name.c b/stubs/get-vm-name.c new file mode 100644 index 0000000000..e5f619ffab --- /dev/null +++ b/stubs/get-vm-name.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" + +const char *qemu_get_vm_name(void) +{ + return NULL; +} + diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c new file mode 100644 index 0000000000..5d8aca1b37 --- /dev/null +++ b/stubs/iothread-lock.c @@ -0,0 +1,10 @@ +#include "qemu-common.h" +#include "qemu/main-loop.h" + +void qemu_mutex_lock_iothread(void) +{ +} + +void qemu_mutex_unlock_iothread(void) +{ +} diff --git a/stubs/migr-blocker.c b/stubs/migr-blocker.c new file mode 100644 index 0000000000..300df6e205 --- /dev/null +++ b/stubs/migr-blocker.c @@ -0,0 +1,10 @@ +#include "qemu-common.h" +#include "migration/migration.h" + +void migrate_add_blocker(Error *reason) +{ +} + +void migrate_del_blocker(Error *reason) +{ +} diff --git a/stubs/mon-is-qmp.c b/stubs/mon-is-qmp.c new file mode 100644 index 0000000000..1f0a8fd98a --- /dev/null +++ b/stubs/mon-is-qmp.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +int monitor_cur_is_qmp(void) +{ + return 0; +} diff --git a/stubs/mon-print-filename.c b/stubs/mon-print-filename.c new file mode 100644 index 0000000000..9c939641ff --- /dev/null +++ b/stubs/mon-print-filename.c @@ -0,0 +1,6 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +void monitor_print_filename(Monitor *mon, const char *filename) +{ +} diff --git a/stubs/mon-printf.c b/stubs/mon-printf.c new file mode 100644 index 0000000000..0ce2ca6925 --- /dev/null +++ b/stubs/mon-printf.c @@ -0,0 +1,10 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +void monitor_printf(Monitor *mon, const char *fmt, ...) +{ +} + +void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) +{ +} diff --git a/stubs/mon-protocol-event.c b/stubs/mon-protocol-event.c new file mode 100644 index 0000000000..0946e94724 --- /dev/null +++ b/stubs/mon-protocol-event.c @@ -0,0 +1,6 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +void monitor_protocol_event(MonitorEvent event, QObject *data) +{ +} diff --git a/stubs/mon-set-error.c b/stubs/mon-set-error.c new file mode 100644 index 0000000000..d0411f97fa --- /dev/null +++ b/stubs/mon-set-error.c @@ -0,0 +1,8 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +Monitor *cur_mon; + +void monitor_set_error(Monitor *mon, QError *qerror) +{ +} diff --git a/stubs/reset.c b/stubs/reset.c new file mode 100644 index 0000000000..ad287251ed --- /dev/null +++ b/stubs/reset.c @@ -0,0 +1,13 @@ +#include "hw/hw.h" + +/* Stub functions for binaries that never call qemu_devices_reset(), + * and don't need to keep track of the reset handler list. + */ + +void qemu_register_reset(QEMUResetHandler *func, void *opaque) +{ +} + +void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) +{ +} diff --git a/stubs/slirp.c b/stubs/slirp.c new file mode 100644 index 0000000000..9a3309a2b9 --- /dev/null +++ b/stubs/slirp.c @@ -0,0 +1,17 @@ +#include "qemu-common.h" +#include "slirp/slirp.h" + +void slirp_update_timeout(uint32_t *timeout) +{ +} + +void slirp_select_fill(int *pnfds, fd_set *readfds, + fd_set *writefds, fd_set *xfds) +{ +} + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, + fd_set *xfds, int select_error) +{ +} + diff --git a/stubs/sysbus.c b/stubs/sysbus.c new file mode 100644 index 0000000000..e13496582b --- /dev/null +++ b/stubs/sysbus.c @@ -0,0 +1,6 @@ +#include "hw/qdev-core.h" + +BusState *sysbus_get_default(void) +{ + return NULL; +} diff --git a/stubs/vm-stop.c b/stubs/vm-stop.c new file mode 100644 index 0000000000..45689354f6 --- /dev/null +++ b/stubs/vm-stop.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "sysemu/sysemu.h" + +void vm_stop(RunState state) +{ + abort(); +} diff --git a/stubs/vmstate.c b/stubs/vmstate.c new file mode 100644 index 0000000000..3682af599e --- /dev/null +++ b/stubs/vmstate.c @@ -0,0 +1,17 @@ +#include "qemu-common.h" +#include "migration/vmstate.h" + +int vmstate_register_with_alias_id(DeviceState *dev, + int instance_id, + const VMStateDescription *vmsd, + void *base, int alias_id, + int required_for_version) +{ + return 0; +} + +void vmstate_unregister(DeviceState *dev, + const VMStateDescription *vmsd, + void *opaque) +{ +} diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 212a6250ba..40e980933f 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -26,11 +26,9 @@ static void alpha_cpu_realize(Object *obj, Error **errp) { -#ifndef CONFIG_USER_ONLY AlphaCPU *cpu = ALPHA_CPU(obj); qemu_init_vcpu(&cpu->env); -#endif } /* Sort alphabetically by type name. */ diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 17875ed0f0..94536bb0cc 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -778,7 +778,7 @@ static void cpu_register(const ARMCPUInfo *info) .class_size = sizeof(ARMCPUClass), }; - type_register_static(&type_info); + type_register(&type_info); } static const TypeInfo arm_cpu_type_info = { diff --git a/target-arm/helper.c b/target-arm/helper.c index 0525aec87a..66ab78e3f1 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1736,7 +1736,7 @@ static void do_interrupt_v7m(CPUARMState *env) armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); return; case EXCP_SWI: - env->regs[15] += 2; + /* The PC already points to the next instruction. */ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC); return; case EXCP_PREFETCH_ABORT: diff --git a/target-i386/arch_memory_mapping.c b/target-i386/arch_memory_mapping.c index c6c7874474..844893f44d 100644 --- a/target-i386/arch_memory_mapping.c +++ b/target-i386/arch_memory_mapping.c @@ -115,7 +115,7 @@ static void walk_pde2(MemoryMappingList *list, hwaddr pde_start_addr, int32_t a20_mask, bool pse) { - hwaddr pde_addr, pte_start_addr, start_paddr; + hwaddr pde_addr, pte_start_addr, start_paddr, high_paddr; uint32_t pde; target_ulong line_addr, start_vaddr; int i; @@ -130,8 +130,13 @@ static void walk_pde2(MemoryMappingList *list, line_addr = (((unsigned int)i & 0x3ff) << 22); if ((pde & PG_PSE_MASK) && pse) { - /* 4 MB page */ - start_paddr = (pde & ~0x3fffff) | ((pde & 0x1fe000) << 19); + /* + * 4 MB page: + * bits 39:32 are bits 20:13 of the PDE + * bit3 31:22 are bits 31:22 of the PDE + */ + high_paddr = ((hwaddr)(pde & 0x1fe000) << 19); + start_paddr = (pde & ~0x3fffff) | high_paddr; if (cpu_physical_memory_is_io(start_paddr)) { /* I/O region */ continue; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 82685dc3f5..78bd61e18f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -124,15 +124,34 @@ static const char *cpuid_7_0_ebx_feature_name[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; +const char *get_register_name_32(unsigned int reg) +{ + static const char *reg_names[CPU_NB_REGS32] = { + [R_EAX] = "EAX", + [R_ECX] = "ECX", + [R_EDX] = "EDX", + [R_EBX] = "EBX", + [R_ESP] = "ESP", + [R_EBP] = "EBP", + [R_ESI] = "ESI", + [R_EDI] = "EDI", + }; + + if (reg > CPU_NB_REGS32) { + return NULL; + } + return reg_names[reg]; +} + /* collects per-function cpuid data */ typedef struct model_features_t { uint32_t *guest_feat; uint32_t *host_feat; - uint32_t check_feat; const char **flag_names; uint32_t cpuid; - } model_features_t; + int reg; +} model_features_t; int check_cpuid = 0; int enforce_cpuid = 0; @@ -388,6 +407,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "core2duo", .level = 10, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 15, .stepping = 11, @@ -432,6 +454,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "qemu32", .level = 4, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 3, .stepping = 3, @@ -442,6 +467,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "kvm32", .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 15, .model = 6, .stepping = 1, @@ -456,6 +484,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "coreduo", .level = 10, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 14, .stepping = 8, @@ -471,6 +502,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "486", .level = 1, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 4, .model = 0, .stepping = 0, @@ -480,6 +514,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium", .level = 1, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 5, .model = 4, .stepping = 3, @@ -489,6 +526,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium2", .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 5, .stepping = 2, @@ -498,6 +538,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium3", .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 7, .stepping = 3, @@ -523,6 +566,9 @@ static x86_def_t builtin_x86_defs[] = { .name = "n270", /* original is on level 10 */ .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 28, .stepping = 2, @@ -897,13 +943,12 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) } } - /* - * Every SVM feature requires emulation support in KVM - so we can't just - * read the host features here. KVM might even support SVM features not - * available on the host hardware. Just set all bits and mask out the - * unsupported ones later. - */ - x86_cpu_def->svm_features = -1; + /* Other KVM-specific feature fields: */ + x86_cpu_def->svm_features = + kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX); + x86_cpu_def->kvm_features = + kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX); + #endif /* CONFIG_KVM */ } @@ -913,18 +958,20 @@ static int unavailable_host_feature(struct model_features_t *f, uint32_t mask) for (i = 0; i < 32; ++i) if (1 << i & mask) { - fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested" - " flag '%s' [0x%08x]\n", - f->cpuid >> 16, f->cpuid & 0xffff, - f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask); + const char *reg = get_register_name_32(f->reg); + assert(reg); + fprintf(stderr, "warning: host doesn't support requested feature: " + "CPUID.%02XH:%s%s%s [bit %d]\n", + f->cpuid, reg, + f->flag_names[i] ? "." : "", + f->flag_names[i] ? f->flag_names[i] : "", i); break; } return 0; } /* best effort attempt to inform user requested cpu flags aren't making - * their way to the guest. Note: ft[].check_feat ideally should be - * specified via a guest_def field to suppress report of extraneous flags. + * their way to the guest. * * This function may be called only if KVM is enabled. */ @@ -935,20 +982,21 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) int rv, i; struct model_features_t ft[] = { {&guest_def->features, &host_def.features, - ~0, feature_name, 0x00000000}, + feature_name, 0x00000001, R_EDX}, {&guest_def->ext_features, &host_def.ext_features, - ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001}, + ext_feature_name, 0x00000001, R_ECX}, {&guest_def->ext2_features, &host_def.ext2_features, - ~PPRO_FEATURES, ext2_feature_name, 0x80000000}, + ext2_feature_name, 0x80000001, R_EDX}, {&guest_def->ext3_features, &host_def.ext3_features, - ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}}; + ext3_feature_name, 0x80000001, R_ECX} + }; assert(kvm_enabled()); kvm_cpu_fill_host(&host_def); for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) for (mask = 1; mask; mask <<= 1) - if (ft[i].check_feat & mask && *ft[i].guest_feat & mask && + if (*ft[i].guest_feat & mask && !(*ft[i].host_feat & mask)) { unavailable_host_feature(&ft[i], mask); rv = 1; @@ -1513,15 +1561,10 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) if (cpu_x86_parse_featurestr(def, features) < 0) { goto error; } - if (def->vendor1) { - env->cpuid_vendor1 = def->vendor1; - env->cpuid_vendor2 = def->vendor2; - env->cpuid_vendor3 = def->vendor3; - } else { - env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1; - env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2; - env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3; - } + assert(def->vendor1); + env->cpuid_vendor1 = def->vendor1; + env->cpuid_vendor2 = def->vendor2; + env->cpuid_vendor3 = def->vendor3; env->cpuid_vendor_override = def->vendor_override; object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); @@ -1540,31 +1583,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000, "tsc-frequency", &error); - /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on - * CPUID[1].EDX. - */ - if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && - env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && - env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) { - env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES; - env->cpuid_ext2_features |= (def->features & CPUID_EXT2_AMD_ALIASES); - } - - if (!kvm_enabled()) { - env->cpuid_features &= TCG_FEATURES; - env->cpuid_ext_features &= TCG_EXT_FEATURES; - env->cpuid_ext2_features &= (TCG_EXT2_FEATURES -#ifdef TARGET_X86_64 - | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM -#endif - ); - env->cpuid_ext3_features &= TCG_EXT3_FEATURES; - env->cpuid_svm_features &= TCG_SVM_FEATURES; - } else { -#ifdef CONFIG_KVM - filter_features_for_kvm(cpu); -#endif - } object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); @@ -2085,6 +2103,33 @@ void x86_cpu_realize(Object *obj, Error **errp) env->cpuid_level = 7; } + /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on + * CPUID[1].EDX. + */ + if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && + env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && + env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) { + env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES; + env->cpuid_ext2_features |= (env->cpuid_features + & CPUID_EXT2_AMD_ALIASES); + } + + if (!kvm_enabled()) { + env->cpuid_features &= TCG_FEATURES; + env->cpuid_ext_features &= TCG_EXT_FEATURES; + env->cpuid_ext2_features &= (TCG_EXT2_FEATURES +#ifdef TARGET_X86_64 + | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM +#endif + ); + env->cpuid_ext3_features &= TCG_EXT3_FEATURES; + env->cpuid_svm_features &= TCG_SVM_FEATURES; + } else { +#ifdef CONFIG_KVM + filter_features_for_kvm(cpu); +#endif + } + #ifndef CONFIG_USER_ONLY qemu_register_reset(x86_cpu_machine_reset_cb, cpu); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1283537108..e56921bbe3 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1220,4 +1220,7 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); void enable_kvm_pv_eoi(void); +/* Return name of 32-bit register, from a R_* constant */ +const char *get_register_name_32(unsigned int reg); + #endif /* CPU_I386_H */ diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 31602ac8ed..5963d62973 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -751,7 +751,7 @@ static inline void compute_hflags(CPUMIPSState *env) { env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | - MIPS_HFLAG_UX); + MIPS_HFLAG_UX | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index a33e2bf9fd..4870e3dbbc 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -2473,7 +2473,7 @@ DP_OB(dpsu_h_obr, 0, 24, 16, 8, 0, 24, 16, 8, 0); void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \ CPUMIPSState *env) \ { \ - uint16_t rsB, rsA, rtB, rtA; \ + int16_t rsB, rsA, rtB, rtA; \ int32_t tempA, tempB; \ int64_t acc; \ \ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d833d78b4f..d5c61e8a84 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2170,11 +2170,17 @@ static unsigned int ieee_rm[] = { float_round_down }; -#define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status) +static inline void restore_rounding_mode(CPUMIPSState *env) +{ + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], + &env->active_fpu.fp_status); +} -#define RESTORE_FLUSH_MODE \ - set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status) +static inline void restore_flush_mode(CPUMIPSState *env) +{ + set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, + &env->active_fpu.fp_status); +} target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) { @@ -2230,9 +2236,9 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t reg) return; } /* set rounding mode */ - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); /* set flush-to-zero mode */ - RESTORE_FLUSH_MODE; + restore_flush_mode(env); set_float_exception_flags(0, &env->active_fpu.fp_status); if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31)) do_raise_exception(env, EXCP_FPE, GETPC()); @@ -2464,7 +2470,7 @@ uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2479,7 +2485,7 @@ uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2494,7 +2500,7 @@ uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2509,7 +2515,7 @@ uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2576,7 +2582,7 @@ uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2591,7 +2597,7 @@ uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2606,7 +2612,7 @@ uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2621,7 +2627,7 @@ uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2636,7 +2642,7 @@ uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2651,7 +2657,7 @@ uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2666,7 +2672,7 @@ uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2681,7 +2687,7 @@ uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 237a0ed4f7..a028dcdcd0 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -1,7 +1,6 @@ -obj-y += translate.o helper.o +obj-y += translate.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o -obj-y += helper.o obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o @@ -9,4 +8,3 @@ obj-y += mmu_helper.o obj-y += timebase_helper.o obj-y += misc_helper.o obj-y += mem_helper.o -obj-y += mpic_helper.o diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index fb6b5a4119..b338f8fb56 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -50,6 +50,9 @@ typedef struct PowerPCCPUClass { /*< public >*/ void (*parent_reset)(CPUState *cpu); + + /* TODO inline fields here */ + ppc_def_t *info; } PowerPCCPUClass; /** @@ -73,5 +76,7 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) #define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e)) +PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); + #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e88ebe00d4..953146eeba 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1067,7 +1067,9 @@ struct CPUPPCState { target_ulong ivor_mask; target_ulong ivpr_mask; target_ulong hreset_vector; - hwaddr mpic_cpu_base; + hwaddr mpic_iack; + /* true when the external proxy facility mode is enabled */ + bool mpic_proxy; #endif /* Those resources are used only during code translation */ @@ -1156,10 +1158,6 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value); void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); -const ppc_def_t *ppc_find_by_pvr(uint32_t pvr); -const ppc_def_t *cpu_ppc_find_by_name (const char *name); -int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); - /* Time-base and decrementer management */ #ifndef NO_CPU_IO_DEFS uint64_t cpu_ppc_load_tbl (CPUPPCState *env); diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 5e34ad08a8..0a1ac86a42 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -84,7 +84,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) " => %08x (%02x)\n", env->nip, excp, env->error_code); /* new srr1 value excluding must-be-zero bits */ - msr = env->msr & ~0x783f0000ULL; + if (excp_model == POWERPC_EXCP_BOOKE) { + msr = env->msr; + } else { + msr = env->msr & ~0x783f0000ULL; + } /* new interrupt handler msr */ new_msr = env->msr & ((target_ulong)1 << MSR_ME); @@ -145,6 +149,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) srr1 = SPR_40x_SRR3; break; case POWERPC_EXCP_BOOKE: + /* FIXME: choose one or the other based on CPU type */ srr0 = SPR_BOOKE_MCSRR0; srr1 = SPR_BOOKE_MCSRR1; asrr0 = SPR_BOOKE_CSRR0; @@ -173,6 +178,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) if (lpes0 == 1) { new_msr |= (target_ulong)MSR_HVB; } + if (env->mpic_proxy) { + /* IACK the IRQ on delivery */ + env->spr[SPR_BOOKE_EPR] = ldl_phys(env->mpic_iack); + } goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ if (lpes1 == 0) { @@ -275,6 +284,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_DEBUG: /* Debug interrupt */ switch (excp_model) { case POWERPC_EXCP_BOOKE: + /* FIXME: choose one or the other based on CPU type */ srr0 = SPR_BOOKE_DSRR0; srr1 = SPR_BOOKE_DSRR1; asrr0 = SPR_BOOKE_CSRR0; @@ -836,8 +846,13 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, void helper_rfi(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], - ~((target_ulong)0x783F0000), 1); + if (env->excp_model == POWERPC_EXCP_BOOKE) { + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0), 0); + } else { + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0x783F0000), 1); + } } #if defined(TARGET_PPC64) @@ -864,20 +879,22 @@ void helper_40x_rfci(CPUPPCState *env) void helper_rfci(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, - ~((target_ulong)0x3FFF0000), 0); + do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], + ~((target_ulong)0), 0); } void helper_rfdi(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, - ~((target_ulong)0x3FFF0000), 0); + /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ + do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1], + ~((target_ulong)0), 0); } void helper_rfmci(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, - ~((target_ulong)0x3FFF0000), 0); + /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ + do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1], + ~((target_ulong)0), 0); } #endif diff --git a/target-ppc/helper.c b/target-ppc/helper.c deleted file mode 100644 index 103855afe0..0000000000 --- a/target-ppc/helper.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * PowerPC emulation helpers for QEMU. - * - * Copyright (c) 2003-2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "cpu.h" -#include "helper_regs.h" -#include "sysemu/kvm.h" -#include "kvm_ppc.h" -#include "sysemu/cpus.h" - -PowerPCCPU *cpu_ppc_init(const char *cpu_model) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - const ppc_def_t *def; - - def = cpu_ppc_find_by_name(cpu_model); - if (!def) { - return NULL; - } - - cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU)); - env = &cpu->env; - - if (tcg_enabled()) { - ppc_translate_init(); - } - - env->cpu_model_str = cpu_model; - cpu_ppc_register_internal(env, def); - - qemu_init_vcpu(env); - - return cpu; -} diff --git a/target-ppc/helper.h b/target-ppc/helper.h index d2e9a55f28..83139d5225 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -405,7 +405,6 @@ DEF_HELPER_2(store_40x_dbcr0, void, env, tl) DEF_HELPER_2(store_40x_sler, void, env, tl) DEF_HELPER_2(store_booke_tcr, void, env, tl) DEF_HELPER_2(store_booke_tsr, void, env, tl) -DEF_HELPER_1(load_epr, tl, env) DEF_HELPER_3(store_ibatl, void, env, i32, tl) DEF_HELPER_3(store_ibatu, void, env, i32, tl) DEF_HELPER_3(store_dbatl, void, env, i32, tl) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 436ca474ff..4846acfc0d 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -989,18 +989,38 @@ uint32_t kvmppc_get_dfp(void) return kvmppc_read_int_cpu_dt("ibm,dfp"); } +static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo) + { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs = CPU(cpu); + + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) && + !kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, pvinfo)) { + return 0; + } + + return 1; +} + +int kvmppc_get_hasidle(CPUPPCState *env) +{ + struct kvm_ppc_pvinfo pvinfo; + + if (!kvmppc_get_pvinfo(env, &pvinfo) && + (pvinfo.flags & KVM_PPC_PVINFO_FLAGS_EV_IDLE)) { + return 1; + } + + return 0; +} + int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); - CPUState *cs = CPU(cpu); uint32_t *hc = (uint32_t*)buf; - struct kvm_ppc_pvinfo pvinfo; - if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) && - !kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) { + if (!kvmppc_get_pvinfo(env, &pvinfo)) { memcpy(buf, pvinfo.hcall, buf_len); - return 0; } @@ -1210,18 +1230,37 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on) } } -const ppc_def_t *kvmppc_host_cpu_def(void) +static void kvmppc_host_cpu_initfn(Object *obj) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(obj); + + assert(kvm_enabled()); + + if (pcc->info->pvr != mfpvr()) { + fprintf(stderr, "Your host CPU is unsupported.\n" + "Please choose a supported model instead, see -cpu ?.\n"); + exit(1); + } +} + +static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); uint32_t host_pvr = mfpvr(); - const ppc_def_t *base_spec; + PowerPCCPUClass *pvr_pcc; ppc_def_t *spec; uint32_t vmx = kvmppc_get_vmx(); uint32_t dfp = kvmppc_get_dfp(); - base_spec = ppc_find_by_pvr(host_pvr); - spec = g_malloc0(sizeof(*spec)); - memcpy(spec, base_spec, sizeof(*spec)); + + pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); + if (pvr_pcc != NULL) { + memcpy(spec, pvr_pcc->info, sizeof(*spec)); + } + pcc->info = spec; + /* Override the display name for -cpu ? and QMP */ + pcc->info->name = "host"; /* Now fix up the spec with information we can query from the host */ @@ -1234,8 +1273,6 @@ const ppc_def_t *kvmppc_host_cpu_def(void) /* Only override when we know what the host supports */ alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); } - - return spec; } int kvmppc_fixup_cpu(CPUPPCState *env) @@ -1265,3 +1302,17 @@ int kvm_arch_on_sigbus(int code, void *addr) { return 1; } + +static const TypeInfo kvm_host_cpu_type_info = { + .name = TYPE_HOST_POWERPC_CPU, + .parent = TYPE_POWERPC_CPU, + .instance_init = kvmppc_host_cpu_initfn, + .class_init = kvmppc_host_cpu_class_init, +}; + +static void kvm_ppc_register_types(void) +{ + type_register_static(&kvm_host_cpu_type_info); +} + +type_init(kvm_ppc_register_types) diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 31eb9e6f22..4b2172360a 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -11,6 +11,8 @@ #include "exec/memory.h" +#define TYPE_HOST_POWERPC_CPU "host-" TYPE_POWERPC_CPU + void kvmppc_init(void); #ifdef CONFIG_KVM @@ -19,6 +21,7 @@ uint32_t kvmppc_get_tbfreq(void); uint64_t kvmppc_get_clockfreq(void); uint32_t kvmppc_get_vmx(void); uint32_t kvmppc_get_dfp(void); +int kvmppc_get_hasidle(CPUPPCState *env); int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); void kvmppc_set_papr(PowerPCCPU *cpu); @@ -30,7 +33,6 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); int kvmppc_reset_htab(int shift_hint); uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ -const ppc_def_t *kvmppc_host_cpu_def(void); int kvmppc_fixup_cpu(CPUPPCState *env); #else @@ -55,6 +57,11 @@ static inline uint32_t kvmppc_get_dfp(void) return 0; } +static inline int kvmppc_get_hasidle(CPUPPCState *env) +{ + return 0; +} + static inline int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) { return -1; @@ -115,11 +122,6 @@ static inline int kvmppc_update_sdr1(CPUPPCState *env) #endif /* !CONFIG_USER_ONLY */ -static inline const ppc_def_t *kvmppc_host_cpu_def(void) -{ - return NULL; -} - static inline int kvmppc_fixup_cpu(CPUPPCState *env) { return -1; diff --git a/target-ppc/mpic_helper.c b/target-ppc/mpic_helper.c deleted file mode 100644 index 2c6a4d30a9..0000000000 --- a/target-ppc/mpic_helper.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * PowerPC emulation helpers for QEMU. - * - * Copyright (c) 2003-2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ -#include "cpu.h" -#include "helper.h" - -/*****************************************************************************/ -/* SPR accesses */ - -#if !defined(CONFIG_USER_ONLY) -/* - * This is an ugly helper for EPR, which is basically the same as accessing - * the IACK (PIAC) register on the MPIC. Because we model the MPIC as a device - * that can only talk to the CPU through MMIO, let's access it that way! - */ -target_ulong helper_load_epr(CPUPPCState *env) -{ - return ldl_phys(env->mpic_cpu_base + 0xA0); -} -#endif diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 42ed748b59..2b03756ee1 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4493,11 +4493,6 @@ static void spr_read_mas73(void *opaque, int gprn, int sprn) tcg_temp_free(mas7); } -static void spr_load_epr(void *opaque, int gprn, int sprn) -{ - gen_helper_load_epr(cpu_gpr[gprn], cpu_env); -} - #endif enum fsl_e500_version { @@ -4656,7 +4651,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) 0x00000000); spr_register(env, SPR_BOOKE_EPR, "EPR", SPR_NOACCESS, SPR_NOACCESS, - &spr_load_epr, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX better abstract into Emb.xxx features */ if (version == fsl_e5500) { @@ -9797,8 +9792,11 @@ static void fix_opcode_tables (opc_handler_t **ppc_opcodes) } /*****************************************************************************/ -static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) +static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + const ppc_def_t *def = pcc->info; opcode_t *opc; fill_new_table(env->opcodes, 0x40); @@ -9806,18 +9804,16 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) if (((opc->handler.type & def->insns_flags) != 0) || ((opc->handler.type2 & def->insns_flags2) != 0)) { if (register_insn(env->opcodes, opc) < 0) { - printf("*** ERROR initializing PowerPC instruction " - "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, - opc->opc3); - return -1; + error_setg(errp, "ERROR initializing PowerPC instruction " + "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + opc->opc3); + return; } } } fix_opcode_tables(env->opcodes); fflush(stdout); fflush(stderr); - - return 0; } #if defined(PPC_DUMP_CPU) @@ -10031,53 +10027,31 @@ static int ppc_fixup_cpu(CPUPPCState *env) return 0; } -int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) +static void ppc_cpu_realize(Object *obj, Error **errp) { - env->msr_mask = def->msr_mask; - env->mmu_model = def->mmu_model; - env->excp_model = def->excp_model; - env->bus_model = def->bus_model; - env->insns_flags = def->insns_flags; - env->insns_flags2 = def->insns_flags2; - env->flags = def->flags; - env->bfd_mach = def->bfd_mach; - env->check_pow = def->check_pow; - -#if defined(TARGET_PPC64) - if (def->sps) - env->sps = *def->sps; - else if (env->mmu_model & POWERPC_MMU_64) { - /* Use default sets of page sizes */ - static const struct ppc_segment_page_sizes defsps = { - .sps = { - { .page_shift = 12, /* 4K */ - .slb_enc = 0, - .enc = { { .page_shift = 12, .pte_enc = 0 } } - }, - { .page_shift = 24, /* 16M */ - .slb_enc = 0x100, - .enc = { { .page_shift = 24, .pte_enc = 0 } } - }, - }, - }; - env->sps = defsps; - } -#endif /* defined(TARGET_PPC64) */ + PowerPCCPU *cpu = POWERPC_CPU(obj); + CPUPPCState *env = &cpu->env; + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + ppc_def_t *def = pcc->info; + Error *local_err = NULL; if (kvm_enabled()) { if (kvmppc_fixup_cpu(env) != 0) { - fprintf(stderr, "Unable to virtualize selected CPU with KVM\n"); - exit(1); + error_setg(errp, "Unable to virtualize selected CPU with KVM"); + return; } } else { if (ppc_fixup_cpu(env) != 0) { - fprintf(stderr, "Unable to emulate selected CPU with TCG\n"); - exit(1); + error_setg(errp, "Unable to emulate selected CPU with TCG"); + return; } } - if (create_ppc_opcodes(env, def) < 0) - return -1; + create_ppc_opcodes(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } init_ppc_proc(env, def); if (def->insns_flags & PPC_FLOAT) { @@ -10093,6 +10067,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) 34, "power-spe.xml", 0); } + qemu_init_vcpu(env); + #if defined(PPC_DUMP_CPU) { const char *mmu_model, *excp_model, *bus_model; @@ -10254,50 +10230,65 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) dump_ppc_sprs(env); fflush(stdout); #endif - - return 0; } -static bool ppc_cpu_usable(const ppc_def_t *def) +static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) { -#if defined(TARGET_PPCEMB) - /* When using the ppcemb target, we only support 440 style cores */ - if (def->mmu_model != POWERPC_MMU_BOOKE) { - return false; + ObjectClass *oc = (ObjectClass *)a; + uint32_t pvr = *(uint32_t *)b; + PowerPCCPUClass *pcc = (PowerPCCPUClass *)a; + + /* -cpu host does a PVR lookup during construction */ + if (unlikely(strcmp(object_class_get_name(oc), + TYPE_HOST_POWERPC_CPU) == 0)) { + return -1; } -#endif - return true; + return pcc->info->pvr == pvr ? 0 : -1; } -const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) +PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr) { - int i; - - for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } + GSList *list, *item; + PowerPCCPUClass *pcc = NULL; - /* If we have an exact match, we're done */ - if (pvr == ppc_defs[i].pvr) { - return &ppc_defs[i]; - } + list = object_class_get_list(TYPE_POWERPC_CPU, false); + item = g_slist_find_custom(list, &pvr, ppc_cpu_compare_class_pvr); + if (item != NULL) { + pcc = POWERPC_CPU_CLASS(item->data); } + g_slist_free(list); - return NULL; + return pcc; +} + +static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b) +{ + ObjectClass *oc = (ObjectClass *)a; + const char *name = b; + + if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 && + strcmp(object_class_get_name(oc) + strlen(name), + "-" TYPE_POWERPC_CPU) == 0) { + return 0; + } + return -1; } #include <ctype.h> -const ppc_def_t *cpu_ppc_find_by_name (const char *name) +static ObjectClass *ppc_cpu_class_by_name(const char *name) { - const ppc_def_t *ret; + GSList *list, *item; + ObjectClass *ret = NULL; const char *p; - int i, max, len; + int i, len; - if (kvm_enabled() && (strcasecmp(name, "host") == 0)) { - return kvmppc_host_cpu_def(); + if (strcasecmp(name, "host") == 0) { + if (kvm_enabled()) { + ret = object_class_by_name(TYPE_HOST_POWERPC_CPU); + } + return ret; } /* Check if the given name is a PVR */ @@ -10312,63 +10303,152 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) if (!qemu_isxdigit(*p++)) break; } - if (i == 8) - return ppc_find_by_pvr(strtoul(name, NULL, 16)); - } - ret = NULL; - max = ARRAY_SIZE(ppc_defs); - for (i = 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; + if (i == 8) { + ret = OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16))); + return ret; } + } - if (strcasecmp(name, ppc_defs[i].name) == 0) { - ret = &ppc_defs[i]; - break; - } + list = object_class_get_list(TYPE_POWERPC_CPU, false); + item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name); + if (item != NULL) { + ret = OBJECT_CLASS(item->data); } + g_slist_free(list); return ret; } -void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) +PowerPCCPU *cpu_ppc_init(const char *cpu_model) { - int i, max; + PowerPCCPU *cpu; + CPUPPCState *env; + ObjectClass *oc; + Error *err = NULL; - max = ARRAY_SIZE(ppc_defs); - for (i = 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } + oc = ppc_cpu_class_by_name(cpu_model); + if (oc == NULL) { + return NULL; + } + + cpu = POWERPC_CPU(object_new(object_class_get_name(oc))); + env = &cpu->env; - (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", - ppc_defs[i].name, ppc_defs[i].pvr); + if (tcg_enabled()) { + ppc_translate_init(); } + + env->cpu_model_str = cpu_model; + + ppc_cpu_realize(OBJECT(cpu), &err); + if (err != NULL) { + fprintf(stderr, "%s\n", error_get_pretty(err)); + error_free(err); + object_delete(OBJECT(cpu)); + return NULL; + } + + return cpu; +} + +/* Sort by PVR, ordering special case "host" last. */ +static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *oc_a = (ObjectClass *)a; + ObjectClass *oc_b = (ObjectClass *)b; + PowerPCCPUClass *pcc_a = POWERPC_CPU_CLASS(oc_a); + PowerPCCPUClass *pcc_b = POWERPC_CPU_CLASS(oc_b); + const char *name_a = object_class_get_name(oc_a); + const char *name_b = object_class_get_name(oc_b); + + if (strcmp(name_a, TYPE_HOST_POWERPC_CPU) == 0) { + return 1; + } else if (strcmp(name_b, TYPE_HOST_POWERPC_CPU) == 0) { + return -1; + } else { + /* Avoid an integer overflow during subtraction */ + if (pcc_a->info->pvr < pcc_b->info->pvr) { + return -1; + } else if (pcc_a->info->pvr > pcc_b->info->pvr) { + return 1; + } else { + return 0; + } + } +} + +static void ppc_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CPUListState *s = user_data; + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", + pcc->info->name, pcc->info->pvr); +} + +void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + CPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_POWERPC_CPU, false); + list = g_slist_sort(list, ppc_cpu_list_compare); + g_slist_foreach(list, ppc_cpu_list_entry, &s); + g_slist_free(list); +} + +static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **first = user_data; + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(pcc->info->name); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = *first; + *first = entry; } CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) { CpuDefinitionInfoList *cpu_list = NULL; - int i; + GSList *list; - for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { - CpuDefinitionInfoList *entry; - CpuDefinitionInfo *info; + list = object_class_get_list(TYPE_POWERPC_CPU, false); + g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list); + g_slist_free(list); - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } + return cpu_list; +} - info = g_malloc0(sizeof(*info)); - info->name = g_strdup(ppc_defs[i].name); +static void ppc_cpu_def_class_init(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + ppc_def_t *info = data; - entry = g_malloc0(sizeof(*entry)); - entry->value = info; - entry->next = cpu_list; - cpu_list = entry; - } + pcc->info = info; +} - return cpu_list; +static void ppc_cpu_register_model(const ppc_def_t *def) +{ + TypeInfo type_info = { + .parent = TYPE_POWERPC_CPU, + .class_init = ppc_cpu_def_class_init, + .class_data = (void *)def, + }; + + type_info.name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, def->name), + type_register(&type_info); + g_free((gpointer)type_info.name); } /* CPUClass::reset() */ @@ -10439,9 +10519,42 @@ static void ppc_cpu_reset(CPUState *s) static void ppc_cpu_initfn(Object *obj) { PowerPCCPU *cpu = POWERPC_CPU(obj); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; + ppc_def_t *def = pcc->info; cpu_exec_init(env); + + env->msr_mask = def->msr_mask; + env->mmu_model = def->mmu_model; + env->excp_model = def->excp_model; + env->bus_model = def->bus_model; + env->insns_flags = def->insns_flags; + env->insns_flags2 = def->insns_flags2; + env->flags = def->flags; + env->bfd_mach = def->bfd_mach; + env->check_pow = def->check_pow; + +#if defined(TARGET_PPC64) + if (def->sps) { + env->sps = *def->sps; + } else if (env->mmu_model & POWERPC_MMU_64) { + /* Use default sets of page sizes */ + static const struct ppc_segment_page_sizes defsps = { + .sps = { + { .page_shift = 12, /* 4K */ + .slb_enc = 0, + .enc = { { .page_shift = 12, .pte_enc = 0 } } + }, + { .page_shift = 24, /* 16M */ + .slb_enc = 0x100, + .enc = { { .page_shift = 24, .pte_enc = 0 } } + }, + }, + }; + env->sps = defsps; + } +#endif /* defined(TARGET_PPC64) */ } static void ppc_cpu_class_init(ObjectClass *oc, void *data) @@ -10458,14 +10571,27 @@ static const TypeInfo ppc_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(PowerPCCPU), .instance_init = ppc_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(PowerPCCPUClass), .class_init = ppc_cpu_class_init, }; static void ppc_cpu_register_types(void) { + int i; + type_register_static(&ppc_cpu_type_info); + + for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + const ppc_def_t *def = &ppc_defs[i]; +#if defined(TARGET_PPCEMB) + /* When using the ppcemb target, we only support 440 style cores */ + if (def->mmu_model != POWERPC_MMU_BOOKE) { + continue; + } +#endif + ppc_cpu_register_model(def); + } } type_init(ppc_cpu_register_types) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 19ef145da9..a6d60bf885 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -20,6 +20,7 @@ #include "cpu.h" #include "helper.h" +#include "qemu/host-utils.h" /* #define DEBUG_HELPER */ #ifdef DEBUG_HELPER @@ -28,8 +29,7 @@ #define HELPER_LOG(x...) #endif -static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, - int32_t dst) +static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst) { if (src == dst) { return 0; @@ -40,13 +40,12 @@ static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, } } -static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_ltgt0_32(int32_t dst) { - return cc_calc_ltgt_32(env, dst, 0); + return cc_calc_ltgt_32(dst, 0); } -static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, - int64_t dst) +static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst) { if (src == dst) { return 0; @@ -57,13 +56,12 @@ static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, } } -static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_ltgt0_64(int64_t dst) { - return cc_calc_ltgt_64(env, dst, 0); + return cc_calc_ltgt_64(dst, 0); } -static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, - uint32_t dst) +static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst) { if (src == dst) { return 0; @@ -74,8 +72,7 @@ static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, } } -static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, - uint64_t dst) +static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst) { if (src == dst) { return 0; @@ -86,13 +83,11 @@ static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, } } -static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, - uint32_t mask) +static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask) { - uint16_t r = val & mask; + uint32_t r = val & mask; - HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); - if (r == 0 || mask == 0) { + if (r == 0) { return 0; } else if (r == mask) { return 3; @@ -101,23 +96,17 @@ static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, } } -/* set condition code for test under mask */ -static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, - uint32_t mask) +static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask) { - uint16_t r = val & mask; + uint64_t r = val & mask; - HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); - if (r == 0 || mask == 0) { + if (r == 0) { return 0; } else if (r == mask) { return 3; } else { - while (!(mask & 0x8000)) { - mask <<= 1; - val <<= 1; - } - if (val & 0x8000) { + int top = clz64(mask); + if ((int64_t)(val << top) < 0) { return 2; } else { return 1; @@ -125,13 +114,12 @@ static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, } } -static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) +static uint32_t cc_calc_nz(uint64_t dst) { return !!dst; } -static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, - int64_t a2, int64_t ar) +static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar) { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { return 3; /* overflow */ @@ -146,26 +134,22 @@ static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, } } -static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_addu_64(uint64_t a1, uint64_t a2, uint64_t ar) { - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } + return (ar != 0) + 2 * (ar < a1); +} + +static uint32_t cc_calc_addc_64(uint64_t a1, uint64_t a2, uint64_t ar) +{ + /* Recover a2 + carry_in. */ + uint64_t a2c = ar - a1; + /* Check for a2+carry_in overflow, then a1+a2c overflow. */ + int carry_out = (a2c < a2) || (ar < a1); + + return (ar != 0) + 2 * carry_out; } -static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, - int64_t a2, int64_t ar) +static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar) { if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -180,8 +164,7 @@ static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, } } -static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar) { if (ar == 0) { return 2; @@ -194,7 +177,25 @@ static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, } } -static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar) +{ + /* We had borrow-in if normal subtraction isn't equal. */ + int borrow_in = ar - (a1 - a2); + int borrow_out; + + /* If a2 was ULONG_MAX, and borrow_in, then a2 is logically 65 bits, + and we must have had borrow out. */ + if (borrow_in && a2 == (uint64_t)-1) { + borrow_out = 1; + } else { + a2 += borrow_in; + borrow_out = (a2 > a1); + } + + return (ar != 0) + 2 * !borrow_out; +} + +static uint32_t cc_calc_abs_64(int64_t dst) { if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; @@ -205,12 +206,12 @@ static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) } } -static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_nabs_64(int64_t dst) { return !!dst; } -static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_comp_64(int64_t dst) { if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; @@ -224,8 +225,7 @@ static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) } -static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, - int32_t a2, int32_t ar) +static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar) { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { return 3; /* overflow */ @@ -240,26 +240,22 @@ static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, } } -static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_addu_32(uint32_t a1, uint32_t a2, uint32_t ar) { - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } + return (ar != 0) + 2 * (ar < a1); +} + +static uint32_t cc_calc_addc_32(uint32_t a1, uint32_t a2, uint32_t ar) +{ + /* Recover a2 + carry_in. */ + uint32_t a2c = ar - a1; + /* Check for a2+carry_in overflow, then a1+a2c overflow. */ + int carry_out = (a2c < a2) || (ar < a1); + + return (ar != 0) + 2 * carry_out; } -static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, - int32_t a2, int32_t ar) +static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar) { if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -274,8 +270,7 @@ static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, } } -static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar) { if (ar == 0) { return 2; @@ -288,7 +283,25 @@ static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, } } -static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar) +{ + /* We had borrow-in if normal subtraction isn't equal. */ + int borrow_in = ar - (a1 - a2); + int borrow_out; + + /* If a2 was UINT_MAX, and borrow_in, then a2 is logically 65 bits, + and we must have had borrow out. */ + if (borrow_in && a2 == (uint32_t)-1) { + borrow_out = 1; + } else { + a2 += borrow_in; + borrow_out = (a2 > a1); + } + + return (ar != 0) + 2 * !borrow_out; +} + +static uint32_t cc_calc_abs_32(int32_t dst) { if ((uint32_t)dst == 0x80000000UL) { return 3; @@ -299,12 +312,12 @@ static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) } } -static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_nabs_32(int32_t dst) { return !!dst; } -static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_comp_32(int32_t dst) { if ((uint32_t)dst == 0x80000000UL) { return 3; @@ -318,69 +331,80 @@ static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) } /* calculate condition code for insert character under mask insn */ -static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, - uint32_t val) +static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) { - uint32_t cc; - - HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); - if (mask == 0xf) { - if (!val) { - return 0; - } else if (val & 0x80000000) { + if ((val & mask) == 0) { + return 0; + } else { + int top = clz64(mask); + if ((int64_t)(val << top) < 0) { return 1; } else { return 2; } } +} + +static uint32_t cc_calc_sla_32(uint32_t src, int shift) +{ + uint32_t mask = ((1U << shift) - 1U) << (32 - shift); + uint32_t sign = 1U << 31; + uint32_t match; + int32_t r; - if (!val || !mask) { - cc = 0; + /* Check if the sign bit stays the same. */ + if (src & sign) { + match = mask; } else { - while (mask != 1) { - mask >>= 1; - val >>= 8; - } - if (val & 0x80) { - cc = 1; - } else { - cc = 2; - } + match = 0; } - return cc; + if ((src & mask) != match) { + /* Overflow. */ + return 3; + } + + r = ((src << shift) & ~sign) | (src & sign); + if (r == 0) { + return 0; + } else if (r < 0) { + return 1; + } + return 2; } -static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, - uint64_t shift) +static uint32_t cc_calc_sla_64(uint64_t src, int shift) { uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); - uint64_t match, r; + uint64_t sign = 1ULL << 63; + uint64_t match; + int64_t r; - /* check if the sign bit stays the same */ - if (src & (1ULL << 63)) { + /* Check if the sign bit stays the same. */ + if (src & sign) { match = mask; } else { match = 0; } - if ((src & mask) != match) { - /* overflow */ + /* Overflow. */ return 3; } - r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); - - if ((int64_t)r == 0) { + r = ((src << shift) & ~sign) | (src & sign); + if (r == 0) { return 0; - } else if ((int64_t)r < 0) { + } else if (r < 0) { return 1; } - return 2; } +static uint32_t cc_calc_flogr(uint64_t dst) +{ + return dst ? 2 : 0; +} -static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, +static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) { uint32_t r = 0; @@ -394,95 +418,110 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, r = cc_op; break; case CC_OP_LTGT0_32: - r = cc_calc_ltgt0_32(env, dst); + r = cc_calc_ltgt0_32(dst); break; case CC_OP_LTGT0_64: - r = cc_calc_ltgt0_64(env, dst); + r = cc_calc_ltgt0_64(dst); break; case CC_OP_LTGT_32: - r = cc_calc_ltgt_32(env, src, dst); + r = cc_calc_ltgt_32(src, dst); break; case CC_OP_LTGT_64: - r = cc_calc_ltgt_64(env, src, dst); + r = cc_calc_ltgt_64(src, dst); break; case CC_OP_LTUGTU_32: - r = cc_calc_ltugtu_32(env, src, dst); + r = cc_calc_ltugtu_32(src, dst); break; case CC_OP_LTUGTU_64: - r = cc_calc_ltugtu_64(env, src, dst); + r = cc_calc_ltugtu_64(src, dst); break; case CC_OP_TM_32: - r = cc_calc_tm_32(env, src, dst); + r = cc_calc_tm_32(src, dst); break; case CC_OP_TM_64: - r = cc_calc_tm_64(env, src, dst); + r = cc_calc_tm_64(src, dst); break; case CC_OP_NZ: - r = cc_calc_nz(env, dst); + r = cc_calc_nz(dst); break; case CC_OP_ADD_64: - r = cc_calc_add_64(env, src, dst, vr); + r = cc_calc_add_64(src, dst, vr); break; case CC_OP_ADDU_64: - r = cc_calc_addu_64(env, src, dst, vr); + r = cc_calc_addu_64(src, dst, vr); + break; + case CC_OP_ADDC_64: + r = cc_calc_addc_64(src, dst, vr); break; case CC_OP_SUB_64: - r = cc_calc_sub_64(env, src, dst, vr); + r = cc_calc_sub_64(src, dst, vr); break; case CC_OP_SUBU_64: - r = cc_calc_subu_64(env, src, dst, vr); + r = cc_calc_subu_64(src, dst, vr); + break; + case CC_OP_SUBB_64: + r = cc_calc_subb_64(src, dst, vr); break; case CC_OP_ABS_64: - r = cc_calc_abs_64(env, dst); + r = cc_calc_abs_64(dst); break; case CC_OP_NABS_64: - r = cc_calc_nabs_64(env, dst); + r = cc_calc_nabs_64(dst); break; case CC_OP_COMP_64: - r = cc_calc_comp_64(env, dst); + r = cc_calc_comp_64(dst); break; case CC_OP_ADD_32: - r = cc_calc_add_32(env, src, dst, vr); + r = cc_calc_add_32(src, dst, vr); break; case CC_OP_ADDU_32: - r = cc_calc_addu_32(env, src, dst, vr); + r = cc_calc_addu_32(src, dst, vr); + break; + case CC_OP_ADDC_32: + r = cc_calc_addc_32(src, dst, vr); break; case CC_OP_SUB_32: - r = cc_calc_sub_32(env, src, dst, vr); + r = cc_calc_sub_32(src, dst, vr); break; case CC_OP_SUBU_32: - r = cc_calc_subu_32(env, src, dst, vr); + r = cc_calc_subu_32(src, dst, vr); + break; + case CC_OP_SUBB_32: + r = cc_calc_subb_32(src, dst, vr); break; case CC_OP_ABS_32: - r = cc_calc_abs_64(env, dst); + r = cc_calc_abs_32(dst); break; case CC_OP_NABS_32: - r = cc_calc_nabs_64(env, dst); + r = cc_calc_nabs_32(dst); break; case CC_OP_COMP_32: - r = cc_calc_comp_32(env, dst); + r = cc_calc_comp_32(dst); break; case CC_OP_ICM: - r = cc_calc_icm_32(env, src, dst); + r = cc_calc_icm(src, dst); break; - case CC_OP_SLAG: - r = cc_calc_slag(env, src, dst); + case CC_OP_SLA_32: + r = cc_calc_sla_32(src, dst); break; - - case CC_OP_LTGT_F32: - r = set_cc_f32(env, src, dst); + case CC_OP_SLA_64: + r = cc_calc_sla_64(src, dst); break; - case CC_OP_LTGT_F64: - r = set_cc_f64(env, src, dst); + case CC_OP_FLOGR: + r = cc_calc_flogr(dst); break; + case CC_OP_NZ_F32: r = set_cc_nz_f32(dst); break; case CC_OP_NZ_F64: r = set_cc_nz_f64(dst); break; + case CC_OP_NZ_F128: + r = set_cc_nz_f128(make_float128(src, dst)); + break; default: cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); @@ -505,18 +544,6 @@ uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, return do_calc_cc(env, cc_op, src, dst, vr); } -/* insert psw mask and condition code into r1 */ -void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1) -{ - uint64_t r = env->regs[r1]; - - r &= 0xffffffff00ffffffULL; - r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); - env->regs[r1] = r; - HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, - cc, env->psw.mask, r); -} - #ifndef CONFIG_USER_ONLY void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) { diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index cd565c91de..bc3fab226b 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -60,17 +60,20 @@ typedef struct ExtQueue { } ExtQueue; typedef struct CPUS390XState { - uint64_t regs[16]; /* GP registers */ + uint64_t regs[16]; /* GP registers */ + CPU_DoubleU fregs[16]; /* FP registers */ + uint32_t aregs[16]; /* access registers */ - uint32_t aregs[16]; /* access registers */ + uint32_t fpc; /* floating-point control register */ + uint32_t cc_op; - uint32_t fpc; /* floating-point control register */ - CPU_DoubleU fregs[16]; /* FP registers */ float_status fpu_status; /* passed to softfloat lib */ + /* The low part of a 128-bit return, or remainder of a divide. */ + uint64_t retxl; + PSW psw; - uint32_t cc_op; uint64_t cc_src; uint64_t cc_dst; uint64_t cc_vr; @@ -79,15 +82,15 @@ typedef struct CPUS390XState { uint64_t psa; uint32_t int_pgm_code; - uint32_t int_pgm_ilc; + uint32_t int_pgm_ilen; uint32_t int_svc_code; - uint32_t int_svc_ilc; + uint32_t int_svc_ilen; uint64_t cregs[16]; /* control registers */ - int pending_int; ExtQueue ext_queue[MAX_EXT_QUEUE]; + int pending_int; int ext_index; @@ -113,7 +116,7 @@ static inline void cpu_clone_regs(CPUS390XState *env, target_ulong newsp) if (newsp) { env->regs[15] = newsp; } - env->regs[0] = 0; + env->regs[2] = 0; } #endif @@ -253,25 +256,31 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); } -static inline int get_ilc(uint8_t opc) +/* While the PoO talks about ILC (a number between 1-3) what is actually + stored in LowCore is shifted left one bit (an even between 2-6). As + this is the actual length of the insn and therefore more useful, that + is what we want to pass around and manipulate. To make sure that we + have applied this distinction universally, rename the "ILC" to "ILEN". */ +static inline int get_ilen(uint8_t opc) { switch (opc >> 6) { case 0: - return 1; + return 2; case 1: case 2: - return 2; - case 3: - return 3; + return 4; + default: + return 6; } - - return 0; } -#define ILC_LATER 0x20 -#define ILC_LATER_INC 0x21 -#define ILC_LATER_INC_2 0x22 - +#ifndef CONFIG_USER_ONLY +/* In several cases of runtime exceptions, we havn't recorded the true + instruction length. Use these codes when raising exceptions in order + to re-compute the length by examining the insn in memory. */ +#define ILEN_LATER 0x20 +#define ILEN_LATER_INC 0x21 +#endif S390CPU *cpu_s390x_init(const char *cpu_model); void s390x_translate_init(void); @@ -352,21 +361,10 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) #include "exec/exec-all.h" -#ifdef CONFIG_USER_ONLY - -#define EXCP_OPEX 1 /* operation exception (sigill) */ -#define EXCP_SVC 2 /* supervisor call (syscall) */ -#define EXCP_ADDR 5 /* addressing exception */ -#define EXCP_SPEC 6 /* specification exception */ - -#else - #define EXCP_EXT 1 /* external interrupt */ #define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_PGM 3 /* program interruption */ -#endif /* CONFIG_USER_ONLY */ - #define INTERRUPT_EXT (1 << 0) #define INTERRUPT_TOD (1 << 1) #define INTERRUPT_CPUTIMER (1 << 2) @@ -430,79 +428,6 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) /* Total. */ #define S390_NUM_REGS 51 -/* Pseudo registers -- PC and condition code. */ -#define S390_PC_REGNUM S390_NUM_REGS -#define S390_CC_REGNUM (S390_NUM_REGS+1) -#define S390_NUM_PSEUDO_REGS 2 -#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) - - - -/* Program Status Word. */ -#define S390_PSWM_REGNUM 0 -#define S390_PSWA_REGNUM 1 -/* General Purpose Registers. */ -#define S390_R0_REGNUM 2 -#define S390_R1_REGNUM 3 -#define S390_R2_REGNUM 4 -#define S390_R3_REGNUM 5 -#define S390_R4_REGNUM 6 -#define S390_R5_REGNUM 7 -#define S390_R6_REGNUM 8 -#define S390_R7_REGNUM 9 -#define S390_R8_REGNUM 10 -#define S390_R9_REGNUM 11 -#define S390_R10_REGNUM 12 -#define S390_R11_REGNUM 13 -#define S390_R12_REGNUM 14 -#define S390_R13_REGNUM 15 -#define S390_R14_REGNUM 16 -#define S390_R15_REGNUM 17 -/* Access Registers. */ -#define S390_A0_REGNUM 18 -#define S390_A1_REGNUM 19 -#define S390_A2_REGNUM 20 -#define S390_A3_REGNUM 21 -#define S390_A4_REGNUM 22 -#define S390_A5_REGNUM 23 -#define S390_A6_REGNUM 24 -#define S390_A7_REGNUM 25 -#define S390_A8_REGNUM 26 -#define S390_A9_REGNUM 27 -#define S390_A10_REGNUM 28 -#define S390_A11_REGNUM 29 -#define S390_A12_REGNUM 30 -#define S390_A13_REGNUM 31 -#define S390_A14_REGNUM 32 -#define S390_A15_REGNUM 33 -/* Floating Point Control Word. */ -#define S390_FPC_REGNUM 34 -/* Floating Point Registers. */ -#define S390_F0_REGNUM 35 -#define S390_F1_REGNUM 36 -#define S390_F2_REGNUM 37 -#define S390_F3_REGNUM 38 -#define S390_F4_REGNUM 39 -#define S390_F5_REGNUM 40 -#define S390_F6_REGNUM 41 -#define S390_F7_REGNUM 42 -#define S390_F8_REGNUM 43 -#define S390_F9_REGNUM 44 -#define S390_F10_REGNUM 45 -#define S390_F11_REGNUM 46 -#define S390_F12_REGNUM 47 -#define S390_F13_REGNUM 48 -#define S390_F14_REGNUM 49 -#define S390_F15_REGNUM 50 -/* Total. */ -#define S390_NUM_REGS 51 - -/* Pseudo registers -- PC and condition code. */ -#define S390_PC_REGNUM S390_NUM_REGS -#define S390_CC_REGNUM (S390_NUM_REGS+1) -#define S390_NUM_PSEUDO_REGS 2 -#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) - /* CC optimization */ enum cc_op { @@ -524,15 +449,19 @@ enum cc_op { CC_OP_ADD_64, /* overflow on add (64bit) */ CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */ + CC_OP_ADDC_64, /* overflow on unsigned add-carry (64bit) */ CC_OP_SUB_64, /* overflow on subtraction (64bit) */ CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */ + CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */ CC_OP_ABS_64, /* sign eval on abs (64bit) */ CC_OP_NABS_64, /* sign eval on nabs (64bit) */ CC_OP_ADD_32, /* overflow on add (32bit) */ CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ + CC_OP_ADDC_32, /* overflow on unsigned add-carry (32bit) */ CC_OP_SUB_32, /* overflow on subtraction (32bit) */ CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */ + CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */ CC_OP_ABS_32, /* sign eval on abs (64bit) */ CC_OP_NABS_32, /* sign eval on nabs (64bit) */ @@ -542,14 +471,14 @@ enum cc_op { CC_OP_TM_32, /* test under mask (32bit) */ CC_OP_TM_64, /* test under mask (64bit) */ - CC_OP_LTGT_F32, /* FP compare (32bit) */ - CC_OP_LTGT_F64, /* FP compare (64bit) */ - CC_OP_NZ_F32, /* FP dst != 0 (32bit) */ CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ + CC_OP_NZ_F128, /* FP dst != 0 (128bit) */ CC_OP_ICM, /* insert characters under mask */ - CC_OP_SLAG, /* Calculate shift left signed */ + CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ + CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ + CC_OP_FLOGR, /* find leftmost one */ CC_OP_MAX }; @@ -569,26 +498,31 @@ static const char *cc_names[] = { [CC_OP_LTGT0_64] = "CC_OP_LTGT0_64", [CC_OP_ADD_64] = "CC_OP_ADD_64", [CC_OP_ADDU_64] = "CC_OP_ADDU_64", + [CC_OP_ADDC_64] = "CC_OP_ADDC_64", [CC_OP_SUB_64] = "CC_OP_SUB_64", [CC_OP_SUBU_64] = "CC_OP_SUBU_64", + [CC_OP_SUBB_64] = "CC_OP_SUBB_64", [CC_OP_ABS_64] = "CC_OP_ABS_64", [CC_OP_NABS_64] = "CC_OP_NABS_64", [CC_OP_ADD_32] = "CC_OP_ADD_32", [CC_OP_ADDU_32] = "CC_OP_ADDU_32", + [CC_OP_ADDC_32] = "CC_OP_ADDC_32", [CC_OP_SUB_32] = "CC_OP_SUB_32", [CC_OP_SUBU_32] = "CC_OP_SUBU_32", + [CC_OP_SUBB_32] = "CC_OP_SUBB_32", [CC_OP_ABS_32] = "CC_OP_ABS_32", [CC_OP_NABS_32] = "CC_OP_NABS_32", [CC_OP_COMP_32] = "CC_OP_COMP_32", [CC_OP_COMP_64] = "CC_OP_COMP_64", [CC_OP_TM_32] = "CC_OP_TM_32", [CC_OP_TM_64] = "CC_OP_TM_64", - [CC_OP_LTGT_F32] = "CC_OP_LTGT_F32", - [CC_OP_LTGT_F64] = "CC_OP_LTGT_F64", [CC_OP_NZ_F32] = "CC_OP_NZ_F32", [CC_OP_NZ_F64] = "CC_OP_NZ_F64", + [CC_OP_NZ_F128] = "CC_OP_NZ_F128", [CC_OP_ICM] = "CC_OP_ICM", - [CC_OP_SLAG] = "CC_OP_SLAG", + [CC_OP_SLA_32] = "CC_OP_SLA_32", + [CC_OP_SLA_64] = "CC_OP_SLA_64", + [CC_OP_FLOGR] = "CC_OP_FLOGR", }; static inline const char *cc_name(int cc_op) @@ -605,9 +539,9 @@ typedef struct LowCore uint32_t ext_params; /* 0x080 */ uint16_t cpu_addr; /* 0x084 */ uint16_t ext_int_code; /* 0x086 */ - uint16_t svc_ilc; /* 0x088 */ + uint16_t svc_ilen; /* 0x088 */ uint16_t svc_code; /* 0x08a */ - uint16_t pgm_ilc; /* 0x08c */ + uint16_t pgm_ilen; /* 0x08c */ uint16_t pgm_code; /* 0x08e */ uint32_t data_exc_code; /* 0x090 */ uint16_t mon_class_num; /* 0x094 */ @@ -991,12 +925,13 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) } /* fpu_helper.c */ -uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2); -uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2); uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); +uint32_t set_cc_nz_f128(float128 v); /* misc_helper.c */ -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); +void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, + uintptr_t retaddr); #endif diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 173f820428..94375b6a63 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -32,6 +32,52 @@ #define HELPER_LOG(x...) #endif +#define RET128(F) (env->retxl = F.low, F.high) + +#define convert_bit(mask, from, to) \ + (to < from \ + ? (mask / (from / to)) & to \ + : (mask & from) * (to / from)) + +static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr) +{ + /* Install the DXC code. */ + env->fpc = (env->fpc & ~0xff00) | (dxc << 8); + /* Trap. */ + runtime_exception(env, PGM_DATA, retaddr); +} + +/* Should be called after any operation that may raise IEEE exceptions. */ +static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr) +{ + unsigned s390_exc, qemu_exc; + + /* Get the exceptions raised by the current operation. Reset the + fpu_status contents so that the next operation has a clean slate. */ + qemu_exc = env->fpu_status.float_exception_flags; + if (qemu_exc == 0) { + return; + } + env->fpu_status.float_exception_flags = 0; + + /* Convert softfloat exception bits to s390 exception bits. */ + s390_exc = 0; + s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80); + s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40); + s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20); + s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10); + s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08); + + /* Install the exceptions that we raised. */ + env->fpc |= s390_exc << 16; + + /* Send signals for enabled exceptions. */ + s390_exc &= env->fpc >> 24; + if (s390_exc) { + ieee_exception(env, s390_exc, retaddr); + } +} + static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) { switch (float_compare) { @@ -48,19 +94,6 @@ static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) } } -/* condition codes for binary FP ops */ -uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2) -{ - return float_comp_to_cc(env, float32_compare_quiet(v1, v2, - &env->fpu_status)); -} - -uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2) -{ - return float_comp_to_cc(env, float64_compare_quiet(v1, v2, - &env->fpu_status)); -} - /* condition codes for unary FP ops */ uint32_t set_cc_nz_f32(float32 v) { @@ -88,7 +121,7 @@ uint32_t set_cc_nz_f64(float64 v) } } -static uint32_t set_cc_nz_f128(float128 v) +uint32_t set_cc_nz_f128(float128 v) { if (float128_is_any_nan(v)) { return 3; @@ -101,433 +134,211 @@ static uint32_t set_cc_nz_f128(float128 v) } } -/* convert 32-bit int to 64-bit float */ -void HELPER(cdfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) +/* 32-bit FP addition */ +uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); - env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); + float32 ret = float32_add(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 32-bit int to 128-bit float */ -void HELPER(cxfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) +/* 64-bit FP addition */ +uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - CPU_QuadU v1; - - v1.q = int32_to_float128(v2, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; + float64 ret = float64_add(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 64-bit int to 32-bit float */ -void HELPER(cegbr)(CPUS390XState *env, uint32_t f1, int64_t v2) +/* 128-bit FP addition */ +uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) { - HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); - env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); + float128 ret = float128_add(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } -/* convert 64-bit int to 64-bit float */ -void HELPER(cdgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) +/* 32-bit FP subtraction */ +uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); - env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); + float32 ret = float32_sub(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 64-bit int to 128-bit float */ -void HELPER(cxgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) +/* 64-bit FP subtraction */ +uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - CPU_QuadU x1; - - x1.q = int64_to_float128(v2, &env->fpu_status); - HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, - x1.ll.upper, x1.ll.lower); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; + float64 ret = float64_sub(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 32-bit int to 32-bit float */ -void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2) +/* 128-bit FP subtraction */ +uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) { - env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); - HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, - env->fregs[f1].l.upper, f1); + float128 ret = float128_sub(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } -/* 32-bit FP addition RR */ -uint32_t HELPER(aebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP division */ +uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); + float32 ret = float32_div(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP addition RR */ -uint32_t HELPER(adbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP division */ +uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, - env->fregs[f2].d, env->fregs[f1].d, f1); - - return set_cc_nz_f64(env->fregs[f1].d); + float64 ret = float64_div(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 32-bit FP subtraction RR */ -uint32_t HELPER(sebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 128-bit FP division */ +uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) { - env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); + float128 ret = float128_div(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } -/* 64-bit FP subtraction RR */ -uint32_t HELPER(sdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP multiplication */ +uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", - __func__, env->fregs[f2].d, env->fregs[f1].d, f1); - - return set_cc_nz_f64(env->fregs[f1].d); + float32 ret = float32_mul(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 32-bit FP division RR */ -void HELPER(debr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP multiplication */ +uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); + float64 ret = float64_mul(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 128-bit FP division RR */ -void HELPER(dxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64/32-bit FP multiplication */ +uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_div(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; + float64 ret = float32_to_float64(f2, &env->fpu_status); + ret = float64_mul(f1, ret, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP multiplication RR */ -void HELPER(mdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 128-bit FP multiplication */ +uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) { - env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); + float128 ret = float128_mul(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } -/* 128-bit FP multiplication RR */ -void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 128/64-bit FP multiplication */ +uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t f2) { - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_mul(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; + float128 ret = float64_to_float128(f2, &env->fpu_status); + ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* convert 32-bit float to 64-bit float */ -void HELPER(ldebr)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) { - env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, - &env->fpu_status); + float64 ret = float32_to_float64(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 64-bit float */ -void HELPER(ldxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al) { - CPU_QuadU x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); + float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 64-bit float to 128-bit float */ -void HELPER(lxdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU res; - - res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; -} - -/* convert 64-bit float to 32-bit float */ -void HELPER(ledbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - float64 d2 = env->fregs[f2].d; - - env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); -} - -/* convert 128-bit float to 32-bit float */ -void HELPER(lexbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); -} - -/* absolute value of 32-bit float */ -uint32_t HELPER(lpebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - float32 v1; - float32 v2 = env->fregs[f2].d; - - v1 = float32_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f32(v1); -} - -/* absolute value of 64-bit float */ -uint32_t HELPER(lpdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - float64 v1; - float64 v2 = env->fregs[f2].d; - - v1 = float64_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f64(v1); -} - -/* absolute value of 128-bit float */ -uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - v1.q = float128_abs(v2.q); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; - return set_cc_nz_f128(v1.q); -} - -/* load and test 64-bit float */ -uint32_t HELPER(ltdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = env->fregs[f2].d; - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load and test 32-bit float */ -uint32_t HELPER(ltebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = env->fregs[f2].l.upper; - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load and test 128-bit float */ -uint32_t HELPER(ltxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU x; - - x.ll.upper = env->fregs[f2].ll; - x.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 2].ll = x.ll.lower; - return set_cc_nz_f128(x.q); -} - -/* load complement of 32-bit float */ -uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load complement of 64-bit float */ -uint32_t HELPER(lcdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_chs(env->fregs[f2].d); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load complement of 128-bit float */ -uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU x1, x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - x1.q = float128_chs(x2.q); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; - return set_cc_nz_f128(x1.q); -} - -/* 32-bit FP addition RM */ -void HELPER(aeb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); -} - -/* 32-bit FP division RM */ -void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); -} - -/* 32-bit FP multiplication RM */ -void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) +uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) { - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); + float128 ret = float64_to_float128(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } -/* 32-bit FP compare RR */ -uint32_t HELPER(cebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* convert 32-bit float to 128-bit float */ +uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2) { - float32 v1 = env->fregs[f1].l.upper; - float32 v2 = env->fregs[f2].l.upper; - - HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2); - return set_cc_f32(env, v1, v2); + float128 ret = float32_to_float128(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } -/* 64-bit FP compare RR */ -uint32_t HELPER(cdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - float64 v1 = env->fregs[f1].d; - float64 v2 = env->fregs[f2].d; - - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, - v1, f1, v2); - return set_cc_f64(env, v1, v2); -} - -/* 128-bit FP compare RR */ -uint32_t HELPER(cxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - - return float_comp_to_cc(env, float128_compare_quiet(v1.q, v2.q, - &env->fpu_status)); -} - -/* 64-bit FP compare RM */ -uint32_t HELPER(cdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +/* convert 64-bit float to 32-bit float */ +uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2) { - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, - f1, v2.d); - return set_cc_f64(env, v1, v2.d); + float32 ret = float64_to_float32(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP addition RM */ -uint32_t HELPER(adb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +/* convert 128-bit float to 32-bit float */ +uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al) { - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); + float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 32-bit FP subtraction RM */ -void HELPER(seb)(CPUS390XState *env, uint32_t f1, uint32_t val) +/* 32-bit FP compare */ +uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); + int cmp = float32_compare_quiet(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } -/* 64-bit FP subtraction RM */ -uint32_t HELPER(sdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +/* 64-bit FP compare */ +uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); + int cmp = float64_compare_quiet(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } -/* 64-bit FP multiplication RM */ -void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +/* 128-bit FP compare */ +uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) { - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); + int cmp = float128_compare_quiet(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } -/* 64-bit FP division RM */ -void HELPER(ddb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); -} - -static void set_round_mode(CPUS390XState *env, int m3) +static int swap_round_mode(CPUS390XState *env, int m3) { + int ret = env->fpu_status.float_rounding_mode; switch (m3) { case 0: /* current mode */ @@ -551,232 +362,242 @@ static void set_round_mode(CPUS390XState *env, int m3) set_float_rounding_mode(float_round_down, &env->fpu_status); break; } + return ret; } -/* convert 32-bit float to 64-bit int */ -uint32_t HELPER(cgebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +/* convert 64-bit int to 32-bit float */ +uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m3) { - float32 v2 = env->fregs[f2].l.upper; - - set_round_mode(env, m3); - env->regs[r1] = float32_to_int64(v2, &env->fpu_status); - return set_cc_nz_f32(v2); + int hold = swap_round_mode(env, m3); + float32 ret = int64_to_float32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 64-bit float to 64-bit int */ -uint32_t HELPER(cgdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +/* convert 64-bit int to 64-bit float */ +uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m3) { - float64 v2 = env->fregs[f2].d; - - set_round_mode(env, m3); - env->regs[r1] = float64_to_int64(v2, &env->fpu_status); - return set_cc_nz_f64(v2); + int hold = swap_round_mode(env, m3); + float64 ret = int64_to_float64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 128-bit float to 64-bit int */ -uint32_t HELPER(cgxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +/* convert 64-bit int to 128-bit float */ +uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m3) { - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - set_round_mode(env, m3); - env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); - if (float128_is_any_nan(v2.q)) { - return 3; - } else if (float128_is_zero(v2.q)) { - return 0; - } else if (float128_is_neg(v2.q)) { - return 1; - } else { - return 2; - } + int hold = swap_round_mode(env, m3); + float128 ret = int64_to_float128(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } -/* convert 32-bit float to 32-bit int */ -uint32_t HELPER(cfebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +/* convert 64-bit uint to 32-bit float */ +uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float32 v2 = env->fregs[f2].l.upper; - - set_round_mode(env, m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float32_to_int32(v2, &env->fpu_status); - return set_cc_nz_f32(v2); + int hold = swap_round_mode(env, m3); + float32 ret = uint64_to_float32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 64-bit float to 32-bit int */ -uint32_t HELPER(cfdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +/* convert 64-bit uint to 64-bit float */ +uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float64 v2 = env->fregs[f2].d; - - set_round_mode(env, m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float64_to_int32(v2, &env->fpu_status); - return set_cc_nz_f64(v2); + int hold = swap_round_mode(env, m3); + float64 ret = uint64_to_float64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 128-bit float to 32-bit int */ -uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +/* convert 64-bit uint to 128-bit float */ +uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float128_to_int32(v2.q, &env->fpu_status); - return set_cc_nz_f128(v2.q); + int hold = swap_round_mode(env, m3); + float128 ret = uint64_to_float128(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } -/* load 32-bit FP zero */ -void HELPER(lzer)(CPUS390XState *env, uint32_t f1) +/* convert 32-bit float to 64-bit int */ +uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - env->fregs[f1].l.upper = float32_zero; + int hold = swap_round_mode(env, m3); + int64_t ret = float32_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* load 64-bit FP zero */ -void HELPER(lzdr)(CPUS390XState *env, uint32_t f1) +/* convert 64-bit float to 64-bit int */ +uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - env->fregs[f1].d = float64_zero; + int hold = swap_round_mode(env, m3); + int64_t ret = float64_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* load 128-bit FP zero */ -void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) +/* convert 128-bit float to 64-bit int */ +uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) { - CPU_QuadU x; - - x.q = float64_to_float128(float64_zero, &env->fpu_status); - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 1].ll = x.ll.lower; + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + int64_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 128-bit FP subtraction RR */ -uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* convert 32-bit float to 32-bit int */ +uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_sub(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); + int hold = swap_round_mode(env, m3); + int32_t ret = float32_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 128-bit FP addition RR */ -uint32_t HELPER(axbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* convert 64-bit float to 32-bit int */ +uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_add(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); + int hold = swap_round_mode(env, m3); + int32_t ret = float64_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 32-bit FP multiplication RR */ -void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* convert 128-bit float to 32-bit int */ +uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) { - env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + int32_t ret = float128_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP division RR */ -void HELPER(ddbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* convert 32-bit float to 64-bit uint */ +uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); + int hold = swap_round_mode(env, m3); + uint64_t ret; + v2 = float32_to_float64(v2, &env->fpu_status); + ret = float64_to_uint64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP multiply and add RM */ -void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) +/* convert 64-bit float to 64-bit uint */ +uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - CPU_DoubleU v2; + int hold = swap_round_mode(env, m3); + uint64_t ret = float64_to_uint64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); - v2.ll = cpu_ldq_data(env, a2); - env->fregs[f1].d = float64_add(env->fregs[f1].d, - float64_mul(v2.d, env->fregs[f3].d, - &env->fpu_status), - &env->fpu_status); +/* convert 128-bit float to 64-bit uint */ +uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + /* ??? Not 100% correct. */ + uint64_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP multiply and add RR */ -void HELPER(madbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* convert 32-bit float to 32-bit uint */ +uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); - env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); + int hold = swap_round_mode(env, m3); + uint32_t ret = float32_to_uint32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP multiply and subtract RR */ -void HELPER(msdbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* convert 64-bit float to 32-bit uint */ +uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); - env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); + int hold = swap_round_mode(env, m3); + uint32_t ret = float64_to_uint32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 32-bit FP multiply and add RR */ -void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* convert 128-bit float to 32-bit uint */ +uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) { - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - float32_mul(env->fregs[f2].l.upper, - env->fregs[f3].l.upper, - &env->fpu_status), - &env->fpu_status); + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + /* Not 100% correct. */ + uint32_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 32-bit float to 64-bit float */ -void HELPER(ldeb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +/* 32-bit FP multiply and add */ +uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - uint32_t v2; + float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - v2 = cpu_ldl_data(env, a2); - env->fregs[f1].d = float32_to_float64(v2, - &env->fpu_status); +/* 64-bit FP multiply and add */ +uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) +{ + float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* convert 64-bit float to 128-bit float */ -void HELPER(lxdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +/* 32-bit FP multiply and subtract */ +uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - CPU_DoubleU v2; - CPU_QuadU v1; + float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, + &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - v2.ll = cpu_ldq_data(env, a2); - v1.q = float64_to_float128(v2.d, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; +/* 64-bit FP multiply and subtract */ +uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) +{ + float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, + &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* test data class 32-bit */ -uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tceb)(uint64_t f1, uint64_t m2) { - float32 v1 = env->fregs[f1].l.upper; + float32 v1 = f1; int neg = float32_is_neg(v1); uint32_t cc = 0; - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || @@ -786,19 +607,16 @@ uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) /* assume normalized number */ cc = 1; } - /* FIXME: denormalized? */ return cc; } /* test data class 64-bit */ -uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tcdb)(uint64_t v1, uint64_t m2) { - float64 v1 = env->fregs[f1].d; int neg = float64_is_neg(v1); uint32_t cc = 0; - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || @@ -813,20 +631,16 @@ uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) } /* test data class 128-bit */ -uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tcxb)(uint64_t ah, uint64_t al, uint64_t m2) { - CPU_QuadU v1; + float128 v1 = make_float128(ah, al); + int neg = float128_is_neg(v1); uint32_t cc = 0; - int neg; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - neg = float128_is_neg(v1.q); - if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || - (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || - (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || - (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { + if ((float128_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float128_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float128_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || + (float128_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { cc = 1; } else if (m2 & (1 << (9-neg))) { /* assume normalized number */ @@ -836,8 +650,64 @@ uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2) return cc; } -/* square root 64-bit RR */ -void HELPER(sqdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* square root 32-bit */ +uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) +{ + float32 ret = float32_sqrt(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* square root 64-bit */ +uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) +{ + float64 ret = float64_sqrt(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* square root 128-bit */ +uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) +{ + float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} + +static const int fpc_to_rnd[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + +/* set fpc */ +void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) +{ + /* Install everything in the main FPC. */ + env->fpc = fpc; + + /* Install the rounding mode in the shadow fpu_status. */ + set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status); +} + +/* set fpc and signal */ +void HELPER(sfas)(CPUS390XState *env, uint64_t val) { - env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); + uint32_t signalling = env->fpc; + uint32_t source = val; + uint32_t s390_exc; + + /* The contents of the source operand are placed in the FPC register; + then the flags in the FPC register are set to the logical OR of the + signalling flags and the source flags. */ + env->fpc = source | (signalling & 0x00ff0000); + set_float_rounding_mode(fpc_to_rnd[source & 3], &env->fpu_status); + + /* If any signalling flag is 1 and the corresponding source mask + is also 1, a simulated-iee-exception trap occurs. */ + s390_exc = (signalling >> 16) & (source >> 24); + if (s390_exc) { + ieee_exception(env, s390_exc | 3, GETPC()); + } } diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 42e06eb85e..9a132e6d2c 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -99,10 +99,10 @@ void do_interrupt(CPUS390XState *env) int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, int rw, int mmu_idx) { - /* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n", - __func__, address, rw, mmu_idx); */ - env->exception_index = EXCP_ADDR; - /* FIXME: find out how this works on a real machine */ + env->exception_index = EXCP_PGM; + env->int_pgm_code = PGM_ADDRESSING; + /* On real machines this value is dropped into LowMem. Since this + is userland, simply put this someplace that cpu_loop can find it. */ env->__excp_addr = address; return 1; } @@ -111,11 +111,11 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, /* Ensure to exit the TB after this call! */ static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, - uint32_t ilc) + uint32_t ilen) { env->exception_index = EXCP_PGM; env->int_pgm_code = code; - env->int_pgm_ilc = ilc; + env->int_pgm_ilen = ilen; } static int trans_bits(CPUS390XState *env, uint64_t mode) @@ -143,30 +143,30 @@ static int trans_bits(CPUS390XState *env, uint64_t mode) static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, uint64_t mode) { - int ilc = ILC_LATER_INC_2; + int ilen = ILEN_LATER_INC; int bits = trans_bits(env, mode) | 4; DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); - trigger_pgm_exception(env, PGM_PROTECTION, ilc); + trigger_pgm_exception(env, PGM_PROTECTION, ilen); } static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type, uint64_t asc, int rw) { - int ilc = ILC_LATER; + int ilen = ILEN_LATER; int bits = trans_bits(env, asc); + /* Code accesses have an undefined ilc. */ if (rw == 2) { - /* code has is undefined ilc */ - ilc = 2; + ilen = 2; } DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); - trigger_pgm_exception(env, type, ilc); + trigger_pgm_exception(env, type, ilen); } static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, @@ -406,7 +406,7 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, if (raddr > (ram_size + virtio_size)) { DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)aaddr, (uint64_t)ram_size); - trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER); + trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); return 1; } @@ -454,18 +454,19 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) env->psw.addr = addr; env->psw.mask = mask; - env->cc_op = (mask >> 13) & 3; + env->cc_op = (mask >> 44) & 3; } static uint64_t get_psw_mask(CPUS390XState *env) { - uint64_t r = env->psw.mask; + uint64_t r; env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); - r &= ~(3ULL << 13); + r = env->psw.mask; + r &= ~PSW_MASK_CC; assert(!(env->cc_op & ~3)); - r |= env->cc_op << 13; + r |= (uint64_t)env->cc_op << 44; return r; } @@ -479,9 +480,9 @@ static void do_svc_interrupt(CPUS390XState *env) lowcore = cpu_physical_memory_map(env->psa, &len, 1); lowcore->svc_code = cpu_to_be16(env->int_svc_code); - lowcore->svc_ilc = cpu_to_be16(env->int_svc_ilc); + lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env)); - lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + (env->int_svc_ilc)); + lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen); mask = be64_to_cpu(lowcore->svc_new_psw.mask); addr = be64_to_cpu(lowcore->svc_new_psw.addr); @@ -495,28 +496,26 @@ static void do_program_interrupt(CPUS390XState *env) uint64_t mask, addr; LowCore *lowcore; hwaddr len = TARGET_PAGE_SIZE; - int ilc = env->int_pgm_ilc; + int ilen = env->int_pgm_ilen; - switch (ilc) { - case ILC_LATER: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); - break; - case ILC_LATER_INC: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); - env->psw.addr += ilc * 2; + switch (ilen) { + case ILEN_LATER: + ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); break; - case ILC_LATER_INC_2: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2; - env->psw.addr += ilc; + case ILEN_LATER_INC: + ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); + env->psw.addr += ilen; break; + default: + assert(ilen == 2 || ilen == 4 || ilen == 6); } - qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilc=%d\n", - __func__, env->int_pgm_code, ilc); + qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", + __func__, env->int_pgm_code, ilen); lowcore = cpu_physical_memory_map(env->psa, &len, 1); - lowcore->pgm_ilc = cpu_to_be16(ilc); + lowcore->pgm_ilen = cpu_to_be16(ilen); lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); @@ -526,7 +525,7 @@ static void do_program_interrupt(CPUS390XState *env) cpu_physical_memory_unmap(lowcore, len, 1, len); DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, - env->int_pgm_code, ilc, env->psw.mask, + env->int_pgm_code, ilen, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c4926c52ad..dd90d93bee 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -1,152 +1,120 @@ #include "exec/def-helper.h" -DEF_HELPER_2(exception, void, env, i32) -DEF_HELPER_4(nc, i32, env, i32, i64, i64) -DEF_HELPER_4(oc, i32, env, i32, i64, i64) -DEF_HELPER_4(xc, i32, env, i32, i64, i64) -DEF_HELPER_4(mvc, void, env, i32, i64, i64) -DEF_HELPER_4(clc, i32, env, i32, i64, i64) +DEF_HELPER_2(exception, noreturn, env, i32) +DEF_HELPER_FLAGS_4(nc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(xc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) -DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_NO_RWG_SE, i32, s32) -DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_NO_RWG_SE, i32, s64) -DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_NO_RWG_SE, i32, i32, i32) -DEF_HELPER_4(clm, i32, env, i32, i32, i64) -DEF_HELPER_4(stcm, void, env, i32, i32, i64) -DEF_HELPER_3(mlg, void, env, i32, i64) -DEF_HELPER_3(dlg, void, env, i32, i64) -DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_NO_RWG_SE, i32, s64, s64, s64) -DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_NO_RWG_SE, i32, s32, s32, s32) -DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_NO_RWG_SE, i32, s64, s64, s64) -DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_NO_RWG_SE, i32, s32, s32, s32) -DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_4(srst, i32, env, i32, i32, i32) -DEF_HELPER_4(clst, i32, env, i32, i32, i32) +DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) +DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64) +DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64) +DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_4(srst, i64, env, i64, i64, i64) +DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) -DEF_HELPER_4(mvst, void, env, i32, i32, i32) -DEF_HELPER_4(csg, i32, env, i32, i64, i32) -DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) -DEF_HELPER_4(cs, i32, env, i32, i64, i32) +DEF_HELPER_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) -DEF_HELPER_4(stcmh, void, env, i32, i64, i32) -DEF_HELPER_4(icmh, i32, env, i32, i64, i32) -DEF_HELPER_3(ipm, void, env, i32, i32) -DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_4(stam, void, env, i32, i64, i32) -DEF_HELPER_4(lam, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(lam, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) -DEF_HELPER_4(slb, i32, env, i32, i32, i32) -DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64) -DEF_HELPER_3(cefbr, void, env, i32, s32) -DEF_HELPER_3(cdfbr, void, env, i32, s32) -DEF_HELPER_3(cxfbr, void, env, i32, s32) -DEF_HELPER_3(cegbr, void, env, i32, s64) -DEF_HELPER_3(cdgbr, void, env, i32, s64) -DEF_HELPER_3(cxgbr, void, env, i32, s64) -DEF_HELPER_3(adbr, i32, env, i32, i32) -DEF_HELPER_3(aebr, i32, env, i32, i32) -DEF_HELPER_3(sebr, i32, env, i32, i32) -DEF_HELPER_3(sdbr, i32, env, i32, i32) -DEF_HELPER_3(debr, void, env, i32, i32) -DEF_HELPER_3(dxbr, void, env, i32, i32) -DEF_HELPER_3(mdbr, void, env, i32, i32) -DEF_HELPER_3(mxbr, void, env, i32, i32) -DEF_HELPER_3(ldebr, void, env, i32, i32) -DEF_HELPER_3(ldxbr, void, env, i32, i32) -DEF_HELPER_3(lxdbr, void, env, i32, i32) -DEF_HELPER_3(ledbr, void, env, i32, i32) -DEF_HELPER_3(lexbr, void, env, i32, i32) -DEF_HELPER_3(lpebr, i32, env, i32, i32) -DEF_HELPER_3(lpdbr, i32, env, i32, i32) -DEF_HELPER_3(lpxbr, i32, env, i32, i32) -DEF_HELPER_3(ltebr, i32, env, i32, i32) -DEF_HELPER_3(ltdbr, i32, env, i32, i32) -DEF_HELPER_3(ltxbr, i32, env, i32, i32) -DEF_HELPER_3(lcebr, i32, env, i32, i32) -DEF_HELPER_3(lcdbr, i32, env, i32, i32) -DEF_HELPER_3(lcxbr, i32, env, i32, i32) -DEF_HELPER_3(aeb, void, env, i32, i32) -DEF_HELPER_3(deb, void, env, i32, i32) -DEF_HELPER_3(meeb, void, env, i32, i32) -DEF_HELPER_3(cdb, i32, env, i32, i64) -DEF_HELPER_3(adb, i32, env, i32, i64) -DEF_HELPER_3(seb, void, env, i32, i32) -DEF_HELPER_3(sdb, i32, env, i32, i64) -DEF_HELPER_3(mdb, void, env, i32, i64) -DEF_HELPER_3(ddb, void, env, i32, i64) -DEF_HELPER_FLAGS_3(cebr, TCG_CALL_NO_SE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_NO_SE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_NO_SE, i32, env, i32, i32) -DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) -DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) -DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) -DEF_HELPER_2(lzer, void, env, i32) -DEF_HELPER_2(lzdr, void, env, i32) -DEF_HELPER_2(lzxr, void, env, i32) -DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) -DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) -DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_3(axbr, i32, env, i32, i32) -DEF_HELPER_3(sxbr, i32, env, i32, i32) -DEF_HELPER_3(meebr, void, env, i32, i32) -DEF_HELPER_3(ddbr, void, env, i32, i32) -DEF_HELPER_4(madb, void, env, i32, i64, i32) -DEF_HELPER_4(maebr, void, env, i32, i32, i32) -DEF_HELPER_4(madbr, void, env, i32, i32, i32) -DEF_HELPER_4(msdbr, void, env, i32, i32, i32) -DEF_HELPER_3(ldeb, void, env, i32, i64) -DEF_HELPER_3(lxdb, void, env, i32, i64) -DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_SE, i32, env, i32, i64) -DEF_HELPER_3(flogr, i32, env, i32, i64) -DEF_HELPER_3(sqdbr, void, env, i32, i32) +DEF_HELPER_3(cegb, i64, env, s64, i32) +DEF_HELPER_3(cdgb, i64, env, s64, i32) +DEF_HELPER_3(cxgb, i64, env, s64, i32) +DEF_HELPER_3(celgb, i64, env, i64, i32) +DEF_HELPER_3(cdlgb, i64, env, i64, i32) +DEF_HELPER_3(cxlgb, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(aeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(adb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(axb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(seb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(sdb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(sxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(deb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(ddb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(dxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(meeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mdeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mdb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(mxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_4(mxdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_2(ldeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(ldxb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(lxdb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(lxeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(ledb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(lexb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) +DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) +DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(cfeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(cfdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(cfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(clgeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(clgdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(clgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(clfeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(clfdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(clfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(maeb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(madb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(mseb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(msdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) +DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) -DEF_HELPER_4(unpk, void, env, i32, i64, i64) -DEF_HELPER_4(tr, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_4(cksm, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) +DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) +DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_3(servc, i32, env, i32, i64) +#ifndef CONFIG_USER_ONLY +DEF_HELPER_3(servc, i32, env, i64, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) -DEF_HELPER_3(load_psw, void, env, i64, i64) -DEF_HELPER_1(program_interrupt, void, i32) -DEF_HELPER_FLAGS_2(stidp, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_3(load_psw, noreturn, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_1(sck, TCG_CALL_NO_RWG, i32, i64) -DEF_HELPER_2(stck, i32, env, i64) -DEF_HELPER_2(stcke, i32, env, i64) +DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_2(stckc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_2(stpt, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_4(stsi, i32, env, i64, i32, i32) -DEF_HELPER_4(lctl, void, env, i32, i64, i32) -DEF_HELPER_4(lctlg, void, env, i32, i64, i32) -DEF_HELPER_4(stctl, void, env, i32, i64, i32) -DEF_HELPER_4(stctg, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) +DEF_HELPER_4(stsi, i32, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(lctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(lctlg, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) -DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i32, i64) -DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_NO_RWG, i32, env, i32, i64) -DEF_HELPER_3(csp, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) +DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_3(csp, i32, env, i32, i64) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) -DEF_HELPER_2(sacf, void, env, i64) +DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) -DEF_HELPER_3(lra, i32, env, i64, i32) -DEF_HELPER_3(stura, void, env, i64, i32) -DEF_HELPER_3(cksm, void, env, i32, i32) - -DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, - i32, env, i32, i64, i64, i64) +DEF_HELPER_2(lra, i64, env, i64) +DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64) +#endif #include "exec/def-helper.h" diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def new file mode 100644 index 0000000000..b42ebb6a1a --- /dev/null +++ b/target-s390x/insn-data.def @@ -0,0 +1,813 @@ +/* ADD */ + C(0x1a00, AR, RR_a, Z, r1, r2, new, r1_32, add, adds32) + C(0xb9f8, ARK, RRF_a, DO, r2, r3, new, r1_32, add, adds32) + C(0x5a00, A, RX_a, Z, r1, m2_32s, new, r1_32, add, adds32) + C(0xe35a, AY, RXY_a, LD, r1, m2_32s, new, r1_32, add, adds32) + C(0xb908, AGR, RRE, Z, r1, r2, r1, 0, add, adds64) + C(0xb918, AGFR, RRE, Z, r1, r2_32s, r1, 0, add, adds64) + C(0xb9e8, AGRK, RRF_a, DO, r2, r3, r1, 0, add, adds64) + C(0xe308, AG, RXY_a, Z, r1, m2_64, r1, 0, add, adds64) + C(0xe318, AGF, RXY_a, Z, r1, m2_32s, r1, 0, add, adds64) + C(0xb30a, AEBR, RRE, Z, e1, e2, new, e1, aeb, f32) + C(0xb31a, ADBR, RRE, Z, f1_o, f2_o, f1, 0, adb, f64) + C(0xb34a, AXBR, RRE, Z, 0, x2_o, x1, 0, axb, f128) + C(0xed0a, AEB, RXE, Z, e1, m2_32u, new, e1, aeb, f32) + C(0xed1a, ADB, RXE, Z, f1_o, m2_64, f1, 0, adb, f64) +/* ADD IMMEDIATE */ + C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) + C(0xeb6a, ASI, SIY, GIE, m1_32s, i2, new, m1_32, add, adds32) + C(0xecd8, AHIK, RIE_d, DO, r3, i2, new, r1_32, add, adds32) + C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) + C(0xeb7a, AGSI, SIY, GIE, m1_64, i2, new, m1_64, add, adds64) + C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) +/* ADD HALFWORD */ + C(0x4a00, AH, RX_a, Z, r1, m2_16s, new, r1_32, add, adds32) + C(0xe37a, AHY, RXY_a, LD, r1, m2_16s, new, r1_32, add, adds32) +/* ADD HALFWORD IMMEDIATE */ + C(0xa70a, AHI, RI_a, Z, r1, i2, new, r1_32, add, adds32) + C(0xa70b, AGHI, RI_a, Z, r1, i2, r1, 0, add, adds64) + +/* ADD LOGICAL */ + C(0x1e00, ALR, RR_a, Z, r1, r2, new, r1_32, add, addu32) + C(0xb9fa, ALRK, RRF_a, DO, r2, r3, new, r1_32, add, addu32) + C(0x5e00, AL, RX_a, Z, r1, m2_32u, new, r1_32, add, addu32) + C(0xe35e, ALY, RXY_a, LD, r1, m2_32u, new, r1_32, add, addu32) + C(0xb90a, ALGR, RRE, Z, r1, r2, r1, 0, add, addu64) + C(0xb91a, ALGFR, RRE, Z, r1, r2_32u, r1, 0, add, addu64) + C(0xb9ea, ALGRK, RRF_a, DO, r2, r3, r1, 0, add, addu64) + C(0xe30a, ALG, RXY_a, Z, r1, m2_64, r1, 0, add, addu64) + C(0xe31a, ALGF, RXY_a, Z, r1, m2_32u, r1, 0, add, addu64) +/* ADD LOGICAL IMMEDIATE */ + C(0xc20b, ALFI, RIL_a, EI, r1, i2_32u, new, r1_32, add, addu32) + C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, add, addu64) +/* ADD LOGICAL WITH SIGNED IMMEDIATE */ + C(0xeb6e, ALSI, SIY, GIE, m1_32u, i2, new, m1_32, add, addu32) + C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32) + C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) + C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* ADD LOGICAL WITH CARRY */ + C(0xb998, ALCR, RRE, Z, r1, r2, new, r1_32, addc, addc32) + C(0xb988, ALCGR, RRE, Z, r1, r2, r1, 0, addc, addc64) + C(0xe398, ALC, RXY_a, Z, r1, m2_32u, new, r1_32, addc, addc32) + C(0xe388, ALCG, RXY_a, Z, r1, m2_64, r1, 0, addc, addc64) + +/* AND */ + C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32) + C(0xb9f4, NRK, RRF_a, DO, r2, r3, new, r1_32, and, nz32) + C(0x5400, N, RX_a, Z, r1, m2_32s, new, r1_32, and, nz32) + C(0xe354, NY, RXY_a, LD, r1, m2_32s, new, r1_32, and, nz32) + C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) + C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) + C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) + C(0xd400, NC, SS_a, Z, la1, a2, 0, 0, nc, 0) +/* AND IMMEDIATE */ + D(0xc00a, NIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2020) + D(0xc00b, NILF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2000) + D(0xa504, NIHH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1030) + D(0xa505, NIHL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1020) + D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) + D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) + C(0x9400, NI, SI, Z, m1_8u, i2_8u, new, m1_8, and, nz64) + C(0xeb54, NIY, SIY, LD, m1_8u, i2_8u, new, m1_8, and, nz64) + +/* BRANCH AND SAVE */ + C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0) + C(0x4d00, BAS, RX_a, Z, 0, a2, r1, 0, bas, 0) +/* BRANCH RELATIVE AND SAVE */ + C(0xa705, BRAS, RI_b, Z, 0, 0, r1, 0, basi, 0) + C(0xc005, BRASL, RIL_b, Z, 0, 0, r1, 0, basi, 0) +/* BRANCH ON CONDITION */ + C(0x0700, BCR, RR_b, Z, 0, r2_nz, 0, 0, bc, 0) + C(0x4700, BC, RX_b, Z, 0, a2, 0, 0, bc, 0) +/* BRANCH RELATIVE ON CONDITION */ + C(0xa704, BRC, RI_c, Z, 0, 0, 0, 0, bc, 0) + C(0xc004, BRCL, RIL_c, Z, 0, 0, 0, 0, bc, 0) +/* BRANCH ON COUNT */ + C(0x0600, BCTR, RR_a, Z, 0, r2_nz, 0, 0, bct32, 0) + C(0xb946, BCTGR, RRE, Z, 0, r2_nz, 0, 0, bct64, 0) + C(0x4600, BCT, RX_a, Z, 0, a2, 0, 0, bct32, 0) + C(0xe346, BCTG, RXY_a, Z, 0, a2, 0, 0, bct64, 0) +/* BRANCH RELATIVE ON COUNT */ + C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) + C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* BRANCH ON INDEX */ + D(0x8600, BXH, RS_a, Z, 0, a2, 0, 0, bx32, 0, 0) + D(0x8700, BXLE, RS_a, Z, 0, a2, 0, 0, bx32, 0, 1) + D(0xeb44, BXHG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 0) + D(0xeb45, BXLEG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 1) +/* BRANCH RELATIVE ON INDEX */ + D(0x8400, BRXH, RSI, Z, 0, 0, 0, 0, bx32, 0, 0) + D(0x8500, BRXLE, RSI, Z, 0, 0, 0, 0, bx32, 0, 1) + D(0xec44, BRXHG, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 0) + D(0xec45, BRXHLE, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 1) + +/* CHECKSUM */ + C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) + +/* COPY SIGN */ + C(0xb372, CPSDR, RRF_b, FPSSH, f3_o, f2_o, f1, 0, cps, 0) + +/* COMPARE */ + C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) + C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) + C(0xe359, CY, RXY_a, LD, r1_o, m2_32s, 0, 0, 0, cmps32) + C(0xb920, CGR, RRE, Z, r1_o, r2_o, 0, 0, 0, cmps64) + C(0xb930, CGFR, RRE, Z, r1_o, r2_32s, 0, 0, 0, cmps64) + C(0xe320, CG, RXY_a, Z, r1_o, m2_64, 0, 0, 0, cmps64) + C(0xe330, CGF, RXY_a, Z, r1_o, m2_32s, 0, 0, 0, cmps64) + C(0xb309, CEBR, RRE, Z, e1, e2, 0, 0, ceb, 0) + C(0xb319, CDBR, RRE, Z, f1_o, f2_o, 0, 0, cdb, 0) + C(0xb349, CXBR, RRE, Z, x1_o, x2_o, 0, 0, cxb, 0) + C(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0) + C(0xed19, CDB, RXE, Z, f1_o, m2_64, 0, 0, cdb, 0) +/* COMPARE IMMEDIATE */ + C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) + C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) +/* COMPARE RELATIVE LONG */ + C(0xc60d, CRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps32) + C(0xc608, CGRL, RIL_b, GIE, r1, mri2_64, 0, 0, 0, cmps64) + C(0xc60c, CGFRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps64) +/* COMPARE HALFWORD */ + C(0x4900, CH, RX_a, Z, r1_o, m2_16s, 0, 0, 0, cmps32) + C(0xe379, CHY, RXY_a, LD, r1_o, m2_16s, 0, 0, 0, cmps32) + C(0xe334, CGH, RXY_a, GIE, r1_o, m2_16s, 0, 0, 0, cmps64) +/* COMPARE HALFWORD IMMEDIATE */ + C(0xa70e, CHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps32) + C(0xa70f, CGHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps64) + C(0xe554, CHHSI, SIL, GIE, m1_16s, i2, 0, 0, 0, cmps64) + C(0xe55c, CHSI, SIL, GIE, m1_32s, i2, 0, 0, 0, cmps64) + C(0xe558, CGHSI, SIL, GIE, m1_64, i2, 0, 0, 0, cmps64) +/* COMPARE HALFWORD RELATIVE LONG */ + C(0xc605, CHRL, RIL_a, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32) + C(0xc604, CGHRL, RIL_a, GIE, r1_o, mri2_64, 0, 0, 0, cmps64) + +/* COMPARE LOGICAL */ + C(0x1500, CLR, RR_a, Z, r1, r2, 0, 0, 0, cmpu32) + C(0x5500, CL, RX_a, Z, r1, m2_32s, 0, 0, 0, cmpu32) + C(0xe355, CLY, RXY_a, LD, r1, m2_32s, 0, 0, 0, cmpu32) + C(0xb921, CLGR, RRE, Z, r1, r2, 0, 0, 0, cmpu64) + C(0xb931, CLGFR, RRE, Z, r1, r2_32u, 0, 0, 0, cmpu64) + C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64) + C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64) + C(0xd500, CLC, SS_a, Z, la1, a2, 0, 0, clc, 0) +/* COMPARE LOGICAL IMMEDIATE */ + C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32) + C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64) + C(0x9500, CLI, SI, Z, m1_8u, i2_8u, 0, 0, 0, cmpu64) + C(0xeb55, CLIY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, cmpu64) + C(0xe555, CLHHSI, SIL, GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64) + C(0xe55d, CLFHSI, SIL, GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64) + C(0xe559, CLGHSI, SIL, GIE, m1_64, i2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL RELATIVE LONG */ + C(0xc60f, CLRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32) + C(0xc60a, CLGRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64) + C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) + C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) + C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL LONG EXTENDED */ + C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) +/* COMPARE LOGICAL CHARACTERS UNDER MASK */ + C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) + C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) + C(0xeb20, CLMH, RSY_b, Z, r1_sr32, a2, 0, 0, clm, 0) +/* COMPARE LOGICAL STRING */ + C(0xb25d, CLST, RRE, Z, r1_o, r2_o, 0, 0, clst, 0) + +/* COMPARE AND BRANCH */ + D(0xecf6, CRB, RRS, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) + D(0xece4, CGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) + D(0xec76, CRJ, RIE_b, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) + D(0xec64, CGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) + D(0xecfe, CIB, RIS, GIE, r1_32s, i2, 0, 0, cj, 0, 0) + D(0xecfc, CGIB, RIS, GIE, r1_o, i2, 0, 0, cj, 0, 0) + D(0xec7e, CIJ, RIE_c, GIE, r1_32s, i2, 0, 0, cj, 0, 0) + D(0xec7c, CGIJ, RIE_c, GIE, r1_o, i2, 0, 0, cj, 0, 0) +/* COMPARE LOGICAL AND BRANCH */ + D(0xecf7, CLRB, RRS, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) + D(0xece5, CLGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) + D(0xec77, CLRJ, RIE_b, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) + D(0xec65, CLGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) + D(0xecff, CLIB, RIS, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) + D(0xecfd, CLGIB, RIS, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) + D(0xec7f, CLIJ, RIE_c, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) + D(0xec7d, CLGIJ, RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) + +/* COMPARE AND SWAP */ + D(0xba00, CS, RS_a, Z, r3_32u, r1_32u, new, r1_32, cs, 0, 0) + D(0xeb14, CSY, RSY_a, LD, r3_32u, r1_32u, new, r1_32, cs, 0, 0) + D(0xeb30, CSG, RSY_a, Z, r3_o, r1_o, new, r1, cs, 0, 1) +/* COMPARE DOUBLE AND SWAP */ + D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, 1) + D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, 1) + C(0xeb3e, CDSG, RSY_a, Z, 0, 0, 0, 0, cdsg, 0) + +/* COMPARE AND TRAP */ + D(0xb972, CRT, RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0) + D(0xb960, CGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 0) + D(0xec72, CIT, RIE_a, GIE, r1_32s, i2, 0, 0, ct, 0, 0) + D(0xec70, CGIT, RIE_a, GIE, r1_o, i2, 0, 0, ct, 0, 0) +/* COMPARE LOGICAL AND TRAP */ + D(0xb973, CLRT, RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1) + D(0xb961, CLGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1) + D(0xec73, CLFIT, RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1) + D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 0) + +/* CONVERT TO DECIMAL */ + C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) + C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) +/* CONVERT TO FIXED */ + C(0xb398, CFEBR, RRF_e, Z, 0, e2, new, r1_32, cfeb, 0) + C(0xb399, CFDBR, RRF_e, Z, 0, f2_o, new, r1_32, cfdb, 0) + C(0xb39a, CFXBR, RRF_e, Z, 0, x2_o, new, r1_32, cfxb, 0) + C(0xb3a8, CGEBR, RRF_e, Z, 0, e2, r1, 0, cgeb, 0) + C(0xb3a9, CGDBR, RRF_e, Z, 0, f2_o, r1, 0, cgdb, 0) + C(0xb3aa, CGXBR, RRF_e, Z, 0, x2_o, r1, 0, cgxb, 0) +/* CONVERT FROM FIXED */ + C(0xb394, CEFBR, RRF_e, Z, 0, r2_32s, new, e1, cegb, 0) + C(0xb395, CDFBR, RRF_e, Z, 0, r2_32s, f1, 0, cdgb, 0) + C(0xb396, CXFBR, RRF_e, Z, 0, r2_32s, x1, 0, cxgb, 0) + C(0xb3a4, CEGBR, RRF_e, Z, 0, r2_o, new, e1, cegb, 0) + C(0xb3a5, CDGBR, RRF_e, Z, 0, r2_o, f1, 0, cdgb, 0) + C(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, x1, 0, cxgb, 0) +/* CONVERT TO LOGICAL */ + C(0xb39c, CLFEBR, RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0) + C(0xb39d, CLFDBR, RRF_e, FPE, 0, f2_o, new, r1_32, clfdb, 0) + C(0xb39e, CLFXBR, RRF_e, FPE, 0, x2_o, new, r1_32, clfxb, 0) + C(0xb3ac, CLGEBR, RRF_e, FPE, 0, e2, r1, 0, clgeb, 0) + C(0xb3ad, CLGDBR, RRF_e, FPE, 0, f2_o, r1, 0, clgdb, 0) + C(0xb3ae, CLGXBR, RRF_e, FPE, 0, x2_o, r1, 0, clgxb, 0) +/* CONVERT FROM LOGICAL */ + C(0xb390, CELFBR, RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0) + C(0xb391, CDLFBR, RRF_e, FPE, 0, r2_32u, f1, 0, cdlgb, 0) + C(0xb392, CXLFBR, RRF_e, FPE, 0, r2_32u, x1, 0, cxlgb, 0) + C(0xb3a0, CELGBR, RRF_e, FPE, 0, r2_o, new, e1, celgb, 0) + C(0xb3a1, CDLGBR, RRF_e, FPE, 0, r2_o, f1, 0, cdlgb, 0) + C(0xb3a2, CXLGBR, RRF_e, FPE, 0, r2_o, x1, 0, cxlgb, 0) + +/* DIVIDE */ + C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) + C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) + C(0xb30d, DEBR, RRE, Z, e1, e2, new, e1, deb, 0) + C(0xb31d, DDBR, RRE, Z, f1_o, f2_o, f1, 0, ddb, 0) + C(0xb34d, DXBR, RRE, Z, 0, x2_o, x1, 0, dxb, 0) + C(0xed0d, DEB, RXE, Z, e1, m2_32u, new, e1, deb, 0) + C(0xed1d, DDB, RXE, Z, f1_o, m2_64, f1, 0, ddb, 0) +/* DIVIDE LOGICAL */ + C(0xb997, DLR, RRE, Z, r1_D32, r2_32u, new_P, r1_P32, divu32, 0) + C(0xe397, DL, RXY_a, Z, r1_D32, m2_32u, new_P, r1_P32, divu32, 0) + C(0xb987, DLGR, RRE, Z, 0, r2_o, r1_P, 0, divu64, 0) + C(0xe387, DLG, RXY_a, Z, 0, m2_64, r1_P, 0, divu64, 0) +/* DIVIDE SINGLE */ + C(0xb90d, DSGR, RRE, Z, r1p1, r2, r1_P, 0, divs64, 0) + C(0xb91d, DSGFR, RRE, Z, r1p1, r2_32s, r1_P, 0, divs64, 0) + C(0xe30d, DSG, RXY_a, Z, r1p1, m2_64, r1_P, 0, divs64, 0) + C(0xe31d, DSGF, RXY_a, Z, r1p1, m2_32s, r1_P, 0, divs64, 0) + +/* EXCLUSIVE OR */ + C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) + C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) + C(0x5700, X, RX_a, Z, r1, m2_32s, new, r1_32, xor, nz32) + C(0xe357, XY, RXY_a, LD, r1, m2_32s, new, r1_32, xor, nz32) + C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) + C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) + C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) + C(0xd700, XC, SS_a, Z, 0, 0, 0, 0, xc, 0) +/* EXCLUSIVE OR IMMEDIATE */ + D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) + D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) + C(0x9700, XI, SI, Z, m1_8u, i2_8u, new, m1_8, xor, nz64) + C(0xeb57, XIY, SIY, LD, m1_8u, i2_8u, new, m1_8, xor, nz64) + +/* EXECUTE */ + C(0x4400, EX, RX_a, Z, r1_o, a2, 0, 0, ex, 0) +/* EXECUTE RELATIVE LONG */ + C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) + +/* EXTRACT ACCESS */ + C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) +/* EXTRACT FPC */ + C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) + +/* FIND LEFTMOST ONE */ + C(0xb983, FLOGR, RRE, EI, 0, r2_o, r1_P, 0, flogr, 0) + +/* INSERT CHARACTER */ + C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) + C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) +/* INSERT CHARACTERS UNDER MASK */ + D(0xbf00, ICM, RS_b, Z, 0, a2, r1, 0, icm, 0, 0) + D(0xeb81, ICMY, RSY_b, LD, 0, a2, r1, 0, icm, 0, 0) + D(0xeb80, ICMH, RSY_b, Z, 0, a2, r1, 0, icm, 0, 32) +/* INSERT IMMEDIATE */ + D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) + D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) + D(0xa500, IIHH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1030) + D(0xa501, IIHL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1020) + D(0xa502, IILH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1010) + D(0xa503, IILL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1000) +/* INSERT PROGRAM MASK */ + C(0xb222, IPM, RRE, Z, 0, 0, r1, 0, ipm, 0) + +/* LOAD */ + C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) + C(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0) + C(0xe358, LY, RXY_a, Z, 0, a2, new, r1_32, ld32s, 0) + C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0) + C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) + C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) + C(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0) + C(0x2800, LDR, RR_a, Z, 0, f2_o, 0, f1, mov2, 0) + C(0x6800, LD, RX_a, Z, 0, m2_64, 0, f1, mov2, 0) + C(0xed65, LDY, RXY_a, LD, 0, m2_64, 0, f1, mov2, 0) + C(0x3800, LER, RR_a, Z, 0, e2, 0, cond_e1e2, mov2, 0) + C(0x7800, LE, RX_a, Z, 0, m2_32u, 0, e1, mov2, 0) + C(0xed64, LEY, RXY_a, LD, 0, m2_32u, 0, e1, mov2, 0) + C(0xb365, LXR, RRE, Z, 0, x2_o, 0, x1, movx, 0) +/* LOAD IMMEDIATE */ + C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) +/* LOAD RELATIVE LONG */ + C(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0) + C(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0) + C(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0) +/* LOAD ADDRESS */ + C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0) + C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0) +/* LOAD ADDRESS RELATIVE LONG */ + C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0) +/* LOAD AND TEST */ + C(0x1200, LTR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, s32) + C(0xb902, LTGR, RRE, Z, 0, r2_o, 0, r1, mov2, s64) + C(0xb912, LTGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, s64) + C(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64) + C(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64) + C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) + C(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32) + C(0xb312, LTDBR, RRE, Z, 0, f2_o, 0, f1, mov2, f64) + C(0xb342, LTXBR, RRE, Z, 0, x2_o, 0, x1, movx, f128) +/* LOAD BYTE */ + C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) + C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) + C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0) + C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0) +/* LOAD COMPLEMENT */ + C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32) + C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64) + C(0xb913, LCGFR, RRE, Z, 0, r2_32s, r1, 0, neg, neg64) + C(0xb303, LCEBR, RRE, Z, 0, e2, new, e1, negf32, f32) + C(0xb313, LCDBR, RRE, Z, 0, f2_o, f1, 0, negf64, f64) + C(0xb343, LCXBR, RRE, Z, 0, x2_o, x1, 0, negf128, f128) + C(0xb373, LCDFR, RRE, FPSSH, 0, f2_o, f1, 0, negf64, 0) +/* LOAD HALFWORD */ + C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) + C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) + C(0x4800, LH, RX_a, Z, 0, a2, new, r1_32, ld16s, 0) + C(0xe378, LHY, RXY_a, LD, 0, a2, new, r1_32, ld16s, 0) + C(0xe315, LGH, RXY_a, Z, 0, a2, r1, 0, ld16s, 0) +/* LOAD HALFWORD IMMEDIATE */ + C(0xa708, LHI, RI_a, Z, 0, i2, 0, r1_32, mov2, 0) + C(0xa709, LGHI, RI_a, Z, 0, i2, 0, r1, mov2, 0) +/* LOAD HALFWORD RELATIVE LONG */ + C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0) + C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0) +/* LOAD LOGICAL */ + C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) + C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) +/* LOAD LOGICAL RELATIVE LONG */ + C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) +/* LOAD LOGICAL CHARACTER */ + C(0xb994, LLCR, RRE, EI, 0, r2_8u, 0, r1_32, mov2, 0) + C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0) + C(0xe394, LLC, RXY_a, EI, 0, a2, new, r1_32, ld8u, 0) + C(0xe390, LLGC, RXY_a, Z, 0, a2, r1, 0, ld8u, 0) +/* LOAD LOGICAL HALFWORD */ + C(0xb995, LLHR, RRE, EI, 0, r2_16u, 0, r1_32, mov2, 0) + C(0xb985, LLGHR, RRE, EI, 0, r2_16u, 0, r1, mov2, 0) + C(0xe395, LLH, RXY_a, EI, 0, a2, new, r1_32, ld16u, 0) + C(0xe391, LLGH, RXY_a, Z, 0, a2, r1, 0, ld16u, 0) +/* LOAD LOGICAL HALFWORD RELATIVE LONG */ + C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0) + C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0) +/* LOAD LOGICAL IMMEDATE */ + D(0xc00e, LLIHF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 32) + D(0xc00f, LLILF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 0) + D(0xa50c, LLIHH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 48) + D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) + D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) + D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) +/* LOAD LOGICAL THIRTY ONE BITS */ + C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0) + C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0) +/* LOAD FPR FROM GR */ + C(0xb3c1, LDGR, RRE, FPRGR, 0, r2_o, 0, f1, mov2, 0) +/* LOAD GR FROM FPR */ + C(0xb3cd, LGDR, RRE, FPRGR, 0, f2_o, 0, r1, mov2, 0) +/* LOAD NEGATIVE */ + C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) + C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) + C(0xb911, LNGFR, RRE, Z, 0, r2_32s, r1, 0, nabs, nabs64) + C(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32) + C(0xb311, LNDBR, RRE, Z, 0, f2_o, f1, 0, nabsf64, f64) + C(0xb341, LNXBR, RRE, Z, 0, x2_o, x1, 0, nabsf128, f128) +/* LOAD ON CONDITION */ + C(0xb9f2, LOCR, RRF_c, LOC, r1, r2, new, r1_32, loc, 0) + C(0xb9e2, LOCGR, RRF_c, LOC, r1, r2, r1, 0, loc, 0) + C(0xebf2, LOC, RSY_b, LOC, r1, m2_32u, new, r1_32, loc, 0) + C(0xebe2, LOCG, RSY_b, LOC, r1, m2_64, r1, 0, loc, 0) +/* LOAD POSITIVE */ + C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) + C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) + C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) + C(0xb300, LPEBR, RRE, Z, 0, e2, new, e1, absf32, f32) + C(0xb310, LPDBR, RRE, Z, 0, f2_o, f1, 0, absf64, f64) + C(0xb340, LPXBR, RRE, Z, 0, x2_o, x1, 0, absf128, f128) +/* LOAD REVERSED */ + C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) + C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0) + C(0xe31f, LRVH, RXY_a, Z, 0, m2_16u, new, r1_16, rev16, 0) + C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) + C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) +/* LOAD ZERO */ + C(0xb374, LZER, RRE, Z, 0, 0, 0, e1, zero, 0) + C(0xb375, LZDR, RRE, Z, 0, 0, 0, f1, zero, 0) + C(0xb376, LZXR, RRE, Z, 0, 0, 0, x1, zero2, 0) + +/* LOAD FPC */ + C(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0) +/* LOAD FPC AND SIGNAL */ + C(0xb2bd, LFAS, S, IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0) + +/* LOAD LENGTHENED */ + C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) + C(0xb305, LXDBR, RRE, Z, 0, f2_o, x1, 0, lxdb, 0) + C(0xb306, LXEBR, RRE, Z, 0, e2, x1, 0, lxeb, 0) + C(0xed04, LDEB, RXE, Z, 0, m2_32u, f1, 0, ldeb, 0) + C(0xed05, LXDB, RXE, Z, 0, m2_64, x1, 0, lxdb, 0) + C(0xed06, LXEB, RXE, Z, 0, m2_32u, x1, 0, lxeb, 0) +/* LOAD ROUNDED */ + C(0xb344, LEDBR, RRE, Z, 0, f2_o, new, e1, ledb, 0) + C(0xb345, LDXBR, RRE, Z, 0, x2_o, f1, 0, ldxb, 0) + C(0xb346, LEXBR, RRE, Z, 0, x2_o, new, e1, lexb, 0) + +/* LOAD MULTIPLE */ + C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) + C(0xeb98, LMY, RSY_a, LD, 0, a2, 0, 0, lm32, 0) + C(0xeb04, LMG, RSY_a, Z, 0, a2, 0, 0, lm64, 0) +/* LOAD MULTIPLE HIGH */ + C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) +/* LOAD ACCESS MULTIPLE */ + C(0x9a00, LAM, RS_a, Z, 0, a2, 0, 0, lam, 0) + C(0xeb9a, LAMY, RSY_a, LD, 0, a2, 0, 0, lam, 0) + +/* MOVE */ + C(0xd200, MVC, SS_a, Z, la1, a2, 0, 0, mvc, 0) + C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) + C(0xe54c, MVHI, SIL, GIE, la1, i2, 0, m1_32, mov2, 0) + C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) + C(0x9200, MVI, SI, Z, la1, i2, 0, m1_8, mov2, 0) + C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) +/* MOVE LONG */ + C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) +/* MOVE LONG EXTENDED */ + C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) +/* MOVE PAGE */ + C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0) +/* MOVE STRING */ + C(0xb255, MVST, RRE, Z, r1_o, r2_o, 0, 0, mvst, 0) + +/* MULTIPLY */ + C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) + C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xe35c, MFY, RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0) + C(0xb31c, MDBR, RRE, Z, f1_o, f2_o, f1, 0, mdb, 0) + C(0xb34c, MXBR, RRE, Z, 0, x2_o, x1, 0, mxb, 0) + C(0xb30c, MDEBR, RRE, Z, f1_o, e2, f1, 0, mdeb, 0) + C(0xb307, MXDBR, RRE, Z, 0, f2_o, x1, 0, mxdb, 0) + C(0xed17, MEEB, RXE, Z, e1, m2_32u, new, e1, meeb, 0) + C(0xed1c, MDB, RXE, Z, f1_o, m2_64, f1, 0, mdb, 0) + C(0xed0c, MDEB, RXE, Z, f1_o, m2_32u, f1, 0, mdeb, 0) + C(0xed07, MXDB, RXE, Z, 0, m2_64, x1, 0, mxdb, 0) +/* MULTIPLY HALFWORD */ + C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) + C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) +/* MULTIPLY HALFWORD IMMEDIATE */ + C(0xa70c, MHI, RI_a, Z, r1_o, i2, new, r1_32, mul, 0) + C(0xa70d, MGHI, RI_a, Z, r1_o, i2, r1, 0, mul, 0) +/* MULTIPLY LOGICAL */ + C(0xb996, MLR, RRE, Z, r1p1_32u, r2_32u, new, r1_D32, mul, 0) + C(0xe396, ML, RXY_a, Z, r1p1_32u, m2_32u, new, r1_D32, mul, 0) + C(0xb986, MLGR, RRE, Z, r1p1, r2_o, r1_P, 0, mul128, 0) + C(0xe386, MLG, RXY_a, Z, r1p1, m2_64, r1_P, 0, mul128, 0) +/* MULTIPLY SINGLE */ + C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) + C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xe351, MSY, RXY_a, LD, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xb90c, MSGR, RRE, Z, r1_o, r2_o, r1, 0, mul, 0) + C(0xb91c, MSGFR, RRE, Z, r1_o, r2_32s, r1, 0, mul, 0) + C(0xe30c, MSG, RXY_a, Z, r1_o, m2_64, r1, 0, mul, 0) + C(0xe31c, MSGF, RXY_a, Z, r1_o, m2_32s, r1, 0, mul, 0) +/* MULTIPLY SINGLE IMMEDIATE */ + C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) + C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) + +/* MULTIPLY AND ADD */ + C(0xb30e, MAEBR, RRD, Z, e1, e2, new, e1, maeb, 0) + C(0xb31e, MADBR, RRD, Z, f1_o, f2_o, f1, 0, madb, 0) + C(0xed0e, MAEB, RXF, Z, e1, m2_32u, new, e1, maeb, 0) + C(0xed1e, MADB, RXF, Z, f1_o, m2_64, f1, 0, madb, 0) +/* MULTIPLY AND SUBTRACT */ + C(0xb30f, MSEBR, RRD, Z, e1, e2, new, e1, mseb, 0) + C(0xb31f, MSDBR, RRD, Z, f1_o, f2_o, f1, 0, msdb, 0) + C(0xed0f, MSEB, RXF, Z, e1, m2_32u, new, e1, mseb, 0) + C(0xed1f, MSDB, RXF, Z, f1_o, m2_64, f1, 0, msdb, 0) + +/* OR */ + C(0x1600, OR, RR_a, Z, r1, r2, new, r1_32, or, nz32) + C(0xb9f6, ORK, RRF_a, DO, r2, r3, new, r1_32, or, nz32) + C(0x5600, O, RX_a, Z, r1, m2_32s, new, r1_32, or, nz32) + C(0xe356, OY, RXY_a, LD, r1, m2_32s, new, r1_32, or, nz32) + C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) + C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) + C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) + C(0xd600, OC, SS_a, Z, la1, a2, 0, 0, oc, 0) +/* OR IMMEDIATE */ + D(0xc00c, OIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2020) + D(0xc00d, OILF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2000) + D(0xa508, OIHH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1030) + D(0xa509, OIHL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1020) + D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) + D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) + C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64) + C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64) + +/* PREFETCH */ + /* Implemented as nops of course. */ + C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) + C(0xc602, PFDRL, RIL_c, GIE, 0, 0, 0, 0, 0, 0) + +/* POPULATION COUNT */ + C(0xb9e1, POPCNT, RRE, PC, 0, r2_o, r1, 0, popcnt, nz64) + +/* ROTATE LEFT SINGLE LOGICAL */ + C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) + C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) + +/* ROTATE THEN INSERT SELECTED BITS */ + C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) + C(0xec5d, RISBHG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) + C(0xec51, RISBLG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) +/* ROTATE_THEN <OP> SELECTED BITS */ + C(0xec54, RNSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + C(0xec56, ROSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + C(0xec57, RXSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + +/* SEARCH STRING */ + C(0xb25e, SRST, RRE, Z, r1_o, r2_o, 0, 0, srst, 0) + +/* SET ACCESS */ + C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) +/* SET FPC */ + C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) +/* SET FPC AND SIGNAL */ + C(0xb385, SFASR, RRE, IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0) +/* SET BFP ROUNDING MODE */ + C(0xb299, SRNM, S, Z, 0, 0, 0, 0, srnm, 0) + C(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0) +/* SET DFP ROUNDING MODE */ + C(0xb2b9, SRNMT, S, DFP, 0, 0, 0, 0, srnm, 0) + +/* SHIFT LEFT SINGLE */ + D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) + D(0xebdd, SLAK, RSY_a, DO, r3, sh32, new, r1_32, sla, 0, 31) + D(0xeb0b, SLAG, RSY_a, Z, r3, sh64, r1, 0, sla, 0, 63) +/* SHIFT LEFT SINGLE LOGICAL */ + C(0x8900, SLL, RS_a, Z, r1_o, sh32, new, r1_32, sll, 0) + C(0xebdf, SLLK, RSY_a, DO, r3_o, sh32, new, r1_32, sll, 0) + C(0xeb0d, SLLG, RSY_a, Z, r3_o, sh64, r1, 0, sll, 0) +/* SHIFT RIGHT SINGLE */ + C(0x8a00, SRA, RS_a, Z, r1_32s, sh32, new, r1_32, sra, s32) + C(0xebdc, SRAK, RSY_a, DO, r3_32s, sh32, new, r1_32, sra, s32) + C(0xeb0a, SRAG, RSY_a, Z, r3_o, sh64, r1, 0, sra, s64) +/* SHIFT RIGHT SINGLE LOGICAL */ + C(0x8800, SRL, RS_a, Z, r1_32u, sh32, new, r1_32, srl, 0) + C(0xebde, SRLK, RSY_a, DO, r3_32u, sh32, new, r1_32, srl, 0) + C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh64, r1, 0, srl, 0) +/* SHIFT LEFT DOUBLE */ + D(0x8f00, SLDA, RS_a, Z, r1_D32, sh64, new, r1_D32, sla, 0, 31) +/* SHIFT LEFT DOUBLE LOGICAL */ + C(0x8d00, SLDL, RS_a, Z, r1_D32, sh64, new, r1_D32, sll, 0) +/* SHIFT RIGHT DOUBLE */ + C(0x8e00, SRDA, RS_a, Z, r1_D32, sh64, new, r1_D32, sra, s64) +/* SHIFT RIGHT DOUBLE LOGICAL */ + C(0x8c00, SRDL, RS_a, Z, r1_D32, sh64, new, r1_D32, srl, 0) + +/* SQUARE ROOT */ + C(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0) + C(0xb315, SQDBR, RRE, Z, 0, f2_o, f1, 0, sqdb, 0) + C(0xb316, SQXBR, RRE, Z, 0, x2_o, x1, 0, sqxb, 0) + C(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0) + C(0xed15, SQDB, RXE, Z, 0, m2_64, f1, 0, sqdb, 0) + +/* STORE */ + C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) + C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) + C(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0) + C(0x6000, STD, RX_a, Z, f1_o, a2, 0, 0, st64, 0) + C(0xed67, STDY, RXY_a, LD, f1_o, a2, 0, 0, st64, 0) + C(0x7000, STE, RX_a, Z, e1, a2, 0, 0, st32, 0) + C(0xed66, STEY, RXY_a, LD, e1, a2, 0, 0, st32, 0) +/* STORE RELATIVE LONG */ + C(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0) + C(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0) +/* STORE CHARACTER */ + C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) + C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) +/* STORE CHARACTERS UNDER MASK */ + D(0xbe00, STCM, RS_b, Z, r1_o, a2, 0, 0, stcm, 0, 0) + D(0xeb2d, STCMY, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 0) + D(0xeb2c, STCMH, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 32) +/* STORE HALFWORD */ + C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) + C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) +/* STORE HALFWORD RELATIVE LONG */ + C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE ON CONDITION */ + D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0) + D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1) +/* STORE REVERSED */ + C(0xe33f, STRVH, RXY_a, Z, la2, r1_16u, new, m1_16, rev16, 0) + C(0xe33e, STRV, RXY_a, Z, la2, r1_32u, new, m1_32, rev32, 0) + C(0xe32f, STRVG, RXY_a, Z, la2, r1_o, new, m1_64, rev64, 0) + +/* STORE FPC */ + C(0xb29c, STFPC, S, Z, 0, a2, new, m2_32, efpc, 0) + +/* STORE MULTIPLE */ + D(0x9000, STM, RS_a, Z, 0, a2, 0, 0, stm, 0, 4) + D(0xeb90, STMY, RSY_a, LD, 0, a2, 0, 0, stm, 0, 4) + D(0xeb24, STMG, RSY_a, Z, 0, a2, 0, 0, stm, 0, 8) +/* STORE MULTIPLE HIGH */ + C(0xeb26, STMH, RSY_a, Z, 0, a2, 0, 0, stmh, 0) +/* STORE ACCESS MULTIPLE */ + C(0x9b00, STAM, RS_a, Z, 0, a2, 0, 0, stam, 0) + C(0xeb9b, STAMY, RSY_a, LD, 0, a2, 0, 0, stam, 0) + +/* SUBTRACT */ + C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) + C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) + C(0x5b00, S, RX_a, Z, r1, m2_32s, new, r1_32, sub, subs32) + C(0xe35b, SY, RXY_a, LD, r1, m2_32s, new, r1_32, sub, subs32) + C(0xb909, SGR, RRE, Z, r1, r2, r1, 0, sub, subs64) + C(0xb919, SGFR, RRE, Z, r1, r2_32s, r1, 0, sub, subs64) + C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) + C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) + C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) + C(0xb30b, SEBR, RRE, Z, e1, e2, new, e1, seb, f32) + C(0xb31b, SDBR, RRE, Z, f1_o, f2_o, f1, 0, sdb, f64) + C(0xb34b, SXBR, RRE, Z, 0, x2_o, x1, 0, sxb, f128) + C(0xed0b, SEB, RXE, Z, e1, m2_32u, new, e1, seb, f32) + C(0xed1b, SDB, RXE, Z, f1_o, m2_64, f1, 0, sdb, f64) +/* SUBTRACT HALFWORD */ + C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) + C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) +/* SUBTRACT LOGICAL */ + C(0x1f00, SLR, RR_a, Z, r1, r2, new, r1_32, sub, subu32) + C(0xb9fb, SLRK, RRF_a, DO, r2, r3, new, r1_32, sub, subu32) + C(0x5f00, SL, RX_a, Z, r1, m2_32u, new, r1_32, sub, subu32) + C(0xe35f, SLY, RXY_a, LD, r1, m2_32u, new, r1_32, sub, subu32) + C(0xb90b, SLGR, RRE, Z, r1, r2, r1, 0, sub, subu64) + C(0xb91b, SLGFR, RRE, Z, r1, r2_32u, r1, 0, sub, subu64) + C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, sub, subu64) + C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, sub, subu64) + C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, sub, subu64) +/* SUBTRACT LOGICAL IMMEDIATE */ + C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32) + C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64) +/* SUBTRACT LOGICAL WITH BORROW */ + C(0xb999, SLBR, RRE, Z, r1, r2, new, r1_32, subb, subb32) + C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb, subb64) + C(0xe399, SLB, RXY_a, Z, r1, m2_32u, new, r1_32, subb, subb32) + C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb, subb64) + +/* SUPERVISOR CALL */ + C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) + +/* TEST DATA CLASS */ + C(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0) + C(0xed11, TCDB, RXE, Z, f1_o, a2, 0, 0, tcdb, 0) + C(0xed12, TCXB, RXE, Z, x1_o, a2, 0, 0, tcxb, 0) + +/* TEST UNDER MASK */ + C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) + C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) + D(0xa702, TMHH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 48) + D(0xa703, TMHL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 32) + D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) + D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) + +/* TRANSLATE */ + C(0xdc00, TR, SS_a, Z, la1, a2, 0, 0, tr, 0) + +/* UNPACK */ + /* Really format SS_b, but we pack both lengths into one argument + for the helper call, so we might as well leave one 8-bit field. */ + C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) + +#ifndef CONFIG_USER_ONLY +/* COMPARE AND SWAP AND PURGE */ + C(0xb250, CSP, RRE, Z, 0, ra2, 0, 0, csp, 0) +/* DIAGNOSE (KVM hypercall) */ + C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) +/* INSERT STORAGE KEY EXTENDED */ + C(0xb229, ISKE, RRE, Z, 0, r2_o, new, r1_8, iske, 0) +/* INVALIDATE PAGE TABLE ENTRY */ + C(0xb221, IPTE, RRF_a, Z, r1_o, r2_o, 0, 0, ipte, 0) +/* LOAD CONTROL */ + C(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0) + C(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0) +/* LOAD PSW */ + C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) +/* LOAD PSW EXTENDED */ + C(0xb2b2, LPSWE, S, Z, 0, a2, 0, 0, lpswe, 0) +/* LOAD REAL ADDRESS */ + C(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0) + C(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0) + C(0xe303, LRAG, RXY_a, Z, 0, a2, r1, 0, lra, 0) +/* MOVE TO PRIMARY */ + C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) +/* MOVE TO SECONDARY */ + C(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0) +/* PURGE TLB */ + C(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0) +/* RESET REFERENCE BIT EXTENDED */ + C(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0) +/* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */ + C(0xb220, SERVC, RRE, Z, r1_o, r2_o, 0, 0, servc, 0) +/* SET ADDRESSING MODE */ + /* We only do 64-bit, so accept this as a no-op. + Let SAM24 and SAM31 signal illegal instruction. */ + C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +/* SET ADDRESS SPACE CONTROL FAST */ + C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) +/* SET CLOCK */ + /* ??? Not implemented - is it necessary? */ + C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) +/* SET CLOCK COMPARATOR */ + C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) +/* SET CPU TIMER */ + C(0xb208, SPT, S, Z, 0, m2_64, 0, 0, spt, 0) +/* SET PREFIX */ + C(0xb210, SPX, S, Z, 0, m2_32u, 0, 0, spx, 0) +/* SET PSW KEY FROM ADDRESS */ + C(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0) +/* SET STORAGE KEY EXTENDED */ + C(0xb22b, SSKE, RRF_c, Z, r1_o, r2_o, 0, 0, sske, 0) +/* SET SYSTEM MASK */ + C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) +/* SIGNAL PROCESSOR */ + C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) +/* STORE CLOCK */ + C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0) + C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0) +/* STORE CLOCK EXTENDED */ + C(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0) +/* STORE CLOCK COMPARATOR */ + C(0xb207, STCKC, S, Z, la2, 0, new, m1_64, stckc, 0) +/* STORE CONTROL */ + C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) + C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) +/* STORE CPU ADDRESS */ + C(0xb212, STAP, S, Z, la2, 0, new, m1_16, stap, 0) +/* STORE CPU ID */ + C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) +/* STORE CPU TIMER */ + C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) +/* STORE FACILITY LIST */ + C(0xb2b1, STFL, S, Z, 0, 0, 0, 0, stfl, 0) +/* STORE PREFIX */ + C(0xb211, STPX, S, Z, la2, 0, new, m1_32, stpx, 0) +/* STORE SYSTEM INFORMATION */ + C(0xb27d, STSI, S, Z, 0, a2, 0, 0, stsi, 0) +/* STORE THEN AND SYSTEM MASK */ + C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) +/* STORE THEN OR SYSTEM MASK */ + C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) +/* STORE USING REAL ADDRESS */ + C(0xb246, STURA, RRE, Z, r1_o, r2_o, 0, 0, stura, 0) +/* TEST PROTECTION */ + C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) + +/* I/O Instructions. For each we simply indicate non-operation. */ + C(0xb276, XSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb230, CSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb231, HSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb232, MSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb23b, RCHP, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb238, RSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb233, SSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb234, STSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb235, TSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + /* ??? Not listed in PoO ninth edition, but there's a linux driver that + uses it: "A CHSC subchannel is usually present on LPAR only." */ + C(0xb25f, CHSC, S, Z, 0, 0, 0, 0, subchannel, 0) +#endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/insn-format.def b/target-s390x/insn-format.def new file mode 100644 index 0000000000..0e898b90bd --- /dev/null +++ b/target-s390x/insn-format.def @@ -0,0 +1,55 @@ +/* Description of s390 insn formats. */ +/* NAME F1, F2... */ +F0(E) +F1(I, I(1, 8, 8)) +F2(RI_a, R(1, 8), I(2,16,16)) +F2(RI_b, R(1, 8), I(2,16,16)) +F2(RI_c, M(1, 8), I(2,16,16)) +F3(RIE_a, R(1, 8), I(2,16,16), M(3,32)) +F4(RIE_b, R(1, 8), R(2,12), M(3,32), I(4,16,16)) +F4(RIE_c, R(1, 8), I(2,32, 8), M(3,12), I(4,16,16)) +F3(RIE_d, R(1, 8), I(2,16,16), R(3,12)) +F3(RIE_e, R(1, 8), I(2,16,16), R(3,12)) +F5(RIE_f, R(1, 8), R(2,12), I(3,16,8), I(4,24,8), I(5,32,8)) +F2(RIL_a, R(1, 8), I(2,16,32)) +F2(RIL_b, R(1, 8), I(2,16,32)) +F2(RIL_c, M(1, 8), I(2,16,32)) +F4(RIS, R(1, 8), I(2,32, 8), M(3,12), BD(4,16,20)) +/* ??? The PoO does not call out subtypes _a and _b for RR, as it does + for e.g. RX. Our checking requires this for e.g. BCR. */ +F2(RR_a, R(1, 8), R(2,12)) +F2(RR_b, M(1, 8), R(2,12)) +F2(RRE, R(1,24), R(2,28)) +F3(RRD, R(1,16), R(2,28), R(3,24)) +F4(RRF_a, R(1,24), R(2,28), R(3,16), M(4,20)) +F4(RRF_b, R(1,24), R(2,28), R(3,16), M(4,20)) +F4(RRF_c, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRF_d, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRF_e, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRS, R(1, 8), R(2,12), M(3,32), BD(4,16,20)) +F3(RS_a, R(1, 8), BD(2,16,20), R(3,12)) +F3(RS_b, R(1, 8), BD(2,16,20), M(3,12)) +F3(RSI, R(1, 8), I(2,16,16), R(3,12)) +F2(RSL, L(1, 8, 4), BD(1,16,20)) +F3(RSY_a, R(1, 8), BDL(2), R(3,12)) +F3(RSY_b, R(1, 8), BDL(2), M(3,12)) +F2(RX_a, R(1, 8), BXD(2)) +F2(RX_b, M(1, 8), BXD(2)) +F2(RXE, R(1, 8), BXD(2)) +F3(RXF, R(1,32), BXD(2), R(3, 8)) +F2(RXY_a, R(1, 8), BXDL(2)) +F2(RXY_b, M(1, 8), BXDL(2)) +F1(S, BD(2,16,20)) +F2(SI, BD(1,16,20), I(2,8,8)) +F2(SIL, BD(1,16,20), I(2,32,16)) +F2(SIY, BDL(1), I(2, 8, 8)) +F3(SS_a, L(1, 8, 8), BD(1,16,20), BD(2,32,36)) +F4(SS_b, L(1, 8, 4), BD(1,16,20), L(2,12,4), BD(2,32,36)) +F4(SS_c, L(1, 8, 4), BD(1,16,20), BD(2,32,36), I(3,12, 4)) +/* ??? Odd man out. The L1 field here is really a register, but the + easy way to compress the fields has R1 and B1 overlap. */ +F4(SS_d, L(1, 8, 4), BD(1,16,20), BD(2,32,36), R(3,12)) +F4(SS_e, R(1, 8), BD(2,16,20), R(3,12), BD(4,32,36)) +F3(SS_f, BD(1,16,20), L(2,8,8), BD(2,32,36)) +F2(SSE, BD(1,16,20), BD(2,32,36)) +F3(SSF, BD(1,16,20), BD(2,32,36), R(3,8)) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index b683709860..685830124f 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -30,46 +30,97 @@ #endif /* 64/64 -> 128 unsigned multiplication */ -void HELPER(mlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) +uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) { -#if HOST_LONG_BITS == 64 && defined(__GNUC__) - /* assuming 64-bit hosts have __uint128_t */ - __uint128_t res = (__uint128_t)env->regs[r1 + 1]; + uint64_t reth; + mulu64(&env->retxl, &reth, v1, v2); + return reth; +} - res *= (__uint128_t)v2; - env->regs[r1] = (uint64_t)(res >> 64); - env->regs[r1 + 1] = (uint64_t)res; -#else - mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); -#endif +/* 64/32 -> 32 signed division */ +int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) +{ + int32_t ret, b = b64; + int64_t q; + + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + ret = q = a / b; + env->retxl = a % b; + + /* Catch non-representable quotient. */ + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + return ret; } -/* 128 -> 64/64 unsigned division */ -void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) +/* 64/32 -> 32 unsigned division */ +uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) +{ + uint32_t ret, b = b64; + uint64_t q; + + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + ret = q = a / b; + env->retxl = a % b; + + /* Catch non-representable quotient. */ + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + return ret; +} + +/* 64/64 -> 64 signed division */ +int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) { - uint64_t divisor = v2; + /* Catch divide by zero, and non-representable quotient (MIN / -1). */ + if (b == 0 || (b == -1 && a == (1ll << 63))) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + env->retxl = a % b; + return a / b; +} - if (!env->regs[r1]) { +/* 128 -> 64/64 unsigned division */ +uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t b) +{ + uint64_t ret; + /* Signal divide by zero. */ + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + if (ah == 0) { /* 64 -> 64/64 case */ - env->regs[r1] = env->regs[r1 + 1] % divisor; - env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; - return; + env->retxl = al % b; + ret = al / b; } else { + /* ??? Move i386 idivq helper to host-utils. */ #if HOST_LONG_BITS == 64 && defined(__GNUC__) /* assuming 64-bit hosts have __uint128_t */ - __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | - (env->regs[r1 + 1]); - __uint128_t quotient = dividend / divisor; - __uint128_t remainder = dividend % divisor; - - env->regs[r1 + 1] = quotient; - env->regs[r1] = remainder; + __uint128_t a = ((__uint128_t)ah << 64) | al; + __uint128_t q = a / b; + env->retxl = a % b; + ret = q; + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } #else /* 32-bit hosts would need special wrapper functionality - just abort if we encounter such a case; it's very unlikely anyways. */ cpu_abort(env, "128 -> 64/64 division not implemented\n"); #endif } + return ret; } /* absolute value 32-bit */ @@ -114,69 +165,10 @@ int64_t HELPER(nabs_i64)(int64_t val) } } -/* add with carry 32-bit unsigned */ -uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) +/* count leading zeros, for find leftmost one */ +uint64_t HELPER(clz)(uint64_t v) { - uint32_t res; - - res = v1 + v2; - if (cc & 2) { - res++; - } - - return res; -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2) -{ - uint32_t v1 = env->regs[r1]; - uint32_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1, - uint64_t v1, uint64_t v2) -{ - uint64_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - -/* find leftmost one */ -uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) -{ - uint64_t res = 0; - uint64_t ov2 = v2; - - while (!(v2 & 0x8000000000000000ULL) && v2) { - v2 <<= 1; - res++; - } - - if (!v2) { - env->regs[r1] = 64; - env->regs[r1 + 1] = 0; - return 0; - } else { - env->regs[r1] = res; - env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); - return 2; - } + return clz64(v); } uint64_t HELPER(cvd)(int32_t bin) @@ -199,3 +191,15 @@ uint64_t HELPER(cvd)(int32_t bin) return dec; } + +uint64_t HELPER(popcnt)(uint64_t r2) +{ + uint64_t ret = 0; + int i; + + for (i = 0; i < 64; i += 8) { + uint64_t t = ctpop32((r2 >> i) & 0xff); + ret |= t << i; + } + return ret; +} diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index bed21e6e1c..372334b3c8 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -304,214 +304,142 @@ uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, return cc; } -/* store character under mask */ -void HELPER(stcm)(CPUS390XState *env, uint32_t r1, uint32_t mask, - uint64_t addr) +static inline uint64_t fix_address(CPUS390XState *env, uint64_t a) { - uint8_t r; - - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, - addr); - while (mask) { - if (mask & 8) { - r = (r1 & 0xff000000UL) >> 24; - cpu_stb_data(env, addr, r); - HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); - addr++; - } - mask = (mask << 1) & 0xf; - r1 <<= 8; + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { + a &= 0x7fffffff; } - HELPER_LOG("\n"); + return a; } static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) { uint64_t r = d2; - if (x2) { r += env->regs[x2]; } - if (b2) { r += env->regs[b2]; } - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; + return fix_address(env, r); } static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) { - uint64_t r = env->regs[reg]; - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; + return fix_address(env, env->regs[reg]); } /* search string (c is byte to search, r2 is string, r1 end of string) */ -uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, + uint64_t str) { - uint64_t i; - uint32_t cc = 2; - uint64_t str = get_address_31fix(env, r2); - uint64_t end = get_address_31fix(env, r1); - - HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, - c, env->regs[r1], env->regs[r2]); - - for (i = str; i != end; i++) { - if (cpu_ldub_data(env, i) == c) { - env->regs[r1] = i; - cc = 1; - break; + uint32_t len; + uint8_t v, c = r0; + + str = fix_address(env, str); + end = fix_address(env, end); + + /* Assume for now that R2 is unmodified. */ + env->retxl = str; + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + if (str + len == end) { + /* Character not found. R1 & R2 are unmodified. */ + env->cc_op = 2; + return end; + } + v = cpu_ldub_data(env, str + len); + if (v == c) { + /* Character found. Set R1 to the location; R2 is unmodified. */ + env->cc_op = 1; + return str + len; } } - return cc; + /* CPU-determined bytes processed. Advance R2 to next byte to process. */ + env->retxl = str + len; + env->cc_op = 3; + return end; } /* unsigned string compare (c is string terminator) */ -uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) { - uint64_t s1 = get_address_31fix(env, r1); - uint64_t s2 = get_address_31fix(env, r2); - uint8_t v1, v2; - uint32_t cc; + uint32_t len; c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: comparing '%s' and '%s'\n", - __func__, (char *)g2h(s1), (char *)g2h(s2)); - } -#endif - for (;;) { - v1 = cpu_ldub_data(env, s1); - v2 = cpu_ldub_data(env, s2); - if ((v1 == c || v2 == c) || (v1 != v2)) { - break; + s1 = fix_address(env, s1); + s2 = fix_address(env, s2); + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + uint8_t v1 = cpu_ldub_data(env, s1 + len); + uint8_t v2 = cpu_ldub_data(env, s2 + len); + if (v1 == v2) { + if (v1 == c) { + /* Equal. CC=0, and don't advance the registers. */ + env->cc_op = 0; + env->retxl = s2; + return s1; + } + } else { + /* Unequal. CC={1,2}, and advance the registers. Note that + the terminator need not be zero, but the string that contains + the terminator is by definition "low". */ + env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2); + env->retxl = s2 + len; + return s1 + len; } - s1++; - s2++; } - if (v1 == v2) { - cc = 0; - } else { - cc = (v1 < v2) ? 1 : 2; - /* FIXME: 31-bit mode! */ - env->regs[r1] = s1; - env->regs[r2] = s2; - } - return cc; + /* CPU-determined bytes equal; advance the registers. */ + env->cc_op = 3; + env->retxl = s2 + len; + return s1 + len; } /* move page */ void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) { /* XXX missing r0 handling */ + env->cc_op = 0; #ifdef CONFIG_USER_ONLY - int i; - - for (i = 0; i < TARGET_PAGE_SIZE; i++) { - cpu_stb_data(env, r1 + i, cpu_ldub_data(env, r2 + i)); - } + memmove(g2h(r1), g2h(r2), TARGET_PAGE_SIZE); #else mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); #endif } /* string copy (c is string terminator) */ -void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s) { - uint64_t dest = get_address_31fix(env, r1); - uint64_t src = get_address_31fix(env, r2); - uint8_t v; + uint32_t len; c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), - dest); - } -#endif - for (;;) { - v = cpu_ldub_data(env, src); - cpu_stb_data(env, dest, v); + d = fix_address(env, d); + s = fix_address(env, s); + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + uint8_t v = cpu_ldub_data(env, s + len); + cpu_stb_data(env, d + len, v); if (v == c) { - break; + /* Complete. Set CC=1 and advance R1. */ + env->cc_op = 1; + env->retxl = s; + return d + len; } - src++; - dest++; - } - env->regs[r1] = dest; /* FIXME: 31-bit mode! */ -} - -/* compare and swap 64-bit */ -uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint64_t v2 = cpu_ldq_data(env, a2); - - if (env->regs[r1] == v2) { - cc = 0; - cpu_stq_data(env, a2, env->regs[r3]); - } else { - cc = 1; - env->regs[r1] = v2; - } - return cc; -} - -/* compare double and swap 64-bit */ -uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint64_t v2_hi = cpu_ldq_data(env, a2); - uint64_t v2_lo = cpu_ldq_data(env, a2 + 8); - uint64_t v1_hi = env->regs[r1]; - uint64_t v1_lo = env->regs[r1 + 1]; - - if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { - cc = 0; - cpu_stq_data(env, a2, env->regs[r3]); - cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]); - } else { - cc = 1; - env->regs[r1] = v2_hi; - env->regs[r1 + 1] = v2_lo; } - return cc; -} - -/* compare and swap 32-bit */ -uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint32_t v2 = cpu_ldl_data(env, a2); - - HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); - if (((uint32_t)env->regs[r1]) == v2) { - cc = 0; - cpu_stl_data(env, a2, (uint32_t)env->regs[r3]); - } else { - cc = 1; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; - } - return cc; + /* Incomplete. Set CC=3 and signal to advance R1 and R2. */ + env->cc_op = 3; + env->retxl = s + len; + return d + len; } static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, @@ -594,7 +522,7 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); env->psw.addr = ret - 4; env->int_svc_code = (insn | v1) & 0xff; - env->int_svc_ilc = 4; + env->int_svc_ilen = 4; helper_exception(env, EXCP_SVC); } else if ((insn & 0xff00) == 0xbf00) { uint32_t insn2, r1, r3, b2, d2; @@ -613,55 +541,6 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, return cc; } -/* store character under mask high operates on the upper half of r1 */ -void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address, - uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - - while (mask) { - if (mask & 8) { - cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff); - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - } -} - -/* insert character under mask high; same as icm, but operates on the - upper half of r1 */ -uint32_t HELPER(icmh)(CPUS390XState *env, uint32_t r1, uint64_t address, - uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - uint64_t rmask = 0xff00000000000000ULL; - uint8_t val = 0; - int ccd = 0; - uint32_t cc = 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &= ~rmask; - val = cpu_ldub_data(env, address); - if ((val & 0x80) && !ccd) { - cc = 1; - } - ccd = 1; - if (val && cc == 0) { - cc = 2; - } - env->regs[r1] |= (uint64_t)val << pos; - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - rmask >>= 8; - } - - return cc; -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { @@ -822,42 +701,49 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, } /* checksum */ -void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, + uint64_t src, uint64_t src_len) { - uint64_t src = get_address_31fix(env, r2); - uint64_t src_len = env->regs[(r2 + 1) & 15]; - uint64_t cksm = (uint32_t)env->regs[r1]; + uint64_t max_len, len; + uint64_t cksm = (uint32_t)r1; - while (src_len >= 4) { - cksm += cpu_ldl_data(env, src); + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + max_len = (src_len > 0x2000 ? 0x2000 : src_len); - /* move to next word */ - src_len -= 4; - src += 4; + /* Process full words as available. */ + for (len = 0; len + 4 <= max_len; len += 4, src += 4) { + cksm += (uint32_t)cpu_ldl_data(env, src); } - switch (src_len) { - case 0: - break; + switch (max_len - len) { case 1: cksm += cpu_ldub_data(env, src) << 24; + len += 1; break; case 2: cksm += cpu_lduw_data(env, src) << 16; + len += 2; break; case 3: cksm += cpu_lduw_data(env, src) << 16; cksm += cpu_ldub_data(env, src + 2) << 8; + len += 3; break; } - /* indicate we've processed everything */ - env->regs[r2] = src + src_len; - env->regs[(r2 + 1) & 15] = 0; + /* Fold the carry from the checksum. Note that we can see carry-out + during folding more than once (but probably not more than twice). */ + while (cksm > 0xffffffffull) { + cksm = (uint32_t)cksm + (cksm >> 32); + } + + /* Indicate whether or not we've processed everything. */ + env->cc_op = (len == src_len ? 0 : 3); - /* store result */ - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - ((uint32_t)cksm + (cksm >> 32)); + /* Return both cksm and processed length. */ + env->retxl = cksm; + return len; } void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, @@ -1007,7 +893,7 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) } /* set storage key extended */ -void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2) +void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) { uint64_t addr = get_address(env, 0, 0, r2); @@ -1019,7 +905,7 @@ void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2) } /* reset reference bit extended */ -uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2) +uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) { uint8_t re; uint8_t key; @@ -1045,16 +931,16 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2) } /* compare and swap and purge */ -uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2) { uint32_t cc; uint32_t o1 = env->regs[r1]; - uint64_t a2 = get_address_31fix(env, r2) & ~3ULL; + uint64_t a2 = r2 & ~3ULL; uint32_t o2 = cpu_ldl_data(env, a2); if (o1 == o2) { cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]); - if (env->regs[r2] & 0x3) { + if (r2 & 0x3) { /* flush TLB / ALB */ tlb_flush(env, 1); } @@ -1154,13 +1040,13 @@ void HELPER(ptlb)(CPUS390XState *env) } /* store using real address */ -void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1) +void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) { - stw_phys(get_address(env, 0, 0, addr), v1); + stw_phys(get_address(env, 0, 0, addr), (uint32_t)v1); } /* load real address */ -uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) +uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) { uint32_t cc = 0; int old_exc = env->exception_index; @@ -1184,14 +1070,7 @@ uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) } env->exception_index = old_exc; - if (!(env->psw.mask & PSW_MASK_64)) { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - (ret & 0xffffffffULL); - } else { - env->regs[r1] = ret; - } - - return cc; + env->cc_op = cc; + return ret; } - #endif diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 70f9739685..3015bfe3f2 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -41,7 +41,27 @@ #define HELPER_LOG(x...) #endif -/* raise an exception */ +/* Raise an exception dynamically from a helper function. */ +void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, + uintptr_t retaddr) +{ + int t; + + env->exception_index = EXCP_PGM; + env->int_pgm_code = excp; + + /* Use the (ultimate) callers address to find the insn that trapped. */ + cpu_restore_state(env, retaddr); + + /* Advance past the insn. */ + t = cpu_ldub_code(env, env->psw.addr); + env->int_pgm_ilen = t = get_ilen(t); + env->psw.addr += 2 * t; + + cpu_loop_exit(env); +} + +/* Raise an exception statically from a TB. */ void HELPER(exception)(CPUS390XState *env, uint32_t excp) { HELPER_LOG("%s: exception %d\n", __func__, excp); @@ -50,7 +70,7 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp) } #ifndef CONFIG_USER_ONLY -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) { qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", env->psw.addr); @@ -61,18 +81,16 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) #endif } else { env->int_pgm_code = code; - env->int_pgm_ilc = ilc; + env->int_pgm_ilen = ilen; env->exception_index = EXCP_PGM; cpu_loop_exit(env); } } /* SCLP service call */ -uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2) +uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) { - int r; - - r = sclp_service_call(r1, r2); + int r = sclp_service_call(r1, r2); if (r < 0) { program_interrupt(env, -r, 4); return 0; @@ -105,38 +123,22 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, } if (r) { - program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); + program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); } return r; } -/* Store CPU ID */ -void HELPER(stidp)(CPUS390XState *env, uint64_t a1) -{ - cpu_stq_data(env, a1, env->cpu_num); -} - /* Set Prefix */ void HELPER(spx)(CPUS390XState *env, uint64_t a1) { - uint32_t prefix; - - prefix = cpu_ldl_data(env, a1); - env->psa = prefix & 0xfffff000; + uint32_t prefix = a1 & 0x7fffe000; + env->psa = prefix; qemu_log("prefix: %#x\n", prefix); tlb_flush_page(env, 0); tlb_flush_page(env, TARGET_PAGE_SIZE); } -/* Set Clock */ -uint32_t HELPER(sck)(uint64_t a1) -{ - /* XXX not implemented - is it necessary? */ - - return 0; -} - static inline uint64_t clock_value(CPUS390XState *env) { uint64_t time; @@ -148,32 +150,14 @@ static inline uint64_t clock_value(CPUS390XState *env) } /* Store Clock */ -uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1) -{ - cpu_stq_data(env, a1, clock_value(env)); - - return 0; -} - -/* Store Clock Extended */ -uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stck)(CPUS390XState *env) { - cpu_stb_data(env, a1, 0); - /* basically the same value as stck */ - cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num); - /* more fine grained than stck */ - cpu_stq_data(env, a1 + 9, 0); - /* XXX programmable fields */ - cpu_stw_data(env, a1 + 17, 0); - - return 0; + return clock_value(env); } /* Set Clock Comparator */ -void HELPER(sckc)(CPUS390XState *env, uint64_t a1) +void HELPER(sckc)(CPUS390XState *env, uint64_t time) { - uint64_t time = cpu_ldq_data(env, a1); - if (time == -1ULL) { return; } @@ -187,17 +171,15 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t a1) } /* Store Clock Comparator */ -void HELPER(stckc)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stckc)(CPUS390XState *env) { /* XXX implement */ - cpu_stq_data(env, a1, 0); + return 0; } /* Set CPU Timer */ -void HELPER(spt)(CPUS390XState *env, uint64_t a1) +void HELPER(spt)(CPUS390XState *env, uint64_t time) { - uint64_t time = cpu_ldq_data(env, a1); - if (time == -1ULL) { return; } @@ -209,15 +191,15 @@ void HELPER(spt)(CPUS390XState *env, uint64_t a1) } /* Store CPU Timer */ -void HELPER(stpt)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stpt)(CPUS390XState *env) { /* XXX implement */ - cpu_stq_data(env, a1, 0); + return 0; } /* Store System Information */ -uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0, - uint32_t r1) +uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, + uint64_t r0, uint64_t r1) { int cc = 0; int sel1, sel2; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9e34741311..a57296c64f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -18,7 +18,6 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -/* #define DEBUG_ILLEGAL_INSTRUCTIONS */ /* #define DEBUG_INLINE_BRANCHES */ #define S390X_DEBUG_DISAS /* #define S390X_DEBUG_DISAS_VERBOSE */ @@ -33,6 +32,7 @@ #include "disas/disas.h" #include "tcg-op.h" #include "qemu/log.h" +#include "qemu/host-utils.h" /* global register indexes */ static TCGv_ptr cpu_env; @@ -42,29 +42,41 @@ static TCGv_ptr cpu_env; #define GEN_HELPER 1 #include "helper.h" + +/* Information that (most) every instruction needs to manipulate. */ typedef struct DisasContext DisasContext; +typedef struct DisasInsn DisasInsn; +typedef struct DisasFields DisasFields; + struct DisasContext { - uint64_t pc; - int is_jmp; - enum cc_op cc_op; struct TranslationBlock *tb; + const DisasInsn *insn; + DisasFields *fields; + uint64_t pc, next_pc; + enum cc_op cc_op; + bool singlestep_enabled; }; -#define DISAS_EXCP 4 +/* Information carried about a condition to be evaluated. */ +typedef struct { + TCGCond cond:8; + bool is_64; + bool g1; + bool g2; + union { + struct { TCGv_i64 a, b; } s64; + struct { TCGv_i32 a, b; } s32; + } u; +} DisasCompare; -static void gen_op_calc_cc(DisasContext *s); +#define DISAS_EXCP 4 #ifdef DEBUG_INLINE_BRANCHES static uint64_t inline_branch_hit[CC_OP_MAX]; static uint64_t inline_branch_miss[CC_OP_MAX]; #endif -static inline void debug_insn(uint64_t insn) -{ - LOG_DISAS("insn: 0x%" PRIx64 "\n", insn); -} - -static inline uint64_t pc_to_link_info(DisasContext *s, uint64_t pc) +static uint64_t pc_to_link_info(DisasContext *s, uint64_t pc) { if (!(s->tb->flags & FLAG_MASK_64)) { if (s->tb->flags & FLAG_MASK_32) { @@ -97,7 +109,7 @@ void cpu_dump_state(CPUS390XState *env, FILE *f, fprintf_function cpu_fprintf, } for (i = 0; i < 16; i++) { - cpu_fprintf(f, "F%02d=%016" PRIx64, i, *(uint64_t *)&env->fregs[i]); + cpu_fprintf(f, "F%02d=%016" PRIx64, i, env->fregs[i].ll); if ((i % 4) == 3) { cpu_fprintf(f, "\n"); } else { @@ -134,21 +146,22 @@ static TCGv_i64 cc_src; static TCGv_i64 cc_dst; static TCGv_i64 cc_vr; -static char cpu_reg_names[10*3 + 6*4]; +static char cpu_reg_names[32][4]; static TCGv_i64 regs[16]; +static TCGv_i64 fregs[16]; static uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; void s390x_translate_init(void) { int i; - size_t cpu_reg_names_size = sizeof(cpu_reg_names); - char *p; cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - psw_addr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, psw.addr), + psw_addr = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUS390XState, psw.addr), "psw_addr"); - psw_mask = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, psw.mask), + psw_mask = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUS390XState, psw.mask), "psw_mask"); cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op), @@ -160,116 +173,87 @@ void s390x_translate_init(void) cc_vr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, cc_vr), "cc_vr"); - p = cpu_reg_names; for (i = 0; i < 16; i++) { - snprintf(p, cpu_reg_names_size, "r%d", i); + snprintf(cpu_reg_names[i], sizeof(cpu_reg_names[0]), "r%d", i); regs[i] = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUS390XState, regs[i]), p); - p += (i < 10) ? 3 : 4; - cpu_reg_names_size -= (i < 10) ? 3 : 4; + offsetof(CPUS390XState, regs[i]), + cpu_reg_names[i]); } -} -static inline TCGv_i64 load_reg(int reg) -{ - TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_mov_i64(r, regs[reg]); - return r; -} - -static inline TCGv_i64 load_freg(int reg) -{ - TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_ld_i64(r, cpu_env, offsetof(CPUS390XState, fregs[reg].d)); - return r; -} + for (i = 0; i < 16; i++) { + snprintf(cpu_reg_names[i + 16], sizeof(cpu_reg_names[0]), "f%d", i); + fregs[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUS390XState, fregs[i].d), + cpu_reg_names[i + 16]); + } -static inline TCGv_i32 load_freg32(int reg) -{ - TCGv_i32 r = tcg_temp_new_i32(); - tcg_gen_ld_i32(r, cpu_env, offsetof(CPUS390XState, fregs[reg].l.upper)); - return r; + /* register helpers */ +#define GEN_HELPER 2 +#include "helper.h" } -static inline TCGv_i32 load_reg32(int reg) +static TCGv_i64 load_reg(int reg) { - TCGv_i32 r = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(r, regs[reg]); + TCGv_i64 r = tcg_temp_new_i64(); + tcg_gen_mov_i64(r, regs[reg]); return r; } -static inline TCGv_i64 load_reg32_i64(int reg) +static TCGv_i64 load_freg32_i64(int reg) { TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_ext32s_i64(r, regs[reg]); + tcg_gen_shri_i64(r, fregs[reg], 32); return r; } -static inline void store_reg(int reg, TCGv_i64 v) +static void store_reg(int reg, TCGv_i64 v) { tcg_gen_mov_i64(regs[reg], v); } -static inline void store_freg(int reg, TCGv_i64 v) +static void store_freg(int reg, TCGv_i64 v) { - tcg_gen_st_i64(v, cpu_env, offsetof(CPUS390XState, fregs[reg].d)); + tcg_gen_mov_i64(fregs[reg], v); } -static inline void store_reg32(int reg, TCGv_i32 v) +static void store_reg32_i64(int reg, TCGv_i64 v) { -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v); -#else - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, v); /* 32 bit register writes keep the upper half */ - tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 32); - tcg_temp_free_i64(tmp); -#endif -} - -static inline void store_reg32_i64(int reg, TCGv_i64 v) -{ - /* 32 bit register writes keep the upper half */ -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(TCGV_LOW(regs[reg]), TCGV_LOW(v)); -#else tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32); -#endif } -static inline void store_reg16(int reg, TCGv_i32 v) +static void store_reg32h_i64(int reg, TCGv_i64 v) { - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, v); - /* 16 bit register writes keep the upper bytes */ - tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 16); - tcg_temp_free_i64(tmp); + tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32); } -static inline void store_reg8(int reg, TCGv_i64 v) +static void store_freg32_i64(int reg, TCGv_i64 v) { - /* 8 bit register writes keep the upper bytes */ - tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 8); + tcg_gen_deposit_i64(fregs[reg], fregs[reg], v, 32, 32); } -static inline void store_freg32(int reg, TCGv_i32 v) +static void return_low128(TCGv_i64 dest) { - tcg_gen_st_i32(v, cpu_env, offsetof(CPUS390XState, fregs[reg].l.upper)); + tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl)); } -static inline void update_psw_addr(DisasContext *s) +static void update_psw_addr(DisasContext *s) { /* psw.addr */ tcg_gen_movi_i64(psw_addr, s->pc); } -static inline void potential_page_fault(DisasContext *s) +static void update_cc_op(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { + tcg_gen_movi_i32(cc_op, s->cc_op); + } +} + +static void potential_page_fault(DisasContext *s) { -#ifndef CONFIG_USER_ONLY update_psw_addr(s); - gen_op_calc_cc(s); -#endif + update_cc_op(s); } static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) @@ -279,18 +263,15 @@ static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc) { - return (uint64_t)cpu_ldl_code(env, pc); + return (uint64_t)(uint32_t)cpu_ldl_code(env, pc); } static inline uint64_t ld_code6(CPUS390XState *env, uint64_t pc) { - uint64_t opc; - opc = (uint64_t)cpu_lduw_code(env, pc) << 32; - opc |= (uint64_t)(uint32_t)cpu_ldl_code(env, pc + 2); - return opc; + return (ld_code2(env, pc) << 32) | ld_code4(env, pc + 2); } -static inline int get_mem_index(DisasContext *s) +static int get_mem_index(DisasContext *s) { switch (s->tb->flags & FLAG_MASK_ASC) { case PSW_ASC_PRIMARY >> 32: @@ -305,179 +286,114 @@ static inline int get_mem_index(DisasContext *s) } } -static inline void gen_debug(DisasContext *s) +static void gen_exception(int excp) { - TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); - update_psw_addr(s); - gen_op_calc_cc(s); + TCGv_i32 tmp = tcg_const_i32(excp); gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_EXCP; -} - -#ifdef CONFIG_USER_ONLY - -static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) -{ - TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_EXCP; -} - -#else /* CONFIG_USER_ONLY */ - -static void debug_print_inst(CPUS390XState *env, DisasContext *s, int ilc) -{ -#ifdef DEBUG_ILLEGAL_INSTRUCTIONS - uint64_t inst = 0; - - switch (ilc & 3) { - case 1: - inst = ld_code2(env, s->pc); - break; - case 2: - inst = ld_code4(env, s->pc); - break; - case 3: - inst = ld_code6(env, s->pc); - break; - } - - fprintf(stderr, "Illegal instruction [%d at %016" PRIx64 "]: 0x%016" - PRIx64 "\n", ilc, s->pc, inst); -#endif } -static void gen_program_exception(CPUS390XState *env, DisasContext *s, int ilc, - int code) +static void gen_program_exception(DisasContext *s, int code) { TCGv_i32 tmp; - debug_print_inst(env, s, ilc); - - /* remember what pgm exeption this was */ + /* Remember what pgm exeption this was. */ tmp = tcg_const_i32(code); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_temp_free_i32(tmp); - tmp = tcg_const_i32(ilc); - tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilc)); + tmp = tcg_const_i32(s->next_pc - s->pc); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen)); tcg_temp_free_i32(tmp); - /* advance past instruction */ - s->pc += (ilc * 2); + /* Advance past instruction. */ + s->pc = s->next_pc; update_psw_addr(s); - /* save off cc */ - gen_op_calc_cc(s); - - /* trigger exception */ - tmp = tcg_const_i32(EXCP_PGM); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); + /* Save off cc. */ + update_cc_op(s); - /* end TB here */ - s->is_jmp = DISAS_EXCP; -} - - -static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) -{ - gen_program_exception(env, s, ilc, PGM_SPECIFICATION); + /* Trigger exception. */ + gen_exception(EXCP_PGM); } -static void gen_privileged_exception(CPUS390XState *env, DisasContext *s, - int ilc) +static inline void gen_illegal_opcode(DisasContext *s) { - gen_program_exception(env, s, ilc, PGM_PRIVILEGED); + gen_program_exception(s, PGM_SPECIFICATION); } -static void check_privileged(CPUS390XState *env, DisasContext *s, int ilc) +static inline void check_privileged(DisasContext *s) { if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) { - gen_privileged_exception(env, s, ilc); + gen_program_exception(s, PGM_PRIVILEGED); } } -#endif /* CONFIG_USER_ONLY */ - static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) { - TCGv_i64 tmp; + TCGv_i64 tmp = tcg_temp_new_i64(); + bool need_31 = !(s->tb->flags & FLAG_MASK_64); - /* 31-bitify the immediate part; register contents are dealt with below */ - if (!(s->tb->flags & FLAG_MASK_64)) { - d2 &= 0x7fffffffUL; - } + /* Note that d2 is limited to 20 bits, signed. If we crop negative + displacements early we create larger immedate addends. */ - if (x2) { - if (d2) { - tmp = tcg_const_i64(d2); - tcg_gen_add_i64(tmp, tmp, regs[x2]); - } else { - tmp = load_reg(x2); - } - if (b2) { - tcg_gen_add_i64(tmp, tmp, regs[b2]); - } + /* Note that addi optimizes the imm==0 case. */ + if (b2 && x2) { + tcg_gen_add_i64(tmp, regs[b2], regs[x2]); + tcg_gen_addi_i64(tmp, tmp, d2); } else if (b2) { - if (d2) { - tmp = tcg_const_i64(d2); - tcg_gen_add_i64(tmp, tmp, regs[b2]); - } else { - tmp = load_reg(b2); - } + tcg_gen_addi_i64(tmp, regs[b2], d2); + } else if (x2) { + tcg_gen_addi_i64(tmp, regs[x2], d2); } else { - tmp = tcg_const_i64(d2); + if (need_31) { + d2 &= 0x7fffffff; + need_31 = false; + } + tcg_gen_movi_i64(tmp, d2); } - - /* 31-bit mode mask if there are values loaded from registers */ - if (!(s->tb->flags & FLAG_MASK_64) && (x2 || b2)) { - tcg_gen_andi_i64(tmp, tmp, 0x7fffffffUL); + if (need_31) { + tcg_gen_andi_i64(tmp, tmp, 0x7fffffff); } return tmp; } -static void gen_op_movi_cc(DisasContext *s, uint32_t val) +static inline bool live_cc_data(DisasContext *s) { - s->cc_op = CC_OP_CONST0 + val; + return (s->cc_op != CC_OP_DYNAMIC + && s->cc_op != CC_OP_STATIC + && s->cc_op > 3); } -static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst) +static inline void gen_op_movi_cc(DisasContext *s, uint32_t val) { - tcg_gen_discard_i64(cc_src); - tcg_gen_mov_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); - s->cc_op = op; + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_dst); + tcg_gen_discard_i64(cc_vr); + } + s->cc_op = CC_OP_CONST0 + val; } -static void gen_op_update1_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 dst) +static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst) { - tcg_gen_discard_i64(cc_src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_vr); + } + tcg_gen_mov_i64(cc_dst, dst); s->cc_op = op; } static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, TCGv_i64 dst) { + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_vr); + } tcg_gen_mov_i64(cc_src, src); tcg_gen_mov_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); - s->cc_op = op; -} - -static void gen_op_update2_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src, - TCGv_i32 dst) -{ - tcg_gen_extu_i32_i64(cc_src, src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); s->cc_op = op; } @@ -490,214 +406,71 @@ static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, s->cc_op = op; } -static void gen_op_update3_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src, - TCGv_i32 dst, TCGv_i32 vr) -{ - tcg_gen_extu_i32_i64(cc_src, src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_extu_i32_i64(cc_vr, vr); - s->cc_op = op; -} - -static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val) -{ - gen_op_update1_cc_i32(s, CC_OP_NZ, val); -} - -static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) +static void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) { gen_op_update1_cc_i64(s, CC_OP_NZ, val); } -static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - enum cc_op cond) -{ - gen_op_update2_cc_i32(s, cond, v1, v2); -} - -static inline void cmp_64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - enum cc_op cond) -{ - gen_op_update2_cc_i64(s, cond, v1, v2); -} - -static inline void cmp_s32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - cmp_32(s, v1, v2, CC_OP_LTGT_32); -} - -static inline void cmp_u32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - cmp_32(s, v1, v2, CC_OP_LTUGTU_32); -} - -static inline void cmp_s32c(DisasContext *s, TCGv_i32 v1, int32_t v2) -{ - /* XXX optimize for the constant? put it in s? */ - TCGv_i32 tmp = tcg_const_i32(v2); - cmp_32(s, v1, tmp, CC_OP_LTGT_32); - tcg_temp_free_i32(tmp); -} - -static inline void cmp_u32c(DisasContext *s, TCGv_i32 v1, uint32_t v2) -{ - TCGv_i32 tmp = tcg_const_i32(v2); - cmp_32(s, v1, tmp, CC_OP_LTUGTU_32); - tcg_temp_free_i32(tmp); -} - -static inline void cmp_s64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2) -{ - cmp_64(s, v1, v2, CC_OP_LTGT_64); -} - -static inline void cmp_u64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2) -{ - cmp_64(s, v1, v2, CC_OP_LTUGTU_64); -} - -static inline void cmp_s64c(DisasContext *s, TCGv_i64 v1, int64_t v2) -{ - TCGv_i64 tmp = tcg_const_i64(v2); - cmp_s64(s, v1, tmp); - tcg_temp_free_i64(tmp); -} - -static inline void cmp_u64c(DisasContext *s, TCGv_i64 v1, uint64_t v2) -{ - TCGv_i64 tmp = tcg_const_i64(v2); - cmp_u64(s, v1, tmp); - tcg_temp_free_i64(tmp); -} - -static inline void set_cc_s32(DisasContext *s, TCGv_i32 val) -{ - gen_op_update1_cc_i32(s, CC_OP_LTGT0_32, val); -} - -static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) -{ - gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); -} - -static void set_cc_add64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_ADD_64, v1, v2, vr); -} - -static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr); -} - -static void set_cc_sub64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_SUB_64, v1, v2, vr); -} - -static void set_cc_subu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_SUBU_64, v1, v2, vr); -} - -static void set_cc_abs64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_ABS_64, v1); -} - -static void set_cc_nabs64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_NABS_64, v1); -} - -static void set_cc_add32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_ADD_32, v1, v2, vr); -} - -static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - TCGv_i32 vr) +static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val) { - gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr); + gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val); } -static void set_cc_sub32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) +static void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val) { - gen_op_update3_cc_i32(s, CC_OP_SUB_32, v1, v2, vr); + gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val); } -static void set_cc_subu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - TCGv_i32 vr) +static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) { - gen_op_update3_cc_i32(s, CC_OP_SUBU_32, v1, v2, vr); -} - -static void set_cc_abs32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1); -} - -static void set_cc_nabs32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_NABS_32, v1); -} - -static void set_cc_comp32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_COMP_32, v1); -} - -static void set_cc_comp64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_COMP_64, v1); -} - -static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); -} - -static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) -{ - tcg_gen_extu_i32_i64(cc_src, v1); - tcg_gen_mov_i64(cc_dst, v2); - tcg_gen_discard_i64(cc_vr); - s->cc_op = CC_OP_LTGT_F32; -} - -static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1); + gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl); } /* CC value is in env->cc_op */ -static inline void set_cc_static(DisasContext *s) +static void set_cc_static(DisasContext *s) { - tcg_gen_discard_i64(cc_src); - tcg_gen_discard_i64(cc_dst); - tcg_gen_discard_i64(cc_vr); - s->cc_op = CC_OP_STATIC; -} - -static inline void gen_op_set_cc_op(DisasContext *s) -{ - if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { - tcg_gen_movi_i32(cc_op, s->cc_op); + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_dst); + tcg_gen_discard_i64(cc_vr); } -} - -static inline void gen_update_cc_op(DisasContext *s) -{ - gen_op_set_cc_op(s); + s->cc_op = CC_OP_STATIC; } /* calculates cc into cc_op */ static void gen_op_calc_cc(DisasContext *s) { - TCGv_i32 local_cc_op = tcg_const_i32(s->cc_op); - TCGv_i64 dummy = tcg_const_i64(0); + TCGv_i32 local_cc_op; + TCGv_i64 dummy; + + TCGV_UNUSED_I32(local_cc_op); + TCGV_UNUSED_I64(dummy); + switch (s->cc_op) { + default: + dummy = tcg_const_i64(0); + /* FALLTHRU */ + case CC_OP_ADD_64: + case CC_OP_ADDU_64: + case CC_OP_ADDC_64: + case CC_OP_SUB_64: + case CC_OP_SUBU_64: + case CC_OP_SUBB_64: + case CC_OP_ADD_32: + case CC_OP_ADDU_32: + case CC_OP_ADDC_32: + case CC_OP_SUB_32: + case CC_OP_SUBU_32: + case CC_OP_SUBB_32: + local_cc_op = tcg_const_i32(s->cc_op); + break; + case CC_OP_CONST0: + case CC_OP_CONST1: + case CC_OP_CONST2: + case CC_OP_CONST3: + case CC_OP_STATIC: + case CC_OP_DYNAMIC: + break; + } switch (s->cc_op) { case CC_OP_CONST0: @@ -721,6 +494,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_COMP_64: case CC_OP_NZ_F32: case CC_OP_NZ_F64: + case CC_OP_FLOGR: /* 1 argument */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); break; @@ -731,20 +505,24 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_LTUGTU_64: case CC_OP_TM_32: case CC_OP_TM_64: - case CC_OP_LTGT_F32: - case CC_OP_LTGT_F64: - case CC_OP_SLAG: + case CC_OP_SLA_32: + case CC_OP_SLA_64: + case CC_OP_NZ_F128: /* 2 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; case CC_OP_ADD_64: case CC_OP_ADDU_64: + case CC_OP_ADDC_64: case CC_OP_SUB_64: case CC_OP_SUBU_64: + case CC_OP_SUBB_64: case CC_OP_ADD_32: case CC_OP_ADDU_32: + case CC_OP_ADDC_32: case CC_OP_SUB_32: case CC_OP_SUBU_32: + case CC_OP_SUBB_32: /* 3 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); break; @@ -756,4358 +534,4204 @@ static void gen_op_calc_cc(DisasContext *s) tcg_abort(); } - tcg_temp_free_i32(local_cc_op); + if (!TCGV_IS_UNUSED_I32(local_cc_op)) { + tcg_temp_free_i32(local_cc_op); + } + if (!TCGV_IS_UNUSED_I64(dummy)) { + tcg_temp_free_i64(dummy); + } /* We now have cc in cc_op as constant */ set_cc_static(s); } -static inline void decode_rr(DisasContext *s, uint64_t insn, int *r1, int *r2) -{ - debug_insn(insn); - - *r1 = (insn >> 4) & 0xf; - *r2 = insn & 0xf; -} - -static inline TCGv_i64 decode_rx(DisasContext *s, uint64_t insn, int *r1, - int *x2, int *b2, int *d2) +static int use_goto_tb(DisasContext *s, uint64_t dest) { - debug_insn(insn); - - *r1 = (insn >> 20) & 0xf; - *x2 = (insn >> 16) & 0xf; - *b2 = (insn >> 12) & 0xf; - *d2 = insn & 0xfff; - - return get_address(s, *x2, *b2, *d2); -} - -static inline void decode_rs(DisasContext *s, uint64_t insn, int *r1, int *r3, - int *b2, int *d2) -{ - debug_insn(insn); - - *r1 = (insn >> 20) & 0xf; - /* aka m3 */ - *r3 = (insn >> 16) & 0xf; - *b2 = (insn >> 12) & 0xf; - *d2 = insn & 0xfff; -} - -static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2, - int *b1, int *d1) -{ - debug_insn(insn); - - *i2 = (insn >> 16) & 0xff; - *b1 = (insn >> 12) & 0xf; - *d1 = insn & 0xfff; - - return get_address(s, 0, *b1, *d1); -} - -static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc) -{ - TranslationBlock *tb; - - gen_update_cc_op(s); - - tb = s->tb; /* NOTE: we handle the case where the TB spans two pages here */ - if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) || - (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) { - /* jump to same page: we can use a direct jump */ - tcg_gen_goto_tb(tb_num); - tcg_gen_movi_i64(psw_addr, pc); - tcg_gen_exit_tb((tcg_target_long)tb + tb_num); - } else { - /* jump to another page: currently not optimized */ - tcg_gen_movi_i64(psw_addr, pc); - tcg_gen_exit_tb(0); - } + return (((dest & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) + || (dest & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) + && !s->singlestep_enabled + && !(s->tb->cflags & CF_LAST_IO)); } -static inline void account_noninline_branch(DisasContext *s, int cc_op) +static void account_noninline_branch(DisasContext *s, int cc_op) { #ifdef DEBUG_INLINE_BRANCHES inline_branch_miss[cc_op]++; #endif } -static inline void account_inline_branch(DisasContext *s) +static void account_inline_branch(DisasContext *s, int cc_op) { #ifdef DEBUG_INLINE_BRANCHES - inline_branch_hit[s->cc_op]++; + inline_branch_hit[cc_op]++; #endif } -static void gen_jcc(DisasContext *s, uint32_t mask, int skip) +/* Table of mask values to comparison codes, given a comparison as input. + For such, CC=3 should not be possible. */ +static const TCGCond ltgt_cond[16] = { + TCG_COND_NEVER, TCG_COND_NEVER, /* | | | x */ + TCG_COND_GT, TCG_COND_GT, /* | | GT | x */ + TCG_COND_LT, TCG_COND_LT, /* | LT | | x */ + TCG_COND_NE, TCG_COND_NE, /* | LT | GT | x */ + TCG_COND_EQ, TCG_COND_EQ, /* EQ | | | x */ + TCG_COND_GE, TCG_COND_GE, /* EQ | | GT | x */ + TCG_COND_LE, TCG_COND_LE, /* EQ | LT | | x */ + TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | LT | GT | x */ +}; + +/* Table of mask values to comparison codes, given a logic op as input. + For such, only CC=0 and CC=1 should be possible. */ +static const TCGCond nz_cond[16] = { + TCG_COND_NEVER, TCG_COND_NEVER, /* | | x | x */ + TCG_COND_NEVER, TCG_COND_NEVER, + TCG_COND_NE, TCG_COND_NE, /* | NE | x | x */ + TCG_COND_NE, TCG_COND_NE, + TCG_COND_EQ, TCG_COND_EQ, /* EQ | | x | x */ + TCG_COND_EQ, TCG_COND_EQ, + TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | NE | x | x */ + TCG_COND_ALWAYS, TCG_COND_ALWAYS, +}; + +/* Interpret MASK in terms of S->CC_OP, and fill in C with all the + details required to generate a TCG comparison. */ +static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) { - TCGv_i32 tmp, tmp2, r; - TCGv_i64 tmp64; - int old_cc_op; + TCGCond cond; + enum cc_op old_cc_op = s->cc_op; + + if (mask == 15 || mask == 0) { + c->cond = (mask ? TCG_COND_ALWAYS : TCG_COND_NEVER); + c->u.s32.a = cc_op; + c->u.s32.b = cc_op; + c->g1 = c->g2 = true; + c->is_64 = false; + return; + } - switch (s->cc_op) { + /* Find the TCG condition for the mask + cc op. */ + switch (old_cc_op) { case CC_OP_LTGT0_32: - tmp = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_dst); - switch (mask) { - case 0x8 | 0x4: /* dst <= 0 */ - tcg_gen_brcondi_i32(TCG_COND_GT, tmp, 0, skip); - break; - case 0x8 | 0x2: /* dst >= 0 */ - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, skip); - break; - case 0x8: /* dst == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); - break; - case 0x7: /* dst != 0 */ - case 0x6: /* dst != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); - break; - case 0x4: /* dst < 0 */ - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, skip); - break; - case 0x2: /* dst > 0 */ - tcg_gen_brcondi_i32(TCG_COND_LE, tmp, 0, skip); - break; - default: - tcg_temp_free_i32(tmp); - goto do_dynamic; - } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - break; case CC_OP_LTGT0_64: - switch (mask) { - case 0x8 | 0x4: /* dst <= 0 */ - tcg_gen_brcondi_i64(TCG_COND_GT, cc_dst, 0, skip); - break; - case 0x8 | 0x2: /* dst >= 0 */ - tcg_gen_brcondi_i64(TCG_COND_LT, cc_dst, 0, skip); - break; - case 0x8: /* dst == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); - break; - case 0x7: /* dst != 0 */ - case 0x6: /* dst != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); - break; - case 0x4: /* dst < 0 */ - tcg_gen_brcondi_i64(TCG_COND_GE, cc_dst, 0, skip); - break; - case 0x2: /* dst > 0 */ - tcg_gen_brcondi_i64(TCG_COND_LE, cc_dst, 0, skip); - break; - default: + case CC_OP_LTGT_32: + case CC_OP_LTGT_64: + cond = ltgt_cond[mask]; + if (cond == TCG_COND_NEVER) { goto do_dynamic; } - account_inline_branch(s); + account_inline_branch(s, old_cc_op); break; - case CC_OP_LTGT_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i32(TCG_COND_GT, tmp, tmp2, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i32(TCG_COND_LT, tmp, tmp2, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i32(TCG_COND_GE, tmp, tmp2, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i32(TCG_COND_LE, tmp, tmp2, skip); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); + + case CC_OP_LTUGTU_32: + case CC_OP_LTUGTU_64: + cond = tcg_unsigned_cond(ltgt_cond[mask]); + if (cond == TCG_COND_NEVER) { goto do_dynamic; } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); + account_inline_branch(s, old_cc_op); break; - case CC_OP_LTGT_64: - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i64(TCG_COND_GT, cc_src, cc_dst, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i64(TCG_COND_LT, cc_src, cc_dst, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i64(TCG_COND_GE, cc_src, cc_dst, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i64(TCG_COND_LE, cc_src, cc_dst, skip); - break; - default: + + case CC_OP_NZ: + cond = nz_cond[mask]; + if (cond == TCG_COND_NEVER) { goto do_dynamic; } - account_inline_branch(s); + account_inline_branch(s, old_cc_op); break; - case CC_OP_LTUGTU_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); + + case CC_OP_TM_32: + case CC_OP_TM_64: switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i32(TCG_COND_GTU, tmp, tmp2, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i32(TCG_COND_LTU, tmp, tmp2, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip); + case 8: + cond = TCG_COND_EQ; break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i32(TCG_COND_GEU, tmp, tmp2, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i32(TCG_COND_LEU, tmp, tmp2, skip); + case 4 | 2 | 1: + cond = TCG_COND_NE; break; default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); goto do_dynamic; } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); + account_inline_branch(s, old_cc_op); break; - case CC_OP_LTUGTU_64: + + case CC_OP_ICM: switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i64(TCG_COND_GTU, cc_src, cc_dst, skip); + case 8: + cond = TCG_COND_EQ; break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i64(TCG_COND_LTU, cc_src, cc_dst, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i64(TCG_COND_GEU, cc_src, cc_dst, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i64(TCG_COND_LEU, cc_src, cc_dst, skip); + case 4 | 2 | 1: + case 4 | 2: + cond = TCG_COND_NE; break; default: goto do_dynamic; } - account_inline_branch(s); + account_inline_branch(s, old_cc_op); break; - case CC_OP_NZ: - switch (mask) { - /* dst == 0 || dst != 0 */ - case 0x8 | 0x4: - case 0x8 | 0x4 | 0x2: - case 0x8 | 0x4 | 0x2 | 0x1: - case 0x8 | 0x4 | 0x1: - break; - /* dst == 0 */ - case 0x8: - case 0x8 | 0x2: - case 0x8 | 0x2 | 0x1: - case 0x8 | 0x1: - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); + + case CC_OP_FLOGR: + switch (mask & 0xa) { + case 8: /* src == 0 -> no one bit found */ + cond = TCG_COND_EQ; break; - /* dst != 0 */ - case 0x4: - case 0x4 | 0x2: - case 0x4 | 0x2 | 0x1: - case 0x4 | 0x1: - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); + case 2: /* src != 0 -> one bit found */ + cond = TCG_COND_NE; break; default: goto do_dynamic; } - account_inline_branch(s); + account_inline_branch(s, old_cc_op); break; - case CC_OP_TM_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); - tcg_gen_and_i32(tmp, tmp, tmp2); + case CC_OP_ADDU_32: + case CC_OP_ADDU_64: switch (mask) { - case 0x8: /* val & mask == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); + case 8 | 2: /* vr == 0 */ + cond = TCG_COND_EQ; + break; + case 4 | 1: /* vr != 0 */ + cond = TCG_COND_NE; break; - case 0x4 | 0x2 | 0x1: /* val & mask != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); + case 8 | 4: /* no carry -> vr >= src */ + cond = TCG_COND_GEU; + break; + case 2 | 1: /* carry -> vr < src */ + cond = TCG_COND_LTU; break; default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); goto do_dynamic; } - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - account_inline_branch(s); + account_inline_branch(s, old_cc_op); break; - case CC_OP_TM_64: - tmp64 = tcg_temp_new_i64(); - tcg_gen_and_i64(tmp64, cc_src, cc_dst); - switch (mask) { - case 0x8: /* val & mask == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, tmp64, 0, skip); + case CC_OP_SUBU_32: + case CC_OP_SUBU_64: + /* Note that CC=0 is impossible; treat it as dont-care. */ + switch (mask & 7) { + case 2: /* zero -> op1 == op2 */ + cond = TCG_COND_EQ; break; - case 0x4 | 0x2 | 0x1: /* val & mask != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, tmp64, 0, skip); + case 4 | 1: /* !zero -> op1 != op2 */ + cond = TCG_COND_NE; break; - default: - tcg_temp_free_i64(tmp64); - goto do_dynamic; - } - tcg_temp_free_i64(tmp64); - account_inline_branch(s); - break; - case CC_OP_ICM: - switch (mask) { - case 0x8: /* val == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); + case 4: /* borrow (!carry) -> op1 < op2 */ + cond = TCG_COND_LTU; break; - case 0x4 | 0x2 | 0x1: /* val != 0 */ - case 0x4 | 0x2: /* val != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); + case 2 | 1: /* !borrow (carry) -> op1 >= op2 */ + cond = TCG_COND_GEU; break; default: goto do_dynamic; } - account_inline_branch(s); + account_inline_branch(s, old_cc_op); break; - case CC_OP_STATIC: - old_cc_op = s->cc_op; - goto do_dynamic_nocccalc; - case CC_OP_DYNAMIC: + default: -do_dynamic: - old_cc_op = s->cc_op; - /* calculate cc value */ + do_dynamic: + /* Calculate cc value. */ gen_op_calc_cc(s); + /* FALLTHRU */ -do_dynamic_nocccalc: - /* jump based on cc */ + case CC_OP_STATIC: + /* Jump based on CC. We'll load up the real cond below; + the assignment here merely avoids a compiler warning. */ account_noninline_branch(s, old_cc_op); + old_cc_op = CC_OP_STATIC; + cond = TCG_COND_NEVER; + break; + } + + /* Load up the arguments of the comparison. */ + c->is_64 = true; + c->g1 = c->g2 = false; + switch (old_cc_op) { + case CC_OP_LTGT0_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_dst); + c->u.s32.b = tcg_const_i32(0); + break; + case CC_OP_LTGT_32: + case CC_OP_LTUGTU_32: + case CC_OP_SUBU_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_src); + c->u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.b, cc_dst); + break; + + case CC_OP_LTGT0_64: + case CC_OP_NZ: + case CC_OP_FLOGR: + c->u.s64.a = cc_dst; + c->u.s64.b = tcg_const_i64(0); + c->g1 = true; + break; + case CC_OP_LTGT_64: + case CC_OP_LTUGTU_64: + case CC_OP_SUBU_64: + c->u.s64.a = cc_src; + c->u.s64.b = cc_dst; + c->g1 = c->g2 = true; + break; + case CC_OP_TM_32: + case CC_OP_TM_64: + case CC_OP_ICM: + c->u.s64.a = tcg_temp_new_i64(); + c->u.s64.b = tcg_const_i64(0); + tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); + break; + + case CC_OP_ADDU_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_vr); + if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { + tcg_gen_movi_i32(c->u.s32.b, 0); + } else { + tcg_gen_trunc_i64_i32(c->u.s32.b, cc_src); + } + break; + + case CC_OP_ADDU_64: + c->u.s64.a = cc_vr; + c->g1 = true; + if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { + c->u.s64.b = tcg_const_i64(0); + } else { + c->u.s64.b = cc_src; + c->g2 = true; + } + break; + + case CC_OP_STATIC: + c->is_64 = false; + c->u.s32.a = cc_op; + c->g1 = true; switch (mask) { - case 0x8 | 0x4 | 0x2 | 0x1: - /* always true */ - break; case 0x8 | 0x4 | 0x2: /* cc != 3 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 3, skip); + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(3); break; case 0x8 | 0x4 | 0x1: /* cc != 2 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 2, skip); + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(2); break; case 0x8 | 0x2 | 0x1: /* cc != 1 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 1, skip); + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(1); break; - case 0x8 | 0x2: /* cc == 0 || cc == 2 */ - tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cc_op, 1); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); - tcg_temp_free_i32(tmp); + case 0x8 | 0x2: /* cc == 0 || cc == 2 => (cc & 1) == 0 */ + cond = TCG_COND_EQ; + c->g1 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_andi_i32(c->u.s32.a, cc_op, 1); break; case 0x8 | 0x4: /* cc < 2 */ - tcg_gen_brcondi_i32(TCG_COND_GEU, cc_op, 2, skip); + cond = TCG_COND_LTU; + c->u.s32.b = tcg_const_i32(2); break; case 0x8: /* cc == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 0, skip); + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(0); break; case 0x4 | 0x2 | 0x1: /* cc != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 0, skip); + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(0); break; - case 0x4 | 0x1: /* cc == 1 || cc == 3 */ - tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cc_op, 1); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); - tcg_temp_free_i32(tmp); + case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */ + cond = TCG_COND_NE; + c->g1 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_andi_i32(c->u.s32.a, cc_op, 1); break; case 0x4: /* cc == 1 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 1, skip); + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(1); break; case 0x2 | 0x1: /* cc > 1 */ - tcg_gen_brcondi_i32(TCG_COND_LEU, cc_op, 1, skip); + cond = TCG_COND_GTU; + c->u.s32.b = tcg_const_i32(1); break; case 0x2: /* cc == 2 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 2, skip); + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(2); break; case 0x1: /* cc == 3 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 3, skip); + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(3); break; - default: /* cc is masked by something else */ - tmp = tcg_const_i32(3); - /* 3 - cc */ - tcg_gen_sub_i32(tmp, tmp, cc_op); - tmp2 = tcg_const_i32(1); - /* 1 << (3 - cc) */ - tcg_gen_shl_i32(tmp2, tmp2, tmp); - r = tcg_const_i32(mask); - /* mask & (1 << (3 - cc)) */ - tcg_gen_and_i32(r, r, tmp2); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - - tcg_gen_brcondi_i32(TCG_COND_EQ, r, 0, skip); - tcg_temp_free_i32(r); + default: + /* CC is masked by something else: (8 >> cc) & mask. */ + cond = TCG_COND_NE; + c->g1 = false; + c->u.s32.a = tcg_const_i32(8); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_shr_i32(c->u.s32.a, c->u.s32.a, cc_op); + tcg_gen_andi_i32(c->u.s32.a, c->u.s32.a, mask); break; } break; + + default: + abort(); } + c->cond = cond; } -static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, - uint64_t offset) +static void free_compare(DisasCompare *c) { - int skip; - - if (mask == 0xf) { - /* unconditional */ - tcg_gen_mov_i64(psw_addr, target); - tcg_gen_exit_tb(0); - } else if (mask == 0) { - /* ignore cc and never match */ - gen_goto_tb(s, 0, offset + 2); - } else { - TCGv_i64 new_addr = tcg_temp_local_new_i64(); - - tcg_gen_mov_i64(new_addr, target); - skip = gen_new_label(); - gen_jcc(s, mask, skip); - tcg_gen_mov_i64(psw_addr, new_addr); - tcg_temp_free_i64(new_addr); - tcg_gen_exit_tb(0); - gen_set_label(skip); - tcg_temp_free_i64(new_addr); - gen_goto_tb(s, 1, offset + 2); + if (!c->g1) { + if (c->is_64) { + tcg_temp_free_i64(c->u.s64.a); + } else { + tcg_temp_free_i32(c->u.s32.a); + } + } + if (!c->g2) { + if (c->is_64) { + tcg_temp_free_i64(c->u.s64.b); + } else { + tcg_temp_free_i32(c->u.s32.b); + } } } -static void gen_brc(uint32_t mask, DisasContext *s, int32_t offset) +/* ====================================================================== */ +/* Define the insn format enumeration. */ +#define F0(N) FMT_##N, +#define F1(N, X1) F0(N) +#define F2(N, X1, X2) F0(N) +#define F3(N, X1, X2, X3) F0(N) +#define F4(N, X1, X2, X3, X4) F0(N) +#define F5(N, X1, X2, X3, X4, X5) F0(N) + +typedef enum { +#include "insn-format.def" +} DisasFormat; + +#undef F0 +#undef F1 +#undef F2 +#undef F3 +#undef F4 +#undef F5 + +/* Define a structure to hold the decoded fields. We'll store each inside + an array indexed by an enum. In order to conserve memory, we'll arrange + for fields that do not exist at the same time to overlap, thus the "C" + for compact. For checking purposes there is an "O" for original index + as well that will be applied to availability bitmaps. */ + +enum DisasFieldIndexO { + FLD_O_r1, + FLD_O_r2, + FLD_O_r3, + FLD_O_m1, + FLD_O_m3, + FLD_O_m4, + FLD_O_b1, + FLD_O_b2, + FLD_O_b4, + FLD_O_d1, + FLD_O_d2, + FLD_O_d4, + FLD_O_x2, + FLD_O_l1, + FLD_O_l2, + FLD_O_i1, + FLD_O_i2, + FLD_O_i3, + FLD_O_i4, + FLD_O_i5 +}; + +enum DisasFieldIndexC { + FLD_C_r1 = 0, + FLD_C_m1 = 0, + FLD_C_b1 = 0, + FLD_C_i1 = 0, + + FLD_C_r2 = 1, + FLD_C_b2 = 1, + FLD_C_i2 = 1, + + FLD_C_r3 = 2, + FLD_C_m3 = 2, + FLD_C_i3 = 2, + + FLD_C_m4 = 3, + FLD_C_b4 = 3, + FLD_C_i4 = 3, + FLD_C_l1 = 3, + + FLD_C_i5 = 4, + FLD_C_d1 = 4, + + FLD_C_d2 = 5, + + FLD_C_d4 = 6, + FLD_C_x2 = 6, + FLD_C_l2 = 6, + + NUM_C_FIELD = 7 +}; + +struct DisasFields { + unsigned op:8; + unsigned op2:8; + unsigned presentC:16; + unsigned int presentO; + int c[NUM_C_FIELD]; +}; + +/* This is the way fields are to be accessed out of DisasFields. */ +#define have_field(S, F) have_field1((S), FLD_O_##F) +#define get_field(S, F) get_field1((S), FLD_O_##F, FLD_C_##F) + +static bool have_field1(const DisasFields *f, enum DisasFieldIndexO c) +{ + return (f->presentO >> c) & 1; +} + +static int get_field1(const DisasFields *f, enum DisasFieldIndexO o, + enum DisasFieldIndexC c) +{ + assert(have_field1(f, o)); + return f->c[c]; +} + +/* Describe the layout of each field in each format. */ +typedef struct DisasField { + unsigned int beg:8; + unsigned int size:8; + unsigned int type:2; + unsigned int indexC:6; + enum DisasFieldIndexO indexO:8; +} DisasField; + +typedef struct DisasFormatInfo { + DisasField op[NUM_C_FIELD]; +} DisasFormatInfo; + +#define R(N, B) { B, 4, 0, FLD_C_r##N, FLD_O_r##N } +#define M(N, B) { B, 4, 0, FLD_C_m##N, FLD_O_m##N } +#define BD(N, BB, BD) { BB, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { BD, 12, 0, FLD_C_d##N, FLD_O_d##N } +#define BXD(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 12, 4, 0, FLD_C_x##N, FLD_O_x##N }, \ + { 20, 12, 0, FLD_C_d##N, FLD_O_d##N } +#define BDL(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 20, 20, 2, FLD_C_d##N, FLD_O_d##N } +#define BXDL(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 12, 4, 0, FLD_C_x##N, FLD_O_x##N }, \ + { 20, 20, 2, FLD_C_d##N, FLD_O_d##N } +#define I(N, B, S) { B, S, 1, FLD_C_i##N, FLD_O_i##N } +#define L(N, B, S) { B, S, 0, FLD_C_l##N, FLD_O_l##N } + +#define F0(N) { { } }, +#define F1(N, X1) { { X1 } }, +#define F2(N, X1, X2) { { X1, X2 } }, +#define F3(N, X1, X2, X3) { { X1, X2, X3 } }, +#define F4(N, X1, X2, X3, X4) { { X1, X2, X3, X4 } }, +#define F5(N, X1, X2, X3, X4, X5) { { X1, X2, X3, X4, X5 } }, + +static const DisasFormatInfo format_info[] = { +#include "insn-format.def" +}; + +#undef F0 +#undef F1 +#undef F2 +#undef F3 +#undef F4 +#undef F5 +#undef R +#undef M +#undef BD +#undef BXD +#undef BDL +#undef BXDL +#undef I +#undef L + +/* Generally, we'll extract operands into this structures, operate upon + them, and store them back. See the "in1", "in2", "prep", "wout" sets + of routines below for more details. */ +typedef struct { + bool g_out, g_out2, g_in1, g_in2; + TCGv_i64 out, out2, in1, in2; + TCGv_i64 addr1; +} DisasOps; + +/* Instructions can place constraints on their operands, raising specification + exceptions if they are violated. To make this easy to automate, each "in1", + "in2", "prep", "wout" helper will have a SPEC_<name> define that equals one + of the following, or 0. To make this easy to document, we'll put the + SPEC_<name> defines next to <name>. */ + +#define SPEC_r1_even 1 +#define SPEC_r2_even 2 +#define SPEC_r3_even 4 +#define SPEC_r1_f128 8 +#define SPEC_r2_f128 16 + +/* Return values from translate_one, indicating the state of the TB. */ +typedef enum { + /* Continue the TB. */ + NO_EXIT, + /* We have emitted one or more goto_tb. No fixup required. */ + EXIT_GOTO_TB, + /* We are not using a goto_tb (for whatever reason), but have updated + the PC (for whatever reason), so there's no need to do it again on + exiting the TB. */ + EXIT_PC_UPDATED, + /* We are exiting the TB, but have neither emitted a goto_tb, nor + updated the PC for the next instruction to be executed. */ + EXIT_PC_STALE, + /* We are ending the TB with a noreturn function call, e.g. longjmp. + No following code will be executed. */ + EXIT_NORETURN, +} ExitStatus; + +typedef enum DisasFacility { + FAC_Z, /* zarch (default) */ + FAC_CASS, /* compare and swap and store */ + FAC_CASS2, /* compare and swap and store 2*/ + FAC_DFP, /* decimal floating point */ + FAC_DFPR, /* decimal floating point rounding */ + FAC_DO, /* distinct operands */ + FAC_EE, /* execute extensions */ + FAC_EI, /* extended immediate */ + FAC_FPE, /* floating point extension */ + FAC_FPSSH, /* floating point support sign handling */ + FAC_FPRGR, /* FPR-GR transfer */ + FAC_GIE, /* general instructions extension */ + FAC_HFP_MA, /* HFP multiply-and-add/subtract */ + FAC_HW, /* high-word */ + FAC_IEEEE_SIM, /* IEEE exception sumilation */ + FAC_LOC, /* load/store on condition */ + FAC_LD, /* long displacement */ + FAC_PC, /* population count */ + FAC_SCF, /* store clock fast */ + FAC_SFLE, /* store facility list extended */ +} DisasFacility; + +struct DisasInsn { + unsigned opc:16; + DisasFormat fmt:8; + DisasFacility fac:8; + unsigned spec:8; + + const char *name; + + void (*help_in1)(DisasContext *, DisasFields *, DisasOps *); + void (*help_in2)(DisasContext *, DisasFields *, DisasOps *); + void (*help_prep)(DisasContext *, DisasFields *, DisasOps *); + void (*help_wout)(DisasContext *, DisasFields *, DisasOps *); + void (*help_cout)(DisasContext *, DisasOps *); + ExitStatus (*help_op)(DisasContext *, DisasOps *); + + uint64_t data; +}; + +/* ====================================================================== */ +/* Miscelaneous helpers, used by several operations. */ + +static void help_l2_shift(DisasContext *s, DisasFields *f, + DisasOps *o, int mask) { - int skip; + int b2 = get_field(f, b2); + int d2 = get_field(f, d2); - if (mask == 0xf) { - /* unconditional */ - gen_goto_tb(s, 0, s->pc + offset); - } else if (mask == 0) { - /* ignore cc and never match */ - gen_goto_tb(s, 0, s->pc + 4); + if (b2 == 0) { + o->in2 = tcg_const_i64(d2 & mask); } else { - skip = gen_new_label(); - gen_jcc(s, mask, skip); - gen_goto_tb(s, 0, s->pc + offset); - gen_set_label(skip); - gen_goto_tb(s, 1, s->pc + 4); + o->in2 = get_address(s, 0, b2, d2); + tcg_gen_andi_i64(o->in2, o->in2, mask); } - s->is_jmp = DISAS_TB_JUMP; } -static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) +static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) { - TCGv_i64 tmp, tmp2; - int i; - int l_memset = gen_new_label(); - int l_out = gen_new_label(); - TCGv_i64 dest = tcg_temp_local_new_i64(); - TCGv_i64 src = tcg_temp_local_new_i64(); - TCGv_i32 vl; + if (dest == s->next_pc) { + return NO_EXIT; + } + if (use_goto_tb(s, dest)) { + update_cc_op(s); + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, dest); + tcg_gen_exit_tb((tcg_target_long)s->tb); + return EXIT_GOTO_TB; + } else { + tcg_gen_movi_i64(psw_addr, dest); + return EXIT_PC_UPDATED; + } +} - /* Find out if we should use the inline version of mvc */ - switch (l) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 11: - case 15: - /* use inline */ - break; - default: - /* Fall back to helper */ - vl = tcg_const_i32(l); - potential_page_fault(s); - gen_helper_mvc(cpu_env, vl, s1, s2); - tcg_temp_free_i32(vl); - return; +static ExitStatus help_branch(DisasContext *s, DisasCompare *c, + bool is_imm, int imm, TCGv_i64 cdest) +{ + ExitStatus ret; + uint64_t dest = s->pc + 2 * imm; + int lab; + + /* Take care of the special cases first. */ + if (c->cond == TCG_COND_NEVER) { + ret = NO_EXIT; + goto egress; + } + if (is_imm) { + if (dest == s->next_pc) { + /* Branch to next. */ + ret = NO_EXIT; + goto egress; + } + if (c->cond == TCG_COND_ALWAYS) { + ret = help_goto_direct(s, dest); + goto egress; + } + } else { + if (TCGV_IS_UNUSED_I64(cdest)) { + /* E.g. bcr %r0 -> no branch. */ + ret = NO_EXIT; + goto egress; + } + if (c->cond == TCG_COND_ALWAYS) { + tcg_gen_mov_i64(psw_addr, cdest); + ret = EXIT_PC_UPDATED; + goto egress; + } } - tcg_gen_mov_i64(dest, s1); - tcg_gen_mov_i64(src, s2); + if (use_goto_tb(s, s->next_pc)) { + if (is_imm && use_goto_tb(s, dest)) { + /* Both exits can use goto_tb. */ + update_cc_op(s); - if (!(s->tb->flags & FLAG_MASK_64)) { - /* XXX what if we overflow while moving? */ - tcg_gen_andi_i64(dest, dest, 0x7fffffffUL); - tcg_gen_andi_i64(src, src, 0x7fffffffUL); + lab = gen_new_label(); + if (c->is_64) { + tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab); + } + + /* Branch not taken. */ + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, s->next_pc); + tcg_gen_exit_tb((tcg_target_long)s->tb + 0); + + /* Branch taken. */ + gen_set_label(lab); + tcg_gen_goto_tb(1); + tcg_gen_movi_i64(psw_addr, dest); + tcg_gen_exit_tb((tcg_target_long)s->tb + 1); + + ret = EXIT_GOTO_TB; + } else { + /* Fallthru can use goto_tb, but taken branch cannot. */ + /* Store taken branch destination before the brcond. This + avoids having to allocate a new local temp to hold it. + We'll overwrite this in the not taken case anyway. */ + if (!is_imm) { + tcg_gen_mov_i64(psw_addr, cdest); + } + + lab = gen_new_label(); + if (c->is_64) { + tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab); + } + + /* Branch not taken. */ + update_cc_op(s); + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, s->next_pc); + tcg_gen_exit_tb((tcg_target_long)s->tb + 0); + + gen_set_label(lab); + if (is_imm) { + tcg_gen_movi_i64(psw_addr, dest); + } + ret = EXIT_PC_UPDATED; + } + } else { + /* Fallthru cannot use goto_tb. This by itself is vanishingly rare. + Most commonly we're single-stepping or some other condition that + disables all use of goto_tb. Just update the PC and exit. */ + + TCGv_i64 next = tcg_const_i64(s->next_pc); + if (is_imm) { + cdest = tcg_const_i64(dest); + } + + if (c->is_64) { + tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b, + cdest, next); + } else { + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 z = tcg_const_i64(0); + tcg_gen_setcond_i32(c->cond, t0, c->u.s32.a, c->u.s32.b); + tcg_gen_extu_i32_i64(t1, t0); + tcg_temp_free_i32(t0); + tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(z); + } + + if (is_imm) { + tcg_temp_free_i64(cdest); + } + tcg_temp_free_i64(next); + + ret = EXIT_PC_UPDATED; } - tmp = tcg_temp_new_i64(); - tcg_gen_addi_i64(tmp, src, 1); - tcg_gen_brcond_i64(TCG_COND_EQ, dest, tmp, l_memset); - tcg_temp_free_i64(tmp); + egress: + free_compare(c); + return ret; +} - switch (l) { - case 0: - tmp = tcg_temp_new_i64(); +/* ====================================================================== */ +/* The operations. These perform the bulk of the work for any insn, + usually after the operands have been loaded and output initialized. */ - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); +static ExitStatus op_abs(DisasContext *s, DisasOps *o) +{ + gen_helper_abs_i64(o->out, o->in2); + return NO_EXIT; +} - tcg_temp_free_i64(tmp); - break; - case 1: - tmp = tcg_temp_new_i64(); +static ExitStatus op_absf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffull); + return NO_EXIT; +} - tcg_gen_qemu_ld16u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st16(tmp, dest, get_mem_index(s)); +static ExitStatus op_absf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull); + return NO_EXIT; +} - tcg_temp_free_i64(tmp); - break; - case 3: - tmp = tcg_temp_new_i64(); +static ExitStatus op_absf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in1, 0x7fffffffffffffffull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} - tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st32(tmp, dest, get_mem_index(s)); +static ExitStatus op_add(DisasContext *s, DisasOps *o) +{ + tcg_gen_add_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} - tcg_temp_free_i64(tmp); - break; - case 4: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s)); - tcg_gen_addi_i64(src, src, 4); - tcg_gen_qemu_ld8u(tmp2, src, get_mem_index(s)); - tcg_gen_qemu_st32(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 4); - tcg_gen_qemu_st8(tmp2, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 7: - tmp = tcg_temp_new_i64(); +static ExitStatus op_addc(DisasContext *s, DisasOps *o) +{ + DisasCompare cmp; + TCGv_i64 carry; + + tcg_gen_add_i64(o->out, o->in1, o->in2); + + /* The carry flag is the msb of CC, therefore the branch mask that would + create that comparison is 3. Feeding the generated comparison to + setcond produces the carry flag that we desire. */ + disas_jcc(s, &cmp, 3); + carry = tcg_temp_new_i64(); + if (cmp.is_64) { + tcg_gen_setcond_i64(cmp.cond, carry, cmp.u.s64.a, cmp.u.s64.b); + } else { + TCGv_i32 t = tcg_temp_new_i32(); + tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b); + tcg_gen_extu_i32_i64(carry, t); + tcg_temp_free_i32(t); + } + free_compare(&cmp); - tcg_gen_qemu_ld64(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); + tcg_gen_add_i64(o->out, o->out, carry); + tcg_temp_free_i64(carry); + return NO_EXIT; +} - tcg_temp_free_i64(tmp); - break; - default: - /* The inline version can become too big for too uneven numbers, only - use it on known good lengths */ - tmp = tcg_temp_new_i64(); - tmp2 = tcg_const_i64(8); - for (i = 0; (i + 7) <= l; i += 8) { - tcg_gen_qemu_ld64(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); - - tcg_gen_add_i64(src, src, tmp2); - tcg_gen_add_i64(dest, dest, tmp2); - } +static ExitStatus op_aeb(DisasContext *s, DisasOps *o) +{ + gen_helper_aeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} - tcg_temp_free_i64(tmp2); - tmp2 = tcg_const_i64(1); +static ExitStatus op_adb(DisasContext *s, DisasOps *o) +{ + gen_helper_adb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} - for (; i <= l; i++) { - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); +static ExitStatus op_axb(DisasContext *s, DisasOps *o) +{ + gen_helper_axb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} - tcg_gen_add_i64(src, src, tmp2); - tcg_gen_add_i64(dest, dest, tmp2); - } +static ExitStatus op_and(DisasContext *s, DisasOps *o) +{ + tcg_gen_and_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; +static ExitStatus op_andi(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_ori_i64(o->in2, o->in2, ~mask); + tcg_gen_and_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + +static ExitStatus op_bas(DisasContext *s, DisasOps *o) +{ + tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); + if (!TCGV_IS_UNUSED_I64(o->in2)) { + tcg_gen_mov_i64(psw_addr, o->in2); + return EXIT_PC_UPDATED; + } else { + return NO_EXIT; } +} - tcg_gen_br(l_out); +static ExitStatus op_basi(DisasContext *s, DisasOps *o) +{ + tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); + return help_goto_direct(s, s->pc + 2 * get_field(s->fields, i2)); +} - gen_set_label(l_memset); - /* memset case (dest == (src + 1)) */ +static ExitStatus op_bc(DisasContext *s, DisasOps *o) +{ + int m1 = get_field(s->fields, m1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + disas_jcc(s, &c, m1); + return help_branch(s, &c, is_imm, imm, o->in2); +} + +static ExitStatus op_bct32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + TCGv_i64 t; + + c.cond = TCG_COND_NE; + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_subi_i64(t, regs[r1], 1); + store_reg32_i64(r1, t); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_const_i32(0); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + +static ExitStatus op_bct64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + c.cond = TCG_COND_NE; + c.is_64 = true; + c.g1 = true; + c.g2 = false; - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - /* fill tmp with the byte */ - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_shli_i64(tmp2, tmp, 8); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_gen_shli_i64(tmp2, tmp, 16); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_gen_shli_i64(tmp2, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_temp_free_i64(tmp2); + tcg_gen_subi_i64(regs[r1], regs[r1], 1); + c.u.s64.a = regs[r1]; + c.u.s64.b = tcg_const_i64(0); - tmp2 = tcg_const_i64(8); + return help_branch(s, &c, is_imm, imm, o->in2); +} - for (i = 0; (i + 7) <= l; i += 8) { - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 8); +static ExitStatus op_bx32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + TCGv_i64 t; + + c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT); + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_add_i64(t, regs[r1], regs[r3]); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_gen_trunc_i64_i32(c.u.s32.b, regs[r3 | 1]); + store_reg32_i64(r1, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + +static ExitStatus op_bx64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT); + c.is_64 = true; + + if (r1 == (r3 | 1)) { + c.u.s64.b = load_reg(r3 | 1); + c.g2 = false; + } else { + c.u.s64.b = regs[r3 | 1]; + c.g2 = true; } - tcg_temp_free_i64(tmp2); - tmp2 = tcg_const_i64(1); + tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]); + c.u.s64.a = regs[r1]; + c.g1 = true; + + return help_branch(s, &c, is_imm, imm, o->in2); +} - for (; i <= l; i++) { - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 1); +static ExitStatus op_cj(DisasContext *s, DisasOps *o) +{ + int imm, m3 = get_field(s->fields, m3); + bool is_imm; + DisasCompare c; + + c.cond = ltgt_cond[m3]; + if (s->insn->data) { + c.cond = tcg_unsigned_cond(c.cond); } + c.is_64 = c.g1 = c.g2 = true; + c.u.s64.a = o->in1; + c.u.s64.b = o->in2; - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); + is_imm = have_field(s->fields, i4); + if (is_imm) { + imm = get_field(s->fields, i4); + } else { + imm = 0; + o->out = get_address(s, 0, get_field(s->fields, b4), + get_field(s->fields, d4)); + } - gen_set_label(l_out); + return help_branch(s, &c, is_imm, imm, o->out); +} - tcg_temp_free(dest); - tcg_temp_free(src); +static ExitStatus op_ceb(DisasContext *s, DisasOps *o) +{ + gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; } -static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) +static ExitStatus op_cdb(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp; - TCGv_i64 tmp2; - TCGv_i32 vl; + gen_helper_cdb(cc_op, cpu_env, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} - /* check for simple 32bit or 64bit match */ - switch (l) { - case 0: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); +static ExitStatus op_cxb(DisasContext *s, DisasOps *o) +{ + gen_helper_cxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} - tcg_gen_qemu_ld8u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld8u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); +static ExitStatus op_cfeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 1: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); +static ExitStatus op_cfdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} - tcg_gen_qemu_ld16u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld16u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); +static ExitStatus op_cfxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 3: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); +static ExitStatus op_cgeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} - tcg_gen_qemu_ld32u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld32u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); +static ExitStatus op_cgdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 7: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); +static ExitStatus op_cgxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} - tcg_gen_qemu_ld64(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld64(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); +static ExitStatus op_clfeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - } +static ExitStatus op_clfdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clfxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cegb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cegb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cdgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cdgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cxgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cxgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_celgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_celgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cdlgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cdlgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cxlgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cxlgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_cksm(DisasContext *s, DisasOps *o) +{ + int r2 = get_field(s->fields, r2); + TCGv_i64 len = tcg_temp_new_i64(); potential_page_fault(s); - vl = tcg_const_i32(l); - gen_helper_clc(cc_op, cpu_env, vl, s1, s2); - tcg_temp_free_i32(vl); + gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]); set_cc_static(s); + return_low128(o->out); + + tcg_gen_add_i64(regs[r2], regs[r2], len); + tcg_gen_sub_i64(regs[r2 + 1], regs[r2 + 1], len); + tcg_temp_free_i64(len); + + return NO_EXIT; } -static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, - int x2, int b2, int d2) +static ExitStatus op_clc(DisasContext *s, DisasOps *o) { - TCGv_i64 addr, tmp, tmp2, tmp3, tmp4; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + int l = get_field(s->fields, l1); + TCGv_i32 vl; - LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", - op, r1, x2, b2, d2); - addr = get_address(s, x2, b2, d2); - switch (op) { - case 0x2: /* LTG R1,D2(X2,B2) [RXY] */ - case 0x4: /* lg r1,d2(x2,b2) */ - tcg_gen_qemu_ld64(regs[r1], addr, get_mem_index(s)); - if (op == 0x2) { - set_cc_s64(s, regs[r1]); - } - break; - case 0x12: /* LT R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_reg32(r1, tmp32_1); - set_cc_s32(s, tmp32_1); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0xc: /* MSG R1,D2(X2,B2) [RXY] */ - case 0x1c: /* MSGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0xc) { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } - tcg_gen_mul_i64(regs[r1], regs[r1], tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ - case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0x1d) { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1 + 1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_div_i64(tmp3, tmp4, tmp2); - store_reg(r1 + 1, tmp3); - tcg_gen_rem_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; - case 0x8: /* AG R1,D2(X2,B2) [RXY] */ - case 0xa: /* ALG R1,D2(X2,B2) [RXY] */ - case 0x18: /* AGF R1,D2(X2,B2) [RXY] */ - case 0x1a: /* ALGF R1,D2(X2,B2) [RXY] */ - if (op == 0x1a) { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - } else if (op == 0x18) { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x8: - case 0x18: - set_cc_add64(s, tmp4, tmp2, tmp3); - break; - case 0xa: - case 0x1a: - set_cc_addu64(s, tmp4, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; - case 0x9: /* SG R1,D2(X2,B2) [RXY] */ - case 0xb: /* SLG R1,D2(X2,B2) [RXY] */ - case 0x19: /* SGF R1,D2(X2,B2) [RXY] */ - case 0x1b: /* SLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0x19) { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else if (op == 0x1b) { - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_sub_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x9: - case 0x19: - set_cc_sub64(s, tmp4, tmp2, tmp3); - break; - case 0xb: - case 0x1b: - set_cc_subu64(s, tmp4, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; - case 0xf: /* LRVG R1,D2(X2,B2) [RXE] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - tcg_gen_bswap64_i64(tmp2, tmp2); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x14: /* LGF R1,D2(X2,B2) [RXY] */ - case 0x16: /* LLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - if (op == 0x14) { - tcg_gen_ext32s_i64(tmp2, tmp2); - } - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s)); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x1f: /* LRVH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_bswap16_i32(tmp32_1, tmp32_1); - store_reg16(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x20: /* CG R1,D2(X2,B2) [RXY] */ - case 0x21: /* CLG R1,D2(X2,B2) */ - case 0x30: /* CGF R1,D2(X2,B2) [RXY] */ - case 0x31: /* CLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - switch (op) { - case 0x20: - case 0x21: - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - break; - case 0x30: - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - break; - case 0x31: - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - break; - default: - tcg_abort(); - } - switch (op) { - case 0x20: - case 0x30: - cmp_s64(s, regs[r1], tmp2); - break; - case 0x21: - case 0x31: - cmp_u64(s, regs[r1], tmp2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - break; - case 0x24: /* stg r1, d2(x2,b2) */ - tcg_gen_qemu_st64(regs[r1], addr, get_mem_index(s)); - break; - case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; - case 0x50: /* STY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; - case 0x57: /* XY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_xor_i32(tmp32_2, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_2); - set_cc_nz_u32(s, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x58: /* LY R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp3, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp3); - break; - case 0x5a: /* AY R1,D2(X2,B2) [RXY] */ - case 0x5b: /* SY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_temp_free_i64(tmp2); - switch (op) { - case 0x5a: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - break; - case 0x5b: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - switch (op) { - case 0x5a: - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5b: - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ - store_reg(r1, addr); - break; - case 0x72: /* STCY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st8(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp2); - break; - case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp3, addr, get_mem_index(s)); - store_reg8(r1, tmp3); - tcg_temp_free_i64(tmp3); - break; - case 0x76: /* LB R1,D2(X2,B2) [RXY] */ - case 0x77: /* LGB R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8s(tmp2, addr, get_mem_index(s)); - switch (op) { - case 0x76: - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg32_i64(r1, tmp2); - break; - case 0x77: - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg(r1, tmp2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - break; - case 0x78: /* LHY R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x80: /* NG R1,D2(X2,B2) [RXY] */ - case 0x81: /* OG R1,D2(X2,B2) [RXY] */ - case 0x82: /* XG R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp3, addr, get_mem_index(s)); - switch (op) { - case 0x80: - tcg_gen_and_i64(regs[r1], regs[r1], tmp3); - break; - case 0x81: - tcg_gen_or_i64(regs[r1], regs[r1], tmp3); - break; - case 0x82: - tcg_gen_xor_i64(regs[r1], regs[r1], tmp3); - break; - default: - tcg_abort(); - } - set_cc_nz_u64(s, regs[r1]); - tcg_temp_free_i64(tmp3); - break; - case 0x86: /* MLG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_mlg(cpu_env, tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_dlg(cpu_env, tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x88: /* ALCG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - tcg_gen_extu_i32_i64(tmp3, cc_op); - tcg_gen_shri_i64(tmp3, tmp3, 1); - tcg_gen_andi_i64(tmp3, tmp3, 1); - tcg_gen_add_i64(tmp3, tmp2, tmp3); - tcg_gen_add_i64(tmp3, regs[r1], tmp3); - store_reg(r1, tmp3); - set_cc_addu64(s, regs[r1], tmp2, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x89: /* SLBG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, regs[r1], tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x90: /* LLGC R1,D2(X2,B2) [RXY] */ - tcg_gen_qemu_ld8u(regs[r1], addr, get_mem_index(s)); - break; - case 0x91: /* LLGH R1,D2(X2,B2) [RXY] */ - tcg_gen_qemu_ld16u(regs[r1], addr, get_mem_index(s)); - break; - case 0x94: /* LLC R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x95: /* LLH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x96: /* ML R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); + switch (l + 1) { + case 1: + tcg_gen_qemu_ld8u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld8u(cc_dst, o->in2, get_mem_index(s)); break; - case 0x97: /* DL R1,D2(X2,B2) [RXY] */ - /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ - /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ - tmp = load_reg(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp3); - - tcg_gen_rem_i64(tmp3, tmp, tmp2); - tcg_gen_div_i64(tmp, tmp, tmp2); - store_reg32_i64((r1 + 1) & 15, tmp); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); + case 2: + tcg_gen_qemu_ld16u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld16u(cc_dst, o->in2, get_mem_index(s)); break; - case 0x98: /* ALC R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - store_reg32(r1, tmp32_3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); + case 4: + tcg_gen_qemu_ld32u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld32u(cc_dst, o->in2, get_mem_index(s)); break; - case 0x99: /* SLB R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); + case 8: + tcg_gen_qemu_ld64(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld64(cc_dst, o->in2, get_mem_index(s)); break; default: - LOG_DISAS("illegal e3 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); - break; + potential_page_fault(s); + vl = tcg_const_i32(l); + gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2); + tcg_temp_free_i32(vl); + set_cc_static(s); + return NO_EXIT; } + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, cc_src, cc_dst); + return NO_EXIT; +} + +static ExitStatus op_clcle(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_clcle(cc_op, cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_clm(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t1, o->in1); + potential_page_fault(s); + gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2); + set_cc_static(s); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_clst(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} + +static ExitStatus op_cps(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t = tcg_temp_new_i64(); + tcg_gen_andi_i64(t, o->in1, 0x8000000000000000ull); + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull); + tcg_gen_or_i64(o->out, o->out, t); + tcg_temp_free_i64(t); + return NO_EXIT; +} + +static ExitStatus op_cs(DisasContext *s, DisasOps *o) +{ + /* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */ + int d2 = get_field(s->fields, d2); + int b2 = get_field(s->fields, b2); + int is_64 = s->insn->data; + TCGv_i64 addr, mem, cc, z; + + /* Note that in1 = R3 (new value) and + in2 = (zero-extended) R1 (expected value). */ + + /* Load the memory into the (temporary) output. While the PoO only talks + about moving the memory to R1 on inequality, if we include equality it + means that R1 is equal to the memory in all conditions. */ + addr = get_address(s, 0, b2, d2); + if (is_64) { + tcg_gen_qemu_ld64(o->out, addr, get_mem_index(s)); + } else { + tcg_gen_qemu_ld32u(o->out, addr, get_mem_index(s)); + } + + /* Are the memory and expected values (un)equal? Note that this setcond + produces the output CC value, thus the NE sense of the test. */ + cc = tcg_temp_new_i64(); + tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in2, o->out); + + /* If the memory and expected values are equal (CC==0), copy R3 to MEM. + Recall that we are allowed to unconditionally issue the store (and + thus any possible write trap), so (re-)store the original contents + of MEM in case of inequality. */ + z = tcg_const_i64(0); + mem = tcg_temp_new_i64(); + tcg_gen_movcond_i64(TCG_COND_EQ, mem, cc, z, o->in1, o->out); + if (is_64) { + tcg_gen_qemu_st64(mem, addr, get_mem_index(s)); + } else { + tcg_gen_qemu_st32(mem, addr, get_mem_index(s)); + } + tcg_temp_free_i64(z); + tcg_temp_free_i64(mem); tcg_temp_free_i64(addr); + + /* Store CC back to cc_op. Wait until after the store so that any + exception gets the old cc_op value. */ + tcg_gen_trunc_i64_i32(cc_op, cc); + tcg_temp_free_i64(cc); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) +{ + /* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + int d2 = get_field(s->fields, d2); + int b2 = get_field(s->fields, b2); + TCGv_i64 addrh, addrl, memh, meml, outh, outl, cc, z; + + /* Note that R1:R1+1 = expected value and R3:R3+1 = new value. */ + + addrh = get_address(s, 0, b2, d2); + addrl = get_address(s, 0, b2, d2 + 8); + outh = tcg_temp_new_i64(); + outl = tcg_temp_new_i64(); + + tcg_gen_qemu_ld64(outh, addrh, get_mem_index(s)); + tcg_gen_qemu_ld64(outl, addrl, get_mem_index(s)); + + /* Fold the double-word compare with arithmetic. */ + cc = tcg_temp_new_i64(); + z = tcg_temp_new_i64(); + tcg_gen_xor_i64(cc, outh, regs[r1]); + tcg_gen_xor_i64(z, outl, regs[r1 + 1]); + tcg_gen_or_i64(cc, cc, z); + tcg_gen_movi_i64(z, 0); + tcg_gen_setcond_i64(TCG_COND_NE, cc, cc, z); + + memh = tcg_temp_new_i64(); + meml = tcg_temp_new_i64(); + tcg_gen_movcond_i64(TCG_COND_EQ, memh, cc, z, regs[r3], outh); + tcg_gen_movcond_i64(TCG_COND_EQ, meml, cc, z, regs[r3 + 1], outl); + tcg_temp_free_i64(z); + + tcg_gen_qemu_st64(memh, addrh, get_mem_index(s)); + tcg_gen_qemu_st64(meml, addrl, get_mem_index(s)); + tcg_temp_free_i64(memh); + tcg_temp_free_i64(meml); + tcg_temp_free_i64(addrh); + tcg_temp_free_i64(addrl); + + /* Save back state now that we've passed all exceptions. */ + tcg_gen_mov_i64(regs[r1], outh); + tcg_gen_mov_i64(regs[r1 + 1], outl); + tcg_gen_trunc_i64_i32(cc_op, cc); + tcg_temp_free_i64(outh); + tcg_temp_free_i64(outl); + tcg_temp_free_i64(cc); + set_cc_static(s); + return NO_EXIT; } #ifndef CONFIG_USER_ONLY -static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) +static ExitStatus op_csp(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp, tmp2; - int op = (insn >> 32) & 0xff; + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + check_privileged(s); + gen_helper_csp(cc_op, cpu_env, r1, o->in2); + tcg_temp_free_i32(r1); + set_cc_static(s); + return NO_EXIT; +} +#endif - tmp = get_address(s, 0, (insn >> 28) & 0xf, (insn >> 16) & 0xfff); - tmp2 = get_address(s, 0, (insn >> 12) & 0xf, insn & 0xfff); +static ExitStatus op_cvd(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i32 t2 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t2, o->in1); + gen_helper_cvd(t1, t2); + tcg_temp_free_i32(t2); + tcg_gen_qemu_st64(t1, o->in2, get_mem_index(s)); + tcg_temp_free_i64(t1); + return NO_EXIT; +} - LOG_DISAS("disas_e5: insn %" PRIx64 "\n", insn); - switch (op) { - case 0x01: /* TPROT D1(B1),D2(B2) [SSE] */ - /* Test Protection */ - potential_page_fault(s); - gen_helper_tprot(cc_op, tmp, tmp2); - set_cc_static(s); - break; - default: - LOG_DISAS("illegal e5 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); - break; +static ExitStatus op_ct(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int lab = gen_new_label(); + TCGv_i32 t; + TCGCond c; + + c = tcg_invert_cond(ltgt_cond[m3]); + if (s->insn->data) { + c = tcg_unsigned_cond(c); } + tcg_gen_brcond_i64(c, o->in1, o->in2, lab); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); + /* Set DXC to 0xff. */ + t = tcg_temp_new_i32(); + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_ori_i32(t, t, 0xff00); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_temp_free_i32(t); + + /* Trap. */ + gen_program_exception(s, PGM_DATA); + + gen_set_label(lab); + return NO_EXIT; +} + +#ifndef CONFIG_USER_ONLY +static ExitStatus op_diag(DisasContext *s, DisasOps *o) +{ + TCGv_i32 tmp; + + check_privileged(s); + potential_page_fault(s); + + /* We pretend the format is RX_a so that D2 is the field we want. */ + tmp = tcg_const_i32(get_field(s->fields, d2) & 0xfff); + gen_helper_diag(regs[2], cpu_env, tmp, regs[2], regs[1]); + tcg_temp_free_i32(tmp); + return NO_EXIT; } #endif -static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, - int r3, int b2, int d2) +static ExitStatus op_divs32(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp, tmp2, tmp3, tmp4; - TCGv_i32 tmp32_1, tmp32_2; - int i, stm_len; - int ilc = 3; + gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} - LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", - op, r1, r3, b2, d2); - switch (op) { - case 0xc: /* SRLG R1,R3,D2(B2) [RSY] */ - case 0xd: /* SLLG R1,R3,D2(B2) [RSY] */ - case 0xa: /* SRAG R1,R3,D2(B2) [RSY] */ - case 0xb: /* SLAG R1,R3,D2(B2) [RSY] */ - case 0x1c: /* RLLG R1,R3,D2(B2) [RSY] */ - if (b2) { - tmp = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - } else { - tmp = tcg_const_i64(d2 & 0x3f); - } - switch (op) { - case 0xc: - tcg_gen_shr_i64(regs[r1], regs[r3], tmp); - break; - case 0xd: - tcg_gen_shl_i64(regs[r1], regs[r3], tmp); - break; - case 0xa: - tcg_gen_sar_i64(regs[r1], regs[r3], tmp); - break; - case 0xb: - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - gen_op_update2_cc_i64(s, CC_OP_SLAG, regs[r3], tmp); - tcg_gen_shl_i64(tmp2, regs[r3], tmp); - /* override sign bit with source sign */ - tcg_gen_andi_i64(tmp2, tmp2, ~0x8000000000000000ULL); - tcg_gen_andi_i64(tmp3, regs[r3], 0x8000000000000000ULL); - tcg_gen_or_i64(regs[r1], tmp2, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x1c: - tcg_gen_rotl_i64(regs[r1], regs[r3], tmp); - break; - default: - tcg_abort(); - break; - } - if (op == 0xa) { - set_cc_s64(s, regs[r1]); - } - tcg_temp_free_i64(tmp); - break; - case 0x1d: /* RLL R1,R3,D2(B2) [RSY] */ - if (b2) { - tmp = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - } else { - tmp = tcg_const_i64(d2 & 0x3f); - } - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r3); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - switch (op) { - case 0x1d: - tcg_gen_rotl_i32(tmp32_1, tmp32_2, tmp32_1); - break; - default: - tcg_abort(); - break; - } - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); +static ExitStatus op_divu32(DisasContext *s, DisasOps *o) +{ + gen_helper_divu32(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_divs64(DisasContext *s, DisasOps *o) +{ + gen_helper_divs64(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_divu64(DisasContext *s, DisasOps *o) +{ + gen_helper_divu64(o->out2, cpu_env, o->out, o->out2, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_deb(DisasContext *s, DisasOps *o) +{ + gen_helper_deb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ddb(DisasContext *s, DisasOps *o) +{ + gen_helper_ddb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_dxb(DisasContext *s, DisasOps *o) +{ + gen_helper_dxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_ear(DisasContext *s, DisasOps *o) +{ + int r2 = get_field(s->fields, r2); + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, aregs[r2])); + return NO_EXIT; +} + +static ExitStatus op_efpc(DisasContext *s, DisasOps *o) +{ + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); + return NO_EXIT; +} + +static ExitStatus op_ex(DisasContext *s, DisasOps *o) +{ + /* ??? Perhaps a better way to implement EXECUTE is to set a bit in + tb->flags, (ab)use the tb->cs_base field as the address of + the template in memory, and grab 8 bits of tb->flags/cflags for + the contents of the register. We would then recognize all this + in gen_intermediate_code_internal, generating code for exactly + one instruction. This new TB then gets executed normally. + + On the other hand, this seems to be mostly used for modifying + MVC inside of memcpy, which needs a helper call anyway. So + perhaps this doesn't bear thinking about any further. */ + + TCGv_i64 tmp; + + update_psw_addr(s); + update_cc_op(s); + + tmp = tcg_const_i64(s->next_pc); + gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp); + tcg_temp_free_i64(tmp); + + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_flogr(DisasContext *s, DisasOps *o) +{ + /* We'll use the original input for cc computation, since we get to + compare that against 0, which ought to be better than comparing + the real output against 64. It also lets cc_dst be a convenient + temporary during our computation. */ + gen_op_update1_cc_i64(s, CC_OP_FLOGR, o->in2); + + /* R1 = IN ? CLZ(IN) : 64. */ + gen_helper_clz(o->out, o->in2); + + /* R1+1 = IN & ~(found bit). Note that we may attempt to shift this + value by 64, which is undefined. But since the shift is 64 iff the + input is zero, we still get the correct result after and'ing. */ + tcg_gen_movi_i64(o->out2, 0x8000000000000000ull); + tcg_gen_shr_i64(o->out2, o->out2, o->out); + tcg_gen_andc_i64(o->out2, cc_dst, o->out2); + return NO_EXIT; +} + +static ExitStatus op_icm(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int pos, len, base = s->insn->data; + TCGv_i64 tmp = tcg_temp_new_i64(); + uint64_t ccm; + + switch (m3) { + case 0xf: + /* Effectively a 32-bit load. */ + tcg_gen_qemu_ld32u(tmp, o->in2, get_mem_index(s)); + len = 32; + goto one_insert; + + case 0xc: + case 0x6: + case 0x3: + /* Effectively a 16-bit load. */ + tcg_gen_qemu_ld16u(tmp, o->in2, get_mem_index(s)); + len = 16; + goto one_insert; + + case 0x8: + case 0x4: + case 0x2: + case 0x1: + /* Effectively an 8-bit load. */ + tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); + len = 8; + goto one_insert; + + one_insert: + pos = base + ctz32(m3) * 8; + tcg_gen_deposit_i64(o->out, o->out, tmp, pos, len); + ccm = ((1ull << len) - 1) << pos; break; - case 0x4: /* LMG R1,R3,D2(B2) [RSE] */ - case 0x24: /* STMG R1,R3,D2(B2) [RSE] */ - stm_len = 8; - goto do_mh; - case 0x26: /* STMH R1,R3,D2(B2) [RSE] */ - case 0x96: /* LMH R1,R3,D2(B2) [RSE] */ - stm_len = 4; -do_mh: - /* Apparently, unrolling lmg/stmg of any size gains performance - - even for very long ones... */ - tmp = get_address(s, 0, b2, d2); - tmp3 = tcg_const_i64(stm_len); - tmp4 = tcg_const_i64(op == 0x26 ? 32 : 4); - for (i = r1;; i = (i + 1) % 16) { - switch (op) { - case 0x4: - tcg_gen_qemu_ld64(regs[i], tmp, get_mem_index(s)); - break; - case 0x96: - tmp2 = tcg_temp_new_i64(); -#if HOST_LONG_BITS == 32 - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(TCGV_HIGH(regs[i]), tmp2); -#else - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_shl_i64(tmp2, tmp2, tmp4); - tcg_gen_ext32u_i64(regs[i], regs[i]); - tcg_gen_or_i64(regs[i], regs[i], tmp2); -#endif - tcg_temp_free_i64(tmp2); - break; - case 0x24: - tcg_gen_qemu_st64(regs[i], tmp, get_mem_index(s)); - break; - case 0x26: - tmp2 = tcg_temp_new_i64(); - tcg_gen_shr_i64(tmp2, regs[i], tmp4); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; - default: - tcg_abort(); - } - if (i == r3) { - break; + + default: + /* This is going to be a sequence of loads and inserts. */ + pos = base + 32 - 8; + ccm = 0; + while (m3) { + if (m3 & 0x8) { + tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 1); + tcg_gen_deposit_i64(o->out, o->out, tmp, pos, 8); + ccm |= 0xff << pos; } - tcg_gen_add_i64(tmp, tmp, tmp3); + m3 = (m3 << 1) & 0xf; + pos -= 8; } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; - case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stcmh(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); break; + } + + tcg_gen_movi_i64(tmp, ccm); + gen_op_update2_cc_i64(s, CC_OP_ICM, tmp, o->out); + tcg_temp_free_i64(tmp); + return NO_EXIT; +} + +static ExitStatus op_insi(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + tcg_gen_deposit_i64(o->out, o->in1, o->in2, shift, size); + return NO_EXIT; +} + +static ExitStatus op_ipm(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1; + + gen_op_calc_cc(s); + tcg_gen_andi_i64(o->out, o->out, ~0xff000000ull); + + t1 = tcg_temp_new_i64(); + tcg_gen_shli_i64(t1, psw_mask, 20); + tcg_gen_shri_i64(t1, t1, 36); + tcg_gen_or_i64(o->out, o->out, t1); + + tcg_gen_extu_i32_i64(t1, cc_op); + tcg_gen_shli_i64(t1, t1, 28); + tcg_gen_or_i64(o->out, o->out, t1); + tcg_temp_free_i64(t1); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY - case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ - /* Load Control */ - check_privileged(env, s, ilc); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lctlg(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */ - /* Store Control */ - check_privileged(env, s, ilc); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stctg(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; +static ExitStatus op_ipte(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_ipte(cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_iske(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_iske(o->out, cpu_env, o->in2); + return NO_EXIT; +} #endif - case 0x30: /* CSG R1,R3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX rewrite in tcg */ - gen_helper_csg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x3e: /* CDSG R1,R3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX rewrite in tcg */ - gen_helper_cdsg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x51: /* TMY D1(B1),I2 [SIY] */ - tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */ - tmp2 = tcg_const_i64((r1 << 4) | r3); - tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s)); - /* yes, this is a 32 bit operation with 64 bit tcg registers, because - that incurs less conversions */ - cmp_64(s, tmp, tmp2, CC_OP_TM_32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x52: /* MVIY D1(B1),I2 [SIY] */ - tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */ - tmp2 = tcg_const_i64((r1 << 4) | r3); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x55: /* CLIY D1(B1),I2 [SIY] */ - tmp3 = get_address(s, 0, b2, d2); /* SIY -> this is the 1st operand */ - tmp = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld8u(tmp, tmp3, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - cmp_u32c(s, tmp32_1, (r1 << 4) | r3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i32(tmp32_1); - break; - case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX split CC calculation out */ - gen_helper_icmh(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - default: - LOG_DISAS("illegal eb operation 0x%x\n", op); - gen_illegal_opcode(env, s, ilc); - break; - } + +static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) +{ + gen_helper_ldeb(o->out, cpu_env, o->in2); + return NO_EXIT; } -static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, - int x2, int b2, int d2, int r1b) +static ExitStatus op_ledb(DisasContext *s, DisasOps *o) { - TCGv_i32 tmp_r1, tmp32; - TCGv_i64 addr, tmp; - addr = get_address(s, x2, b2, d2); - tmp_r1 = tcg_const_i32(r1); - switch (op) { - case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_ldeb(cpu_env, tmp_r1, addr); - break; - case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_lxdb(cpu_env, tmp_r1, addr); - break; - case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = load_freg32(r1); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - set_cc_cmp_f32_i64(s, tmp32, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; - case 0xa: /* AEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_aeb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - - tmp32 = load_freg32(r1); - gen_set_cc_nz_f32(s, tmp32); - tcg_temp_free_i32(tmp32); - break; - case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_seb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - - tmp32 = load_freg32(r1); - gen_set_cc_nz_f32(s, tmp32); - tcg_temp_free_i32(tmp32); - break; - case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_deb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; - case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tcdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_meeb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; - case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_cdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_adb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_mdb(cpu_env, tmp_r1, addr); - break; - case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_ddb(cpu_env, tmp_r1, addr); - break; - case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ - /* for RXF insns, r1 is R3 and r1b is R1 */ - tmp32 = tcg_const_i32(r1b); - potential_page_fault(s); - gen_helper_madb(cpu_env, tmp32, addr, tmp_r1); - tcg_temp_free_i32(tmp32); - break; - default: - LOG_DISAS("illegal ed operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); - return; + gen_helper_ledb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ldxb(DisasContext *s, DisasOps *o) +{ + gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_lexb(DisasContext *s, DisasOps *o) +{ + gen_helper_lexb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_lxdb(DisasContext *s, DisasOps *o) +{ + gen_helper_lxdb(o->out, cpu_env, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_lxeb(DisasContext *s, DisasOps *o) +{ + gen_helper_lxeb(o->out, cpu_env, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_llgt(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff); + return NO_EXIT; +} + +static ExitStatus op_ld8s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld8u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld8u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld16s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld16s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld16u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld16u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld32s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld32s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld32u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld64(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_loc(DisasContext *s, DisasOps *o) +{ + DisasCompare c; + + disas_jcc(s, &c, get_field(s->fields, m3)); + + if (c.is_64) { + tcg_gen_movcond_i64(c.cond, o->out, c.u.s64.a, c.u.s64.b, + o->in2, o->in1); + free_compare(&c); + } else { + TCGv_i32 t32 = tcg_temp_new_i32(); + TCGv_i64 t, z; + + tcg_gen_setcond_i32(c.cond, t32, c.u.s32.a, c.u.s32.b); + free_compare(&c); + + t = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t, t32); + tcg_temp_free_i32(t32); + + z = tcg_const_i64(0); + tcg_gen_movcond_i64(TCG_COND_NE, o->out, t, z, o->in2, o->in1); + tcg_temp_free_i64(t); + tcg_temp_free_i64(z); } - tcg_temp_free_i32(tmp_r1); - tcg_temp_free_i64(addr); + + return NO_EXIT; } -static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) +#ifndef CONFIG_USER_ONLY +static ExitStatus op_lctl(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp, tmp2; - TCGv_i32 tmp32; - LOG_DISAS("disas_a5: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); - switch (op) { - case 0x0: /* IIHH R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 48, 16); - tcg_temp_free_i64(tmp); - break; - case 0x1: /* IIHL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 32, 16); - tcg_temp_free_i64(tmp); - break; - case 0x2: /* IILH R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 16, 16); - tcg_temp_free_i64(tmp); - break; - case 0x3: /* IILL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 0, 16); - tcg_temp_free_i64(tmp); - break; - case 0x4: /* NIHH R1,I2 [RI] */ - case 0x8: /* OIHH R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x4: - tmp2 = tcg_const_i64((((uint64_t)i2) << 48) - | 0x0000ffffffffffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x8: - tmp2 = tcg_const_i64(((uint64_t)i2) << 48); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp2, tmp, 48); - tcg_gen_trunc_i64_i32(tmp32, tmp2); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x5: /* NIHL R1,I2 [RI] */ - case 0x9: /* OIHL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x5: - tmp2 = tcg_const_i64((((uint64_t)i2) << 32) - | 0xffff0000ffffffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x9: - tmp2 = tcg_const_i64(((uint64_t)i2) << 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp2, tmp, 32); - tcg_gen_trunc_i64_i32(tmp32, tmp2); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x6: /* NILH R1,I2 [RI] */ - case 0xa: /* OILH R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x6: - tmp2 = tcg_const_i64((((uint64_t)i2) << 16) - | 0xffffffff0000ffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0xa: - tmp2 = tcg_const_i64(((uint64_t)i2) << 16); - tcg_gen_or_i64(tmp, tmp, tmp2); + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_lctl(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + +static ExitStatus op_lctlg(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_lctlg(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} +static ExitStatus op_lra(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_lra(o->out, cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1, t2; + + check_privileged(s); + + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 4); + tcg_gen_qemu_ld32u(t2, o->in2, get_mem_index(s)); + /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK. */ + tcg_gen_shli_i64(t1, t1, 32); + gen_helper_load_psw(cpu_env, t1, t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return EXIT_NORETURN; +} + +static ExitStatus op_lpswe(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1, t2; + + check_privileged(s); + + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 8); + tcg_gen_qemu_ld64(t2, o->in2, get_mem_index(s)); + gen_helper_load_psw(cpu_env, t1, t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return EXIT_NORETURN; +} +#endif + +static ExitStatus op_lam(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_lam(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + +static ExitStatus op_lm32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + + while (1) { + tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); + store_reg32_i64(r1, t); + if (r1 == r3) { break; - default: - tcg_abort(); } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp, tmp, 16); - tcg_gen_trunc_i64_i32(tmp32, tmp); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x7: /* NILL R1,I2 [RI] */ - case 0xb: /* OILL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x7: - tmp2 = tcg_const_i64(i2 | 0xffffffffffff0000ULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0xb: - tmp2 = tcg_const_i64(i2); - tcg_gen_or_i64(tmp, tmp, tmp2); + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + return NO_EXIT; +} + +static ExitStatus op_lmh(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + + while (1) { + tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); + store_reg32h_i64(r1, t); + if (r1 == r3) { break; - default: - tcg_abort(); } - store_reg(r1, tmp); - tcg_gen_trunc_i64_i32(tmp32, tmp); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); /* signedness should not matter here */ - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0xc: /* LLIHH R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 48 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xd: /* LLIHL R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 32 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xe: /* LLILH R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 16 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xf: /* LLILL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - default: - LOG_DISAS("illegal a5 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); - return; + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + return NO_EXIT; } -static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) +static ExitStatus op_lm64(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp, tmp2; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; - int l1; + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t8 = tcg_const_i64(8); - LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); - switch (op) { - case 0x0: /* TMLH or TMH R1,I2 [RI] */ - case 0x1: /* TMLL or TML R1,I2 [RI] */ - case 0x2: /* TMHH R1,I2 [RI] */ - case 0x3: /* TMHL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64((uint16_t)i2); - switch (op) { - case 0x0: - tcg_gen_shri_i64(tmp, tmp, 16); - break; - case 0x1: - break; - case 0x2: - tcg_gen_shri_i64(tmp, tmp, 48); - break; - case 0x3: - tcg_gen_shri_i64(tmp, tmp, 32); + while (1) { + tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s)); + if (r1 == r3) { break; } - tcg_gen_andi_i64(tmp, tmp, 0xffff); - cmp_64(s, tmp, tmp2, CC_OP_TM_64); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x4: /* brc m1, i2 */ - gen_brc(r1, s, i2 * 2LL); - return; - case 0x5: /* BRAS R1,I2 [RI] */ - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 4)); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - gen_goto_tb(s, 0, s->pc + i2 * 2LL); - s->is_jmp = DISAS_TB_JUMP; - break; - case 0x6: /* BRCT R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1); - gen_goto_tb(s, 0, s->pc + (i2 * 2LL)); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 4); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i32(tmp32_1); - break; - case 0x7: /* BRCTG R1,I2 [RI] */ - tmp = load_reg(r1); - tcg_gen_subi_i64(tmp, tmp, 1); - store_reg(r1, tmp); - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i64(TCG_COND_EQ, tmp, 0, l1); - gen_goto_tb(s, 0, s->pc + (i2 * 2LL)); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 4); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i64(tmp); - break; - case 0x8: /* lhi r1, i2 */ - tmp32_1 = tcg_const_i32(i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x9: /* lghi r1, i2 */ - tmp = tcg_const_i64(i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xa: /* AHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_const_i32(i2); + tcg_gen_add_i64(o->in2, o->in2, t8); + r1 = (r1 + 1) & 15; + } - if (i2 < 0) { - tcg_gen_subi_i32(tmp32_2, tmp32_1, -i2); - } else { - tcg_gen_add_i32(tmp32_2, tmp32_1, tmp32_3); - } + tcg_temp_free_i64(t8); + return NO_EXIT; +} + +static ExitStatus op_mov2(DisasContext *s, DisasOps *o) +{ + o->out = o->in2; + o->g_out = o->g_in2; + TCGV_UNUSED_I64(o->in2); + o->g_in2 = false; + return NO_EXIT; +} + +static ExitStatus op_movx(DisasContext *s, DisasOps *o) +{ + o->out = o->in1; + o->out2 = o->in2; + o->g_out = o->g_in1; + o->g_out2 = o->g_in2; + TCGV_UNUSED_I64(o->in1); + TCGV_UNUSED_I64(o->in2); + o->g_in1 = o->g_in2 = false; + return NO_EXIT; +} - store_reg32(r1, tmp32_2); - set_cc_add32(s, tmp32_1, tmp32_3, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); +static ExitStatus op_mvc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_mvc(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + +static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2)); + potential_page_fault(s); + gen_helper_mvcl(cc_op, cpu_env, r1, r2); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_mvcle(cc_op, cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + set_cc_static(s); + return NO_EXIT; +} + +#ifndef CONFIG_USER_ONLY +static ExitStatus op_mvcp(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, l1); + check_privileged(s); + potential_page_fault(s); + gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_mvcs(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, l1); + check_privileged(s); + potential_page_fault(s); + gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} +#endif + +static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_mvpg(cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_mvst(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} + +static ExitStatus op_mul(DisasContext *s, DisasOps *o) +{ + tcg_gen_mul_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mul128(DisasContext *s, DisasOps *o) +{ + gen_helper_mul128(o->out, cpu_env, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_meeb(DisasContext *s, DisasOps *o) +{ + gen_helper_meeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mdeb(DisasContext *s, DisasOps *o) +{ + gen_helper_mdeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mdb(DisasContext *s, DisasOps *o) +{ + gen_helper_mdb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mxb(DisasContext *s, DisasOps *o) +{ + gen_helper_mxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_mxdb(DisasContext *s, DisasOps *o) +{ + gen_helper_mxdb(o->out, cpu_env, o->out, o->out2, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_maeb(DisasContext *s, DisasOps *o) +{ + TCGv_i64 r3 = load_freg32_i64(get_field(s->fields, r3)); + gen_helper_maeb(o->out, cpu_env, o->in1, o->in2, r3); + tcg_temp_free_i64(r3); + return NO_EXIT; +} + +static ExitStatus op_madb(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + gen_helper_madb(o->out, cpu_env, o->in1, o->in2, fregs[r3]); + return NO_EXIT; +} + +static ExitStatus op_mseb(DisasContext *s, DisasOps *o) +{ + TCGv_i64 r3 = load_freg32_i64(get_field(s->fields, r3)); + gen_helper_mseb(o->out, cpu_env, o->in1, o->in2, r3); + tcg_temp_free_i64(r3); + return NO_EXIT; +} + +static ExitStatus op_msdb(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + gen_helper_msdb(o->out, cpu_env, o->in1, o->in2, fregs[r3]); + return NO_EXIT; +} + +static ExitStatus op_nabs(DisasContext *s, DisasOps *o) +{ + gen_helper_nabs_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_nabsf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in2, 0x80000000ull); + return NO_EXIT; +} + +static ExitStatus op_nabsf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in2, 0x8000000000000000ull); + return NO_EXIT; +} + +static ExitStatus op_nabsf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in1, 0x8000000000000000ull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} + +static ExitStatus op_nc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_neg(DisasContext *s, DisasOps *o) +{ + tcg_gen_neg_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_negf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in2, 0x80000000ull); + return NO_EXIT; +} + +static ExitStatus op_negf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in2, 0x8000000000000000ull); + return NO_EXIT; +} + +static ExitStatus op_negf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in1, 0x8000000000000000ull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} + +static ExitStatus op_oc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_or(DisasContext *s, DisasOps *o) +{ + tcg_gen_or_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ori(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_or_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + +static ExitStatus op_popcnt(DisasContext *s, DisasOps *o) +{ + gen_helper_popcnt(o->out, o->in2); + return NO_EXIT; +} + +#ifndef CONFIG_USER_ONLY +static ExitStatus op_ptlb(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_ptlb(cpu_env); + return NO_EXIT; +} +#endif + +static ExitStatus op_risbg(DisasContext *s, DisasOps *o) +{ + int i3 = get_field(s->fields, i3); + int i4 = get_field(s->fields, i4); + int i5 = get_field(s->fields, i5); + int do_zero = i4 & 0x80; + uint64_t mask, imask, pmask; + int pos, len, rot; + + /* Adjust the arguments for the specific insn. */ + switch (s->fields->op2) { + case 0x55: /* risbg */ + i3 &= 63; + i4 &= 63; + pmask = ~0; + break; + case 0x5d: /* risbhg */ + i3 &= 31; + i4 &= 31; + pmask = 0xffffffff00000000ull; + break; + case 0x51: /* risblg */ + i3 &= 31; + i4 &= 31; + pmask = 0x00000000ffffffffull; break; - case 0xb: /* aghi r1, i2 */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64(i2); + default: + abort(); + } - if (i2 < 0) { - tcg_gen_subi_i64(regs[r1], tmp, -i2); + /* MASK is the set of bits to be inserted from R2. + Take care for I3/I4 wraparound. */ + mask = pmask >> i3; + if (i3 <= i4) { + mask ^= pmask >> i4 >> 1; + } else { + mask |= ~(pmask >> i4 >> 1); + } + mask &= pmask; + + /* IMASK is the set of bits to be kept from R1. In the case of the high/low + insns, we need to keep the other half of the register. */ + imask = ~mask | ~pmask; + if (do_zero) { + if (s->fields->op2 == 0x55) { + imask = 0; } else { - tcg_gen_add_i64(regs[r1], tmp, tmp2); + imask = ~pmask; } - set_cc_add64(s, tmp, tmp2, regs[r1]); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0xc: /* MHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tcg_gen_muli_i32(tmp32_1, tmp32_1, i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0xd: /* MGHI R1,I2 [RI] */ - tmp = load_reg(r1); - tcg_gen_muli_i64(tmp, tmp, i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); + } + + /* In some cases we can implement this with deposit, which can be more + efficient on some hosts. */ + if (~mask == imask && i3 <= i4) { + if (s->fields->op2 == 0x5d) { + i3 += 32, i4 += 32; + } + /* Note that we rotate the bits to be inserted to the lsb, not to + the position as described in the PoO. */ + len = i4 - i3 + 1; + pos = 63 - i4; + rot = (i5 - pos) & 63; + } else { + pos = len = -1; + rot = i5 & 63; + } + + /* Rotate the input as necessary. */ + tcg_gen_rotli_i64(o->in2, o->in2, rot); + + /* Insert the selected bits into the output. */ + if (pos >= 0) { + tcg_gen_deposit_i64(o->out, o->out, o->in2, pos, len); + } else if (imask == 0) { + tcg_gen_andi_i64(o->out, o->in2, mask); + } else { + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_andi_i64(o->out, o->out, imask); + tcg_gen_or_i64(o->out, o->out, o->in2); + } + return NO_EXIT; +} + +static ExitStatus op_rosbg(DisasContext *s, DisasOps *o) +{ + int i3 = get_field(s->fields, i3); + int i4 = get_field(s->fields, i4); + int i5 = get_field(s->fields, i5); + uint64_t mask; + + /* If this is a test-only form, arrange to discard the result. */ + if (i3 & 0x80) { + o->out = tcg_temp_new_i64(); + o->g_out = false; + } + + i3 &= 63; + i4 &= 63; + i5 &= 63; + + /* MASK is the set of bits to be operated on from R2. + Take care for I3/I4 wraparound. */ + mask = ~0ull >> i3; + if (i3 <= i4) { + mask ^= ~0ull >> i4 >> 1; + } else { + mask |= ~(~0ull >> i4 >> 1); + } + + /* Rotate the input as necessary. */ + tcg_gen_rotli_i64(o->in2, o->in2, i5); + + /* Operate. */ + switch (s->fields->op2) { + case 0x55: /* AND */ + tcg_gen_ori_i64(o->in2, o->in2, ~mask); + tcg_gen_and_i64(o->out, o->out, o->in2); break; - case 0xe: /* CHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - cmp_s32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); + case 0x56: /* OR */ + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_or_i64(o->out, o->out, o->in2); break; - case 0xf: /* CGHI R1,I2 [RI] */ - tmp = load_reg(r1); - cmp_s64c(s, tmp, i2); - tcg_temp_free_i64(tmp); + case 0x57: /* XOR */ + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_xor_i64(o->out, o->out, o->in2); break; default: - LOG_DISAS("illegal a7 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); - return; + abort(); } + + /* Set the CC. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + +static ExitStatus op_rev16(DisasContext *s, DisasOps *o) +{ + tcg_gen_bswap16_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_rev32(DisasContext *s, DisasOps *o) +{ + tcg_gen_bswap32_i64(o->out, o->in2); + return NO_EXIT; } -static void disas_b2(CPUS390XState *env, DisasContext *s, int op, - uint32_t insn) +static ExitStatus op_rev64(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; - int r1, r2; - int ilc = 2; + tcg_gen_bswap64_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_rll32(DisasContext *s, DisasOps *o) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 to = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t1, o->in1); + tcg_gen_trunc_i64_i32(t2, o->in2); + tcg_gen_rotl_i32(to, t1, t2); + tcg_gen_extu_i32_i64(o->out, to); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(to); + return NO_EXIT; +} + +static ExitStatus op_rll64(DisasContext *s, DisasOps *o) +{ + tcg_gen_rotl_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY - int r3, d2, b2; +static ExitStatus op_rrbe(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_rrbe(cc_op, cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_sacf(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sacf(cpu_env, o->in2); + /* Addressing mode has changed, so end the block. */ + return EXIT_PC_STALE; +} #endif - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; +static ExitStatus op_sar(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + tcg_gen_st32_i64(o->in2, cpu_env, offsetof(CPUS390XState, aregs[r1])); + return NO_EXIT; +} - LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); +static ExitStatus op_seb(DisasContext *s, DisasOps *o) +{ + gen_helper_seb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} - switch (op) { - case 0x22: /* IPM R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_ipm(cpu_env, cc_op, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x41: /* CKSM R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_cksm(cpu_env, tmp32_1, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - gen_op_movi_cc(s, 0); - break; - case 0x4e: /* SAR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r1])); - tcg_temp_free_i32(tmp32_1); - break; - case 0x4f: /* EAR R1,R2 [RRE] */ - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r2])); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x52: /* MSR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x54: /* MVPG R1,R2 [RRE] */ - tmp = load_reg(0); - tmp2 = load_reg(r1); - tmp3 = load_reg(r2); - potential_page_fault(s); - gen_helper_mvpg(cpu_env, tmp, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - /* XXX check CCO bit and set CC accordingly */ - gen_op_movi_cc(s, 0); - break; - case 0x55: /* MVST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_mvst(cpu_env, tmp32_1, tmp32_2, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - gen_op_movi_cc(s, 1); - break; - case 0x5d: /* CLST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_clst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x5e: /* SRST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_srst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; +static ExitStatus op_sdb(DisasContext *s, DisasOps *o) +{ + gen_helper_sdb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sxb(DisasContext *s, DisasOps *o) +{ + gen_helper_sxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_sqeb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqeb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sqdb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqdb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sqxb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqxb(o->out, cpu_env, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} #ifndef CONFIG_USER_ONLY - case 0x02: /* STIDP D2(B2) [S] */ - /* Store CPU ID */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stidp(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x04: /* SCK D2(B2) [S] */ - /* Set Clock */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sck(cc_op, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; - case 0x05: /* STCK D2(B2) [S] */ - /* Store Clock */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stck(cc_op, cpu_env, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; - case 0x06: /* SCKC D2(B2) [S] */ - /* Set Clock Comparator */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sckc(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x07: /* STCKC D2(B2) [S] */ - /* Store Clock Comparator */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stckc(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x08: /* SPT D2(B2) [S] */ - /* Set CPU Timer */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_spt(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x09: /* STPT D2(B2) [S] */ - /* Store CPU Timer */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stpt(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x0a: /* SPKA D2(B2) [S] */ - /* Set PSW Key from Address */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_andi_i64(tmp2, psw_mask, ~PSW_MASK_KEY); - tcg_gen_shli_i64(tmp, tmp, PSW_SHIFT_KEY - 4); - tcg_gen_or_i64(psw_mask, tmp2, tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; - case 0x0d: /* PTLB [S] */ - /* Purge TLB */ - check_privileged(env, s, ilc); - gen_helper_ptlb(cpu_env); - break; - case 0x10: /* SPX D2(B2) [S] */ - /* Set Prefix Register */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_spx(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x11: /* STPX D2(B2) [S] */ - /* Store Prefix */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp2, cpu_env, offsetof(CPUS390XState, psa)); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x12: /* STAP D2(B2) [S] */ - /* Store CPU Address */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, cpu_num)); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x21: /* IPTE R1,R2 [RRE] */ - /* Invalidate PTE */ - check_privileged(env, s, ilc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp = load_reg(r1); - tmp2 = load_reg(r2); - gen_helper_ipte(cpu_env, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x29: /* ISKE R1,R2 [RRE] */ - /* Insert Storage Key Extended */ - check_privileged(env, s, ilc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp = load_reg(r2); - tmp2 = tcg_temp_new_i64(); - gen_helper_iske(tmp2, cpu_env, tmp); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x2a: /* RRBE R1,R2 [RRE] */ - /* Set Storage Key Extended */ - check_privileged(env, s, ilc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - gen_helper_rrbe(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x2b: /* SSKE R1,R2 [RRE] */ - /* Set Storage Key Extended */ - check_privileged(env, s, ilc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - gen_helper_sske(cpu_env, tmp32_1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x34: /* STCH ? */ - /* Store Subchannel */ - check_privileged(env, s, ilc); - gen_op_movi_cc(s, 3); - break; - case 0x46: /* STURA R1,R2 [RRE] */ - /* Store Using Real Address */ - check_privileged(env, s, ilc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - potential_page_fault(s); - gen_helper_stura(cpu_env, tmp, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x50: /* CSP R1,R2 [RRE] */ - /* Compare And Swap And Purge */ - check_privileged(env, s, ilc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - gen_helper_csp(cc_op, cpu_env, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x5f: /* CHSC ? */ - /* Channel Subsystem Call */ - check_privileged(env, s, ilc); - gen_op_movi_cc(s, 3); - break; - case 0x78: /* STCKE D2(B2) [S] */ - /* Store Clock Extended */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stcke(cc_op, cpu_env, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; - case 0x79: /* SACF D2(B2) [S] */ - /* Store Clock Extended */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sacf(cpu_env, tmp); - tcg_temp_free_i64(tmp); - /* addressing mode has changed, so end the block */ - s->pc += ilc * 2; - update_psw_addr(s); - s->is_jmp = DISAS_EXCP; - break; - case 0x7d: /* STSI D2,(B2) [S] */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(0); - tmp32_2 = load_reg32(1); - potential_page_fault(s); - gen_helper_stsi(cc_op, cpu_env, tmp, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x9d: /* LFPC D2(B2) [S] */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0xb1: /* STFL D2(B2) [S] */ - /* Store Facility List (CPU features) at 200 */ - check_privileged(env, s, ilc); - tmp2 = tcg_const_i64(0xc0000000); - tmp = tcg_const_i64(200); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; - case 0xb2: /* LPSWE D2(B2) [S] */ - /* Load PSW Extended */ - check_privileged(env, s, ilc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); - tcg_gen_addi_i64(tmp, tmp, 8); - tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s)); - gen_helper_load_psw(cpu_env, tmp2, tmp3); - /* we need to keep cc_op intact */ - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x20: /* SERVC R1,R2 [RRE] */ - /* SCLP Service call (PV hypercall) */ - check_privileged(env, s, ilc); - potential_page_fault(s); - tmp32_1 = load_reg32(r2); - tmp = load_reg(r1); - gen_helper_servc(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; +static ExitStatus op_servc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_servc(cc_op, cpu_env, o->in2, o->in1); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_sigp(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + check_privileged(s); + potential_page_fault(s); + gen_helper_sigp(cc_op, cpu_env, o->in2, r1, o->in1); + tcg_temp_free_i32(r1); + return NO_EXIT; +} #endif - default: - LOG_DISAS("illegal b2 operation 0x%x\n", op); - gen_illegal_opcode(env, s, ilc); - break; + +static ExitStatus op_soc(DisasContext *s, DisasOps *o) +{ + DisasCompare c; + TCGv_i64 a; + int lab, r1; + + disas_jcc(s, &c, get_field(s->fields, m3)); + + lab = gen_new_label(); + if (c.is_64) { + tcg_gen_brcond_i64(c.cond, c.u.s64.a, c.u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c.cond, c.u.s32.a, c.u.s32.b, lab); } + free_compare(&c); + + r1 = get_field(s->fields, r1); + a = get_address(s, 0, get_field(s->fields, b2), get_field(s->fields, d2)); + if (s->insn->data) { + tcg_gen_qemu_st64(regs[r1], a, get_mem_index(s)); + } else { + tcg_gen_qemu_st32(regs[r1], a, get_mem_index(s)); + } + tcg_temp_free_i64(a); + + gen_set_label(lab); + return NO_EXIT; } -static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, - int r1, int r2) +static ExitStatus op_sla(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; - LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); -#define FP_HELPER(i) \ - tmp32_1 = tcg_const_i32(r1); \ - tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i(cpu_env, tmp32_1, tmp32_2); \ - tcg_temp_free_i32(tmp32_1); \ - tcg_temp_free_i32(tmp32_2); - -#define FP_HELPER_CC(i) \ - tmp32_1 = tcg_const_i32(r1); \ - tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i(cc_op, cpu_env, tmp32_1, tmp32_2); \ - set_cc_static(s); \ - tcg_temp_free_i32(tmp32_1); \ - tcg_temp_free_i32(tmp32_2); + uint64_t sign = 1ull << s->insn->data; + enum cc_op cco = s->insn->data == 31 ? CC_OP_SLA_32 : CC_OP_SLA_64; + gen_op_update2_cc_i64(s, cco, o->in1, o->in2); + tcg_gen_shl_i64(o->out, o->in1, o->in2); + /* The arithmetic left shift is curious in that it does not affect + the sign bit. Copy that over from the source unchanged. */ + tcg_gen_andi_i64(o->out, o->out, ~sign); + tcg_gen_andi_i64(o->in1, o->in1, sign); + tcg_gen_or_i64(o->out, o->out, o->in1); + return NO_EXIT; +} - switch (op) { - case 0x0: /* LPEBR R1,R2 [RRE] */ - FP_HELPER_CC(lpebr); - break; - case 0x2: /* LTEBR R1,R2 [RRE] */ - FP_HELPER_CC(ltebr); - break; - case 0x3: /* LCEBR R1,R2 [RRE] */ - FP_HELPER_CC(lcebr); - break; - case 0x4: /* LDEBR R1,R2 [RRE] */ - FP_HELPER(ldebr); - break; - case 0x5: /* LXDBR R1,R2 [RRE] */ - FP_HELPER(lxdbr); - break; - case 0x9: /* CEBR R1,R2 [RRE] */ - FP_HELPER_CC(cebr); - break; - case 0xa: /* AEBR R1,R2 [RRE] */ - FP_HELPER_CC(aebr); - break; - case 0xb: /* SEBR R1,R2 [RRE] */ - FP_HELPER_CC(sebr); - break; - case 0xd: /* DEBR R1,R2 [RRE] */ - FP_HELPER(debr); - break; - case 0x10: /* LPDBR R1,R2 [RRE] */ - FP_HELPER_CC(lpdbr); - break; - case 0x12: /* LTDBR R1,R2 [RRE] */ - FP_HELPER_CC(ltdbr); - break; - case 0x13: /* LCDBR R1,R2 [RRE] */ - FP_HELPER_CC(lcdbr); - break; - case 0x15: /* SQBDR R1,R2 [RRE] */ - FP_HELPER(sqdbr); - break; - case 0x17: /* MEEBR R1,R2 [RRE] */ - FP_HELPER(meebr); - break; - case 0x19: /* CDBR R1,R2 [RRE] */ - FP_HELPER_CC(cdbr); - break; - case 0x1a: /* ADBR R1,R2 [RRE] */ - FP_HELPER_CC(adbr); - break; - case 0x1b: /* SDBR R1,R2 [RRE] */ - FP_HELPER_CC(sdbr); - break; - case 0x1c: /* MDBR R1,R2 [RRE] */ - FP_HELPER(mdbr); - break; - case 0x1d: /* DDBR R1,R2 [RRE] */ - FP_HELPER(ddbr); - break; - case 0xe: /* MAEBR R1,R3,R2 [RRF] */ - case 0x1e: /* MADBR R1,R3,R2 [RRF] */ - case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ - /* for RRF insns, m3 is R1, r1 is R3, and r2 is R2 */ - tmp32_1 = tcg_const_i32(m3); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(r1); - switch (op) { - case 0xe: - gen_helper_maebr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - case 0x1e: - gen_helper_madbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - case 0x1f: - gen_helper_msdbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x40: /* LPXBR R1,R2 [RRE] */ - FP_HELPER_CC(lpxbr); - break; - case 0x42: /* LTXBR R1,R2 [RRE] */ - FP_HELPER_CC(ltxbr); - break; - case 0x43: /* LCXBR R1,R2 [RRE] */ - FP_HELPER_CC(lcxbr); - break; - case 0x44: /* LEDBR R1,R2 [RRE] */ - FP_HELPER(ledbr); - break; - case 0x45: /* LDXBR R1,R2 [RRE] */ - FP_HELPER(ldxbr); - break; - case 0x46: /* LEXBR R1,R2 [RRE] */ - FP_HELPER(lexbr); - break; - case 0x49: /* CXBR R1,R2 [RRE] */ - FP_HELPER_CC(cxbr); - break; - case 0x4a: /* AXBR R1,R2 [RRE] */ - FP_HELPER_CC(axbr); - break; - case 0x4b: /* SXBR R1,R2 [RRE] */ - FP_HELPER_CC(sxbr); - break; - case 0x4c: /* MXBR R1,R2 [RRE] */ - FP_HELPER(mxbr); - break; - case 0x4d: /* DXBR R1,R2 [RRE] */ - FP_HELPER(dxbr); - break; - case 0x65: /* LXR R1,R2 [RRE] */ - tmp = load_freg(r2); - store_freg(r1, tmp); - tcg_temp_free_i64(tmp); - tmp = load_freg(r2 + 2); - store_freg(r1 + 2, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x74: /* LZER R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzer(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x75: /* LZDR R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzdr(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x76: /* LZXR R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzxr(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x84: /* SFPC R1 [RRE] */ - tmp32_1 = load_reg32(r1); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_temp_free_i32(tmp32_1); - break; - case 0x8c: /* EFPC R1 [RRE] */ - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x94: /* CEFBR R1,R2 [RRE] */ - case 0x95: /* CDFBR R1,R2 [RRE] */ - case 0x96: /* CXFBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = load_reg32(r2); - switch (op) { - case 0x94: - gen_helper_cefbr(cpu_env, tmp32_1, tmp32_2); - break; - case 0x95: - gen_helper_cdfbr(cpu_env, tmp32_1, tmp32_2); - break; - case 0x96: - gen_helper_cxfbr(cpu_env, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x98: /* CFEBR R1,R2 [RRE] */ - case 0x99: /* CFDBR R1,R2 [RRE] */ - case 0x9a: /* CFXBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - switch (op) { - case 0x98: - gen_helper_cfebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x99: - gen_helper_cfdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x9a: - gen_helper_cfxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xa4: /* CEGBR R1,R2 [RRE] */ - case 0xa5: /* CDGBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - switch (op) { - case 0xa4: - gen_helper_cegbr(cpu_env, tmp32_1, tmp); - break; - case 0xa5: - gen_helper_cdgbr(cpu_env, tmp32_1, tmp); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0xa6: /* CXGBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - gen_helper_cxgbr(cpu_env, tmp32_1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0xa8: /* CGEBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xa9: /* CGDBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); +static ExitStatus op_sll(DisasContext *s, DisasOps *o) +{ + tcg_gen_shl_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sra(DisasContext *s, DisasOps *o) +{ + tcg_gen_sar_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_srl(DisasContext *s, DisasOps *o) +{ + tcg_gen_shr_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) +{ + gen_helper_sfpc(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sfas(DisasContext *s, DisasOps *o) +{ + gen_helper_sfas(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_srnm(DisasContext *s, DisasOps *o) +{ + int b2 = get_field(s->fields, b2); + int d2 = get_field(s->fields, d2); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + int mask, pos, len; + + switch (s->fields->op2) { + case 0x99: /* SRNM */ + pos = 0, len = 2; break; - case 0xaa: /* CGXBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); + case 0xb8: /* SRNMB */ + pos = 0, len = 3; break; + case 0xb9: /* SRNMT */ + pos = 4, len = 3; default: - LOG_DISAS("illegal b3 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); - break; + tcg_abort(); } + mask = (1 << len) - 1; -#undef FP_HELPER_CC -#undef FP_HELPER + /* Insert the value into the appropriate field of the FPC. */ + if (b2 == 0) { + tcg_gen_movi_i64(t1, d2 & mask); + } else { + tcg_gen_addi_i64(t1, regs[b2], d2); + tcg_gen_andi_i64(t1, t1, mask); + } + tcg_gen_ld32u_i64(t2, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_deposit_i64(t2, t2, t1, pos, len); + tcg_temp_free_i64(t1); + + /* Then install the new FPC to set the rounding mode in fpu_status. */ + gen_helper_sfpc(cpu_env, t2); + tcg_temp_free_i64(t2); + return NO_EXIT; } -static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, - int r2) +#ifndef CONFIG_USER_ONLY +static ExitStatus op_spka(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + check_privileged(s); + tcg_gen_shri_i64(o->in2, o->in2, 4); + tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, PSW_SHIFT_KEY - 4, 4); + return NO_EXIT; +} - LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); - switch (op) { - case 0x0: /* LPGR R1,R2 [RRE] */ - case 0x1: /* LNGR R1,R2 [RRE] */ - case 0x2: /* LTGR R1,R2 [RRE] */ - case 0x3: /* LCGR R1,R2 [RRE] */ - case 0x10: /* LPGFR R1,R2 [RRE] */ - case 0x11: /* LNFGR R1,R2 [RRE] */ - case 0x12: /* LTGFR R1,R2 [RRE] */ - case 0x13: /* LCGFR R1,R2 [RRE] */ - if (op & 0x10) { - tmp = load_reg32_i64(r2); - } else { - tmp = load_reg(r2); - } - switch (op & 0xf) { - case 0x0: /* LP?GR */ - set_cc_abs64(s, tmp); - gen_helper_abs_i64(tmp, tmp); - store_reg(r1, tmp); - break; - case 0x1: /* LN?GR */ - set_cc_nabs64(s, tmp); - gen_helper_nabs_i64(tmp, tmp); - store_reg(r1, tmp); - break; - case 0x2: /* LT?GR */ - if (r1 != r2) { - store_reg(r1, tmp); - } - set_cc_s64(s, tmp); - break; - case 0x3: /* LC?GR */ - tcg_gen_neg_i64(regs[r1], tmp); - set_cc_comp64(s, regs[r1]); - break; - } - tcg_temp_free_i64(tmp); - break; - case 0x4: /* LGR R1,R2 [RRE] */ - store_reg(r1, regs[r2]); - break; - case 0x6: /* LGBR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x8: /* AGR R1,R2 [RRE] */ - case 0xa: /* ALGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x8: - set_cc_add64(s, tmp, tmp2, tmp3); - break; - case 0xa: - set_cc_addu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); +static ExitStatus op_sske(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sske(cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ssm(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8); + return NO_EXIT; +} + +static ExitStatus op_stap(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* ??? Surely cpu address != cpu number. In any case the previous + version of this stored more than the required half-word, so it + is unlikely this has ever been tested. */ + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + return NO_EXIT; +} + +static ExitStatus op_stck(DisasContext *s, DisasOps *o) +{ + gen_helper_stck(o->out, cpu_env); + /* ??? We don't implement clock states. */ + gen_op_movi_cc(s, 0); + return NO_EXIT; +} + +static ExitStatus op_stcke(DisasContext *s, DisasOps *o) +{ + TCGv_i64 c1 = tcg_temp_new_i64(); + TCGv_i64 c2 = tcg_temp_new_i64(); + gen_helper_stck(c1, cpu_env); + /* Shift the 64-bit value into its place as a zero-extended + 104-bit value. Note that "bit positions 64-103 are always + non-zero so that they compare differently to STCK"; we set + the least significant bit to 1. */ + tcg_gen_shli_i64(c2, c1, 56); + tcg_gen_shri_i64(c1, c1, 8); + tcg_gen_ori_i64(c2, c2, 0x10000); + tcg_gen_qemu_st64(c1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 8); + tcg_gen_qemu_st64(c2, o->in2, get_mem_index(s)); + tcg_temp_free_i64(c1); + tcg_temp_free_i64(c2); + /* ??? We don't implement clock states. */ + gen_op_movi_cc(s, 0); + return NO_EXIT; +} + +static ExitStatus op_sckc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sckc(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_stckc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_stckc(o->out, cpu_env); + return NO_EXIT; +} + +static ExitStatus op_stctg(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_stctg(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + +static ExitStatus op_stctl(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_stctl(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + +static ExitStatus op_stidp(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + return NO_EXIT; +} + +static ExitStatus op_spt(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_spt(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_stfl(DisasContext *s, DisasOps *o) +{ + TCGv_i64 f, a; + /* We really ought to have more complete indication of facilities + that we implement. Address this when STFLE is implemented. */ + check_privileged(s); + f = tcg_const_i64(0xc0000000); + a = tcg_const_i64(200); + tcg_gen_qemu_st32(f, a, get_mem_index(s)); + tcg_temp_free_i64(f); + tcg_temp_free_i64(a); + return NO_EXIT; +} + +static ExitStatus op_stpt(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_stpt(o->out, cpu_env); + return NO_EXIT; +} + +static ExitStatus op_stsi(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_spx(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_spx(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_subchannel(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* Not operational. */ + gen_op_movi_cc(s, 3); + return NO_EXIT; +} + +static ExitStatus op_stpx(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, psa)); + tcg_gen_andi_i64(o->out, o->out, 0x7fffe000); + return NO_EXIT; +} + +static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) +{ + uint64_t i2 = get_field(s->fields, i2); + TCGv_i64 t; + + check_privileged(s); + + /* It is important to do what the instruction name says: STORE THEN. + If we let the output hook perform the store then if we fault and + restart, we'll have the wrong SYSTEM MASK in place. */ + t = tcg_temp_new_i64(); + tcg_gen_shri_i64(t, psw_mask, 56); + tcg_gen_qemu_st8(t, o->addr1, get_mem_index(s)); + tcg_temp_free_i64(t); + + if (s->fields->op == 0xac) { + tcg_gen_andi_i64(psw_mask, psw_mask, + (i2 << 56) | 0x00ffffffffffffffull); + } else { + tcg_gen_ori_i64(psw_mask, psw_mask, i2 << 56); + } + return NO_EXIT; +} + +static ExitStatus op_stura(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_stura(cpu_env, o->in2, o->in1); + return NO_EXIT; +} +#endif + +static ExitStatus op_st8(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st8(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st16(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st16(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st32(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st32(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st64(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st64(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_stam(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_stam(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + +static ExitStatus op_stcm(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int pos, base = s->insn->data; + TCGv_i64 tmp = tcg_temp_new_i64(); + + pos = base + ctz32(m3) * 8; + switch (m3) { + case 0xf: + /* Effectively a 32-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st32(tmp, o->in2, get_mem_index(s)); break; - case 0x9: /* SGR R1,R2 [RRE] */ - case 0xb: /* SLGR R1,R2 [RRE] */ - case 0x1b: /* SLGFR R1,R2 [RRE] */ - case 0x19: /* SGFR R1,R2 [RRE] */ - tmp = load_reg(r1); - switch (op) { - case 0x1b: - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x19: - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - default: - tmp2 = load_reg(r2); - break; - } - tmp3 = tcg_temp_new_i64(); - tcg_gen_sub_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x9: - case 0x19: - set_cc_sub64(s, tmp, tmp2, tmp3); - break; - case 0xb: - case 0x1b: - set_cc_subu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); + + case 0xc: + case 0x6: + case 0x3: + /* Effectively a 16-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st16(tmp, o->in2, get_mem_index(s)); break; - case 0xc: /* MSGR R1,R2 [RRE] */ - case 0x1c: /* MSGFR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - if (op == 0x1c) { - tcg_gen_ext32s_i64(tmp2, tmp2); - } - tcg_gen_mul_i64(tmp, tmp, tmp2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); + + case 0x8: + case 0x4: + case 0x2: + case 0x1: + /* Effectively an 8-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s)); break; - case 0xd: /* DSGR R1,R2 [RRE] */ - case 0x1d: /* DSGFR R1,R2 [RRE] */ - tmp = load_reg(r1 + 1); - if (op == 0xd) { - tmp2 = load_reg(r2); - } else { - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); + + default: + /* This is going to be a sequence of shifts and stores. */ + pos = base + 32 - 8; + while (m3) { + if (m3 & 0x8) { + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 1); + } + m3 = (m3 << 1) & 0xf; + pos -= 8; } - tmp3 = tcg_temp_new_i64(); - tcg_gen_div_i64(tmp3, tmp, tmp2); - store_reg(r1 + 1, tmp3); - tcg_gen_rem_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); break; - case 0x14: /* LGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x16: /* LLGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x17: /* LLGTR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0x7fffffffUL); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x18: /* AGFR R1,R2 [RRE] */ - case 0x1a: /* ALGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - if (op == 0x18) { - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - } else { - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - } - tcg_temp_free_i32(tmp32_1); - tmp = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - if (op == 0x18) { - set_cc_add64(s, tmp, tmp2, tmp3); + } + tcg_temp_free_i64(tmp); + return NO_EXIT; +} + +static ExitStatus op_stm(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + int size = s->insn->data; + TCGv_i64 tsize = tcg_const_i64(size); + + while (1) { + if (size == 8) { + tcg_gen_qemu_st64(regs[r1], o->in2, get_mem_index(s)); } else { - set_cc_addu64(s, tmp, tmp2, tmp3); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x0f: /* LRVGR R1,R2 [RRE] */ - tcg_gen_bswap64_i64(regs[r1], regs[r2]); - break; - case 0x1f: /* LRVR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x20: /* CGR R1,R2 [RRE] */ - case 0x30: /* CGFR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - if (op == 0x30) { - tcg_gen_ext32s_i64(tmp2, tmp2); + tcg_gen_qemu_st32(regs[r1], o->in2, get_mem_index(s)); } - tmp = load_reg(r1); - cmp_s64(s, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x21: /* CLGR R1,R2 [RRE] */ - case 0x31: /* CLGFR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - if (op == 0x31) { - tcg_gen_ext32u_i64(tmp2, tmp2); - } - tmp = load_reg(r1); - cmp_u64(s, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x26: /* LBR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_ext8s_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x27: /* LHR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_ext16s_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x80: /* NGR R1,R2 [RRE] */ - case 0x81: /* OGR R1,R2 [RRE] */ - case 0x82: /* XGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - switch (op) { - case 0x80: - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x81: - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - case 0x82: - tcg_gen_xor_i64(tmp, tmp, tmp2); + if (r1 == r3) { break; - default: - tcg_abort(); } - store_reg(r1, tmp); - set_cc_nz_u64(s, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x83: /* FLOGR R1,R2 [RRE] */ - tmp = load_reg(r2); - tmp32_1 = tcg_const_i32(r1); - gen_helper_flogr(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; - case 0x84: /* LLGCR R1,R2 [RRE] */ - tmp = load_reg(r2); - tcg_gen_andi_i64(tmp, tmp, 0xff); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x85: /* LLGHR R1,R2 [RRE] */ - tmp = load_reg(r2); - tcg_gen_andi_i64(tmp, tmp, 0xffff); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x87: /* DLGR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - gen_helper_dlg(cpu_env, tmp32_1, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; - case 0x88: /* ALCGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = tcg_temp_new_i64(); - gen_op_calc_cc(s); - tcg_gen_extu_i32_i64(tmp3, cc_op); - tcg_gen_shri_i64(tmp3, tmp3, 1); - tcg_gen_andi_i64(tmp3, tmp3, 1); - tcg_gen_add_i64(tmp3, tmp2, tmp3); - tcg_gen_add_i64(tmp3, tmp, tmp3); - store_reg(r1, tmp3); - set_cc_addu64(s, tmp, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x89: /* SLBGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp32_1 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, tmp, tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x94: /* LLCR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xff); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x95: /* LLHR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xffff); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x96: /* MLR R1,R2 [RRE] */ - /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x97: /* DLR R1,R2 [RRE] */ - /* reg(r1) = reg(r1, r1+1) % reg(r2) */ - /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp3); - - tcg_gen_rem_i64(tmp3, tmp, tmp2); - tcg_gen_div_i64(tmp, tmp, tmp2); - store_reg32_i64((r1 + 1) & 15, tmp); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x98: /* ALCR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - store_reg32(r1, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x99: /* SLBR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp32_2 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_2, tmp32_1); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - default: - LOG_DISAS("illegal b9 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); - break; + tcg_gen_add_i64(o->in2, o->in2, tsize); + r1 = (r1 + 1) & 15; } + + tcg_temp_free_i64(tsize); + return NO_EXIT; } -static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) +static ExitStatus op_stmh(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2; - uint64_t target = s->pc + i2 * 2LL; - int l1; - - LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 t32 = tcg_const_i64(32); - switch (op) { - case 0: /* larl r1, i2 */ - tmp = tcg_const_i64(target); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x1: /* LGFI R1,I2 [RIL] */ - tmp = tcg_const_i64((int64_t)i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x4: /* BRCL M1,I2 [RIL] */ - /* m1 & (1 << (3 - cc)) */ - tmp32_1 = tcg_const_i32(3); - tmp32_2 = tcg_const_i32(1); - gen_op_calc_cc(s); - tcg_gen_sub_i32(tmp32_1, tmp32_1, cc_op); - tcg_gen_shl_i32(tmp32_2, tmp32_2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tmp32_1 = tcg_const_i32(r1); /* m1 == r1 */ - tcg_gen_and_i32(tmp32_1, tmp32_1, tmp32_2); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1); - gen_goto_tb(s, 0, target); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 6); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x5: /* brasl r1, i2 */ - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 6)); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - gen_goto_tb(s, 0, target); - s->is_jmp = DISAS_TB_JUMP; - break; - case 0x7: /* XILF R1,I2 [RIL] */ - case 0xb: /* NILF R1,I2 [RIL] */ - case 0xd: /* OILF R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - switch (op) { - case 0x7: - tcg_gen_xori_i32(tmp32_1, tmp32_1, (uint32_t)i2); - break; - case 0xb: - tcg_gen_andi_i32(tmp32_1, tmp32_1, (uint32_t)i2); + while (1) { + tcg_gen_shl_i64(t, regs[r1], t32); + tcg_gen_qemu_st32(t, o->in2, get_mem_index(s)); + if (r1 == r3) { break; - case 0xd: - tcg_gen_ori_i32(tmp32_1, tmp32_1, (uint32_t)i2); - break; - default: - tcg_abort(); } - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x9: /* IILF R1,I2 [RIL] */ - tmp32_1 = tcg_const_i32((uint32_t)i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0xa: /* NIHF R1,I2 [RIL] */ - tmp = load_reg(r1); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_andi_i64(tmp, tmp, (((uint64_t)((uint32_t)i2)) << 32) - | 0xffffffffULL); - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp, tmp, 32); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; - case 0xe: /* LLIHF R1,I2 [RIL] */ - tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xf: /* LLILF R1,I2 [RIL] */ - tmp = tcg_const_i64((uint32_t)i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - default: - LOG_DISAS("illegal c0 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); - break; + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + tcg_temp_free_i64(t32); + return NO_EXIT; } -static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) +static ExitStatus op_srst(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + potential_page_fault(s); + gen_helper_srst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} - switch (op) { - case 0x4: /* SLGFI R1,I2 [RIL] */ - case 0xa: /* ALGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64((uint64_t)(uint32_t)i2); - tmp3 = tcg_temp_new_i64(); - switch (op) { - case 0x4: - tcg_gen_sub_i64(tmp3, tmp, tmp2); - set_cc_subu64(s, tmp, tmp2, tmp3); - break; - case 0xa: - tcg_gen_add_i64(tmp3, tmp, tmp2); - set_cc_addu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x5: /* SLFI R1,I2 [RIL] */ - case 0xb: /* ALFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(i2); - tmp32_3 = tcg_temp_new_i32(); - switch (op) { - case 0x5: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0xb: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xc: /* CGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - cmp_s64c(s, tmp, (int64_t)i2); - tcg_temp_free_i64(tmp); - break; - case 0xe: /* CLGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - cmp_u64c(s, tmp, (uint64_t)(uint32_t)i2); - tcg_temp_free_i64(tmp); - break; - case 0xd: /* CFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - cmp_s32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); - break; - case 0xf: /* CLFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - cmp_u32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); - break; - default: - LOG_DISAS("illegal c2 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); - break; - } +static ExitStatus op_sub(DisasContext *s, DisasOps *o) +{ + tcg_gen_sub_i64(o->out, o->in1, o->in2); + return NO_EXIT; } -static void gen_and_or_xor_i32(int opc, TCGv_i32 tmp, TCGv_i32 tmp2) +static ExitStatus op_subb(DisasContext *s, DisasOps *o) { - switch (opc & 0xf) { - case 0x4: - tcg_gen_and_i32(tmp, tmp, tmp2); - break; - case 0x6: - tcg_gen_or_i32(tmp, tmp, tmp2); - break; - case 0x7: - tcg_gen_xor_i32(tmp, tmp, tmp2); - break; - default: - tcg_abort(); + DisasCompare cmp; + TCGv_i64 borrow; + + tcg_gen_sub_i64(o->out, o->in1, o->in2); + + /* The !borrow flag is the msb of CC. Since we want the inverse of + that, we ask for a comparison of CC=0 | CC=1 -> mask of 8 | 4. */ + disas_jcc(s, &cmp, 8 | 4); + borrow = tcg_temp_new_i64(); + if (cmp.is_64) { + tcg_gen_setcond_i64(cmp.cond, borrow, cmp.u.s64.a, cmp.u.s64.b); + } else { + TCGv_i32 t = tcg_temp_new_i32(); + tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b); + tcg_gen_extu_i32_i64(borrow, t); + tcg_temp_free_i32(t); } + free_compare(&cmp); + + tcg_gen_sub_i64(o->out, o->out, borrow); + tcg_temp_free_i64(borrow); + return NO_EXIT; } -static void disas_s390_insn(CPUS390XState *env, DisasContext *s) +static ExitStatus op_svc(DisasContext *s, DisasOps *o) { - TCGv_i64 tmp, tmp2, tmp3, tmp4; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3, tmp32_4; - unsigned char opc; - uint64_t insn; - int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; - TCGv_i32 vl; - int ilc; - int l1; + TCGv_i32 t; - opc = cpu_ldub_code(env, s->pc); - LOG_DISAS("opc 0x%x\n", opc); + update_psw_addr(s); + update_cc_op(s); - ilc = get_ilc(opc); + t = tcg_const_i32(get_field(s->fields, i1) & 0xff); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code)); + tcg_temp_free_i32(t); + + t = tcg_const_i32(s->next_pc - s->pc); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); + tcg_temp_free_i32(t); + + gen_exception(EXCP_SVC); + return EXIT_NORETURN; +} + +static ExitStatus op_tceb(DisasContext *s, DisasOps *o) +{ + gen_helper_tceb(cc_op, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_tcdb(DisasContext *s, DisasOps *o) +{ + gen_helper_tcdb(cc_op, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_tcxb(DisasContext *s, DisasOps *o) +{ + gen_helper_tcxb(cc_op, o->out, o->out2, o->in2); + set_cc_static(s); + return NO_EXIT; +} - switch (opc) { #ifndef CONFIG_USER_ONLY - case 0x01: /* SAM */ - insn = ld_code2(env, s->pc); - /* set addressing mode, but we only do 64bit anyways */ - break; +static ExitStatus op_tprot(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_tprot(cc_op, o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} #endif - case 0x6: /* BCTR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - - if (r2) { - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1); - - /* not taking the branch, jump to after the instruction */ - gen_goto_tb(s, 0, s->pc + 2); - gen_set_label(l1); - - /* take the branch, move R2 into psw.addr */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_mov_i64(psw_addr, tmp); - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - } - break; - case 0x7: /* BCR M1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - if (r2) { - tmp = load_reg(r2); - gen_bcr(s, r1, tmp, s->pc); - tcg_temp_free_i64(tmp); - s->is_jmp = DISAS_TB_JUMP; - } else { - /* XXX: "serialization and checkpoint-synchronization function"? */ - } - break; - case 0xa: /* SVC I [RR] */ - insn = ld_code2(env, s->pc); - debug_insn(insn); - i = insn & 0xff; - update_psw_addr(s); - gen_op_calc_cc(s); - tmp32_1 = tcg_const_i32(i); - tmp32_2 = tcg_const_i32(ilc * 2); - tmp32_3 = tcg_const_i32(EXCP_SVC); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); - tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilc)); - gen_helper_exception(cpu_env, tmp32_3); - s->is_jmp = DISAS_EXCP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xd: /* BASR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 2)); - store_reg(r1, tmp); - if (r2) { - tmp2 = load_reg(r2); - tcg_gen_mov_i64(psw_addr, tmp2); - tcg_temp_free_i64(tmp2); - s->is_jmp = DISAS_JUMP; - } - tcg_temp_free_i64(tmp); - break; - case 0xe: /* MVCL R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_mvcl(cc_op, cpu_env, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x10: /* LPR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - set_cc_abs32(s, tmp32_1); - gen_helper_abs_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x11: /* LNR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - set_cc_nabs32(s, tmp32_1); - gen_helper_nabs_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x12: /* LTR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - if (r1 != r2) { - store_reg32(r1, tmp32_1); - } - set_cc_s32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x13: /* LCR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - tcg_gen_neg_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - set_cc_comp32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x14: /* NR R1,R2 [RR] */ - case 0x16: /* OR R1,R2 [RR] */ - case 0x17: /* XR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_2 = load_reg32(r2); - tmp32_1 = load_reg32(r1); - gen_and_or_xor_i32(opc, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x18: /* LR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x15: /* CLR R1,R2 [RR] */ - case 0x19: /* CR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - if (opc == 0x15) { - cmp_u32(s, tmp32_1, tmp32_2); - } else { - cmp_s32(s, tmp32_1, tmp32_2); + +static ExitStatus op_tr(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_tr(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_unpk(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_unpk(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + +static ExitStatus op_xc(DisasContext *s, DisasOps *o) +{ + int d1 = get_field(s->fields, d1); + int d2 = get_field(s->fields, d2); + int b1 = get_field(s->fields, b1); + int b2 = get_field(s->fields, b2); + int l = get_field(s->fields, l1); + TCGv_i32 t32; + + o->addr1 = get_address(s, 0, b1, d1); + + /* If the addresses are identical, this is a store/memset of zero. */ + if (b1 == b2 && d1 == d2 && (l + 1) <= 32) { + o->in2 = tcg_const_i64(0); + + l++; + while (l >= 8) { + tcg_gen_qemu_st64(o->in2, o->addr1, get_mem_index(s)); + l -= 8; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 8); + } } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x1a: /* AR R1,R2 [RR] */ - case 0x1e: /* ALR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_3); - if (opc == 0x1a) { - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - } else { - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); + if (l >= 4) { + tcg_gen_qemu_st32(o->in2, o->addr1, get_mem_index(s)); + l -= 4; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 4); + } } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x1b: /* SR R1,R2 [RR] */ - case 0x1f: /* SLR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_3); - if (opc == 0x1b) { - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - } else { - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); + if (l >= 2) { + tcg_gen_qemu_st16(o->in2, o->addr1, get_mem_index(s)); + l -= 2; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 2); + } } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x1c: /* MR R1,R2 [RR] */ - /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32s_i64(tmp2, tmp2); - tcg_gen_ext32s_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x1d: /* DR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - tmp32_3 = load_reg32(r2); - - tmp = tcg_temp_new_i64(); /* dividend */ - tmp2 = tcg_temp_new_i64(); /* divisor */ - tmp3 = tcg_temp_new_i64(); - - /* dividend is r(r1 << 32) | r(r1 + 1) */ - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_2); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - - /* divisor is r(r2) */ - tcg_gen_ext_i32_i64(tmp2, tmp32_3); - - tcg_gen_div_i64(tmp3, tmp, tmp2); - tcg_gen_rem_i64(tmp, tmp, tmp2); - - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - tcg_gen_trunc_i64_i32(tmp32_2, tmp3); - - store_reg32(r1, tmp32_1); /* remainder */ - store_reg32(r1 + 1, tmp32_2); /* quotient */ - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x28: /* LDR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp = load_freg(r2); - store_freg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x38: /* LER R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_freg32(r2); - store_freg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x40: /* STH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st16(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x41: /* la */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */ - tcg_temp_free_i64(tmp); - break; - case 0x42: /* STC R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x43: /* IC R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - store_reg8(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x44: /* EX R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tmp3 = tcg_const_i64(s->pc + 4); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_ex(cc_op, cpu_env, cc_op, tmp2, tmp, tmp3); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x46: /* BCT R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tcg_temp_free_i64(tmp); - - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1); - - /* not taking the branch, jump to after the instruction */ - gen_goto_tb(s, 0, s->pc + 4); - gen_set_label(l1); - - /* take the branch, move R2 into psw.addr */ - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tcg_gen_mov_i64(psw_addr, tmp); - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x47: /* BC M1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - gen_bcr(s, r1, tmp, s->pc + 4); - tcg_temp_free_i64(tmp); - s->is_jmp = DISAS_TB_JUMP; - break; - case 0x48: /* LH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x49: /* CH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - cmp_s32(s, tmp32_1, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x4a: /* AH R1,D2(X2,B2) [RX] */ - case 0x4b: /* SH R1,D2(X2,B2) [RX] */ - case 0x4c: /* MH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - switch (opc) { - case 0x4a: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x4b: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x4c: - tcg_gen_mul_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); + if (l) { + tcg_gen_qemu_st8(o->in2, o->addr1, get_mem_index(s)); } - store_reg32(r1, tmp32_3); + gen_op_movi_cc(s, 0); + return NO_EXIT; + } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_const_i64(pc_to_link_info(s, s->pc + 4)); - store_reg(r1, tmp2); - tcg_gen_mov_i64(psw_addr, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - s->is_jmp = DISAS_JUMP; - break; - case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp32_1, regs[r1]); - gen_helper_cvd(tmp2, tmp32_1); - tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x50: /* st r1, d2(x2, b2) */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x55: /* CL R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r1); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - cmp_u32(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x54: /* N R1,D2(X2,B2) [RX] */ - case 0x56: /* O R1,D2(X2,B2) [RX] */ - case 0x57: /* X R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - gen_and_or_xor_i32(opc, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x58: /* l r1, d2(x2, b2) */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x59: /* C R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r1); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - cmp_s32(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x5a: /* A R1,D2(X2,B2) [RX] */ - case 0x5b: /* S R1,D2(X2,B2) [RX] */ - case 0x5e: /* AL R1,D2(X2,B2) [RX] */ - case 0x5f: /* SL R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp); - switch (opc) { - case 0x5a: - case 0x5e: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - break; - case 0x5b: - case 0x5f: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - switch (opc) { - case 0x5a: - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5e: - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5b: - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5f: - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x5c: /* M R1,D2(X2,B2) [RX] */ - /* reg(r1, r1+1) = reg(r1+1) * *(s32*)addr */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32s_i64(tmp2, tmp2); - tcg_gen_ext32s_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x5d: /* D R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - /* dividend is r(r1 << 32) | r(r1 + 1) */ - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_2); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - - /* divisor is in memory */ - tcg_gen_qemu_ld32s(tmp2, tmp3, get_mem_index(s)); - - /* XXX divisor == 0 -> FixP divide exception */ - - tcg_gen_div_i64(tmp3, tmp, tmp2); - tcg_gen_rem_i64(tmp, tmp, tmp2); - - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - tcg_gen_trunc_i64_i32(tmp32_2, tmp3); - - store_reg32(r1, tmp32_1); /* remainder */ - store_reg32(r1 + 1, tmp32_2); /* quotient */ - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x60: /* STD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_freg(r1); - tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x68: /* LD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); - store_freg(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); + /* But in general we'll defer to a helper. */ + o->in2 = get_address(s, 0, b2, d2); + t32 = tcg_const_i32(l); + potential_page_fault(s); + gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2); + tcg_temp_free_i32(t32); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_xor(DisasContext *s, DisasOps *o) +{ + tcg_gen_xor_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_xori(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_xor_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + +static ExitStatus op_zero(DisasContext *s, DisasOps *o) +{ + o->out = tcg_const_i64(0); + return NO_EXIT; +} + +static ExitStatus op_zero2(DisasContext *s, DisasOps *o) +{ + o->out = tcg_const_i64(0); + o->out2 = o->out; + o->g_out2 = true; + return NO_EXIT; +} + +/* ====================================================================== */ +/* The "Cc OUTput" generators. Given the generated output (and in some cases + the original inputs), update the various cc data structures in order to + be able to compute the new condition code. */ + +static void cout_abs32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_ABS_32, o->out); +} + +static void cout_abs64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_ABS_64, o->out); +} + +static void cout_adds32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADD_32, o->in1, o->in2, o->out); +} + +static void cout_adds64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADD_64, o->in1, o->in2, o->out); +} + +static void cout_addu32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDU_32, o->in1, o->in2, o->out); +} + +static void cout_addu64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); +} + +static void cout_addc32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDC_32, o->in1, o->in2, o->out); +} + +static void cout_addc64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDC_64, o->in1, o->in2, o->out); +} + +static void cout_cmps32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2); +} + +static void cout_cmps64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTGT_64, o->in1, o->in2); +} + +static void cout_cmpu32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_32, o->in1, o->in2); +} + +static void cout_cmpu64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2); +} + +static void cout_f32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F32, o->out); +} + +static void cout_f64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F64, o->out); +} + +static void cout_f128(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_NZ_F128, o->out, o->out2); +} + +static void cout_nabs32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NABS_32, o->out); +} + +static void cout_nabs64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NABS_64, o->out); +} + +static void cout_neg32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_COMP_32, o->out); +} + +static void cout_neg64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_COMP_64, o->out); +} + +static void cout_nz32(DisasContext *s, DisasOps *o) +{ + tcg_gen_ext32u_i64(cc_dst, o->out); + gen_op_update1_cc_i64(s, CC_OP_NZ, cc_dst); +} + +static void cout_nz64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ, o->out); +} + +static void cout_s32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_LTGT0_32, o->out); +} + +static void cout_s64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, o->out); +} + +static void cout_subs32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out); +} + +static void cout_subs64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUB_64, o->in1, o->in2, o->out); +} + +static void cout_subu32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBU_32, o->in1, o->in2, o->out); +} + +static void cout_subu64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out); +} + +static void cout_subb32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBB_32, o->in1, o->in2, o->out); +} + +static void cout_subb64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBB_64, o->in1, o->in2, o->out); +} + +static void cout_tm32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_TM_32, o->in1, o->in2); +} + +static void cout_tm64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_TM_64, o->in1, o->in2); +} + +/* ====================================================================== */ +/* The "PREPeration" generators. These initialize the DisasOps.OUT fields + with the TCG register to which we will write. Used in combination with + the "wout" generators, in some cases we need a new temporary, and in + some cases we can write to a TCG global. */ + +static void prep_new(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = tcg_temp_new_i64(); +} +#define SPEC_prep_new 0 + +static void prep_new_P(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = tcg_temp_new_i64(); + o->out2 = tcg_temp_new_i64(); +} +#define SPEC_prep_new_P 0 + +static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = regs[get_field(f, r1)]; + o->g_out = true; +} +#define SPEC_prep_r1 0 + +static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + o->out = regs[r1]; + o->out2 = regs[r1 + 1]; + o->g_out = o->g_out2 = true; +} +#define SPEC_prep_r1_P SPEC_r1_even + +static void prep_f1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = fregs[get_field(f, r1)]; + o->g_out = true; +} +#define SPEC_prep_f1 0 + +static void prep_x1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + o->out = fregs[r1]; + o->out2 = fregs[r1 + 2]; + o->g_out = o->g_out2 = true; +} +#define SPEC_prep_x1 SPEC_r1_f128 + +/* ====================================================================== */ +/* The "Write OUTput" generators. These generally perform some non-trivial + copy of data to TCG globals, or to main memory. The trivial cases are + generally handled by having a "prep" generator install the TCG global + as the destination of the operation. */ + +static void wout_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_reg(get_field(f, r1), o->out); +} +#define SPEC_wout_r1 0 + +static void wout_r1_8(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8); +} +#define SPEC_wout_r1_8 0 + +static void wout_r1_16(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 16); +} +#define SPEC_wout_r1_16 0 + +static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_reg32_i64(get_field(f, r1), o->out); +} +#define SPEC_wout_r1_32 0 + +static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + store_reg32_i64(r1, o->out); + store_reg32_i64(r1 + 1, o->out2); +} +#define SPEC_wout_r1_P32 SPEC_r1_even + +static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + store_reg32_i64(r1 + 1, o->out); + tcg_gen_shri_i64(o->out, o->out, 32); + store_reg32_i64(r1, o->out); +} +#define SPEC_wout_r1_D32 SPEC_r1_even + +static void wout_e1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_freg32_i64(get_field(f, r1), o->out); +} +#define SPEC_wout_e1 0 + +static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_freg(get_field(f, r1), o->out); +} +#define SPEC_wout_f1 0 + +static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int f1 = get_field(s->fields, r1); + store_freg(f1, o->out); + store_freg(f1 + 2, o->out2); +} +#define SPEC_wout_x1 SPEC_r1_f128 + +static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + if (get_field(f, r1) != get_field(f, r2)) { + store_reg32_i64(get_field(f, r1), o->out); + } +} +#define SPEC_wout_cond_r1r2_32 0 + +static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + if (get_field(f, r1) != get_field(f, r2)) { + store_freg32_i64(get_field(f, r1), o->out); + } +} +#define SPEC_wout_cond_e1e2 0 + +static void wout_m1_8(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st8(o->out, o->addr1, get_mem_index(s)); +} +#define SPEC_wout_m1_8 0 + +static void wout_m1_16(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st16(o->out, o->addr1, get_mem_index(s)); +} +#define SPEC_wout_m1_16 0 + +static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); +} +#define SPEC_wout_m1_32 0 + +static void wout_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s)); +} +#define SPEC_wout_m1_64 0 + +static void wout_m2_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st32(o->out, o->in2, get_mem_index(s)); +} +#define SPEC_wout_m2_32 0 + +/* ====================================================================== */ +/* The "INput 1" generators. These load the first operand to an insn. */ + +static void in1_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r1)); +} +#define SPEC_in1_r1 0 + +static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = regs[get_field(f, r1)]; + o->g_in1 = true; +} +#define SPEC_in1_r1_o 0 + +static void in1_r1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1)]); +} +#define SPEC_in1_r1_32s 0 + +static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]); +} +#define SPEC_in1_r1_32u 0 + +static void in1_r1_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in1, regs[get_field(f, r1)], 32); +} +#define SPEC_in1_r1_sr32 0 + +static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r1) + 1); +} +#define SPEC_in1_r1p1 SPEC_r1_even + +static void in1_r1p1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1) + 1]); +} +#define SPEC_in1_r1p1_32s SPEC_r1_even + +static void in1_r1p1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1) + 1]); +} +#define SPEC_in1_r1p1_32u SPEC_r1_even + +static void in1_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + o->in1 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in1, regs[r1 + 1], regs[r1]); +} +#define SPEC_in1_r1_D32 SPEC_r1_even + +static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r2)); +} +#define SPEC_in1_r2 0 + +static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r3)); +} +#define SPEC_in1_r3 0 + +static void in1_r3_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = regs[get_field(f, r3)]; + o->g_in1 = true; +} +#define SPEC_in1_r3_o 0 + +static void in1_r3_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r3)]); +} +#define SPEC_in1_r3_32s 0 + +static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r3)]); +} +#define SPEC_in1_r3_32u 0 + +static void in1_r3_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r3 = get_field(f, r3); + o->in1 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in1, regs[r3 + 1], regs[r3]); +} +#define SPEC_in1_r3_D32 SPEC_r3_even + +static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_freg32_i64(get_field(f, r1)); +} +#define SPEC_in1_e1 0 + +static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = fregs[get_field(f, r1)]; + o->g_in1 = true; +} +#define SPEC_in1_f1_o 0 + +static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + o->out = fregs[r1]; + o->out2 = fregs[r1 + 2]; + o->g_out = o->g_out2 = true; +} +#define SPEC_in1_x1_o SPEC_r1_f128 + +static void in1_f3_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = fregs[get_field(f, r3)]; + o->g_in1 = true; +} +#define SPEC_in1_f3_o 0 + +static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); +} +#define SPEC_in1_la1 0 + +static void in1_la2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int x2 = have_field(f, x2) ? get_field(f, x2) : 0; + o->addr1 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); +} +#define SPEC_in1_la2 0 + +static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld8u(o->in1, o->addr1, get_mem_index(s)); +} +#define SPEC_in1_m1_8u 0 + +static void in1_m1_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16s(o->in1, o->addr1, get_mem_index(s)); +} +#define SPEC_in1_m1_16s 0 + +static void in1_m1_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16u(o->in1, o->addr1, get_mem_index(s)); +} +#define SPEC_in1_m1_16u 0 + +static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s)); +} +#define SPEC_in1_m1_32s 0 + +static void in1_m1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(o->in1, o->addr1, get_mem_index(s)); +} +#define SPEC_in1_m1_32u 0 + +static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(o->in1, o->addr1, get_mem_index(s)); +} +#define SPEC_in1_m1_64 0 + +/* ====================================================================== */ +/* The "INput 2" generators. These load the second operand to an insn. */ + +static void in2_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = regs[get_field(f, r1)]; + o->g_in2 = true; +} +#define SPEC_in2_r1_o 0 + +static void in2_r1_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r1)]); +} +#define SPEC_in2_r1_16u 0 + +static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r1)]); +} +#define SPEC_in2_r1_32u 0 + +static void in2_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + o->in2 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in2, regs[r1 + 1], regs[r1]); +} +#define SPEC_in2_r1_D32 SPEC_r1_even + +static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_reg(get_field(f, r2)); +} +#define SPEC_in2_r2 0 + +static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = regs[get_field(f, r2)]; + o->g_in2 = true; +} +#define SPEC_in2_r2_o 0 + +static void in2_r2_nz(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r2 = get_field(f, r2); + if (r2 != 0) { + o->in2 = load_reg(r2); + } +} +#define SPEC_in2_r2_nz 0 + +static void in2_r2_8s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext8s_i64(o->in2, regs[get_field(f, r2)]); +} +#define SPEC_in2_r2_8s 0 + +static void in2_r2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext8u_i64(o->in2, regs[get_field(f, r2)]); +} +#define SPEC_in2_r2_8u 0 + +static void in2_r2_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16s_i64(o->in2, regs[get_field(f, r2)]); +} +#define SPEC_in2_r2_16s 0 + +static void in2_r2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r2)]); +} +#define SPEC_in2_r2_16u 0 + +static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_reg(get_field(f, r3)); +} +#define SPEC_in2_r3 0 + +static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in2, regs[get_field(f, r2)]); +} +#define SPEC_in2_r2_32s 0 + +static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r2)]); +} +#define SPEC_in2_r2_32u 0 + +static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_freg32_i64(get_field(f, r2)); +} +#define SPEC_in2_e2 0 + +static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = fregs[get_field(f, r2)]; + o->g_in2 = true; +} +#define SPEC_in2_f2_o 0 + +static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r2 = get_field(f, r2); + o->in1 = fregs[r2]; + o->in2 = fregs[r2 + 2]; + o->g_in1 = o->g_in2 = true; +} +#define SPEC_in2_x2_o SPEC_r2_f128 + +static void in2_ra2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = get_address(s, 0, get_field(f, r2), 0); +} +#define SPEC_in2_ra2 0 + +static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int x2 = have_field(f, x2) ? get_field(f, x2) : 0; + o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); +} +#define SPEC_in2_a2 0 + +static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); +} +#define SPEC_in2_ri2 0 + +static void in2_sh32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + help_l2_shift(s, f, o, 31); +} +#define SPEC_in2_sh32 0 + +static void in2_sh64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + help_l2_shift(s, f, o, 63); +} +#define SPEC_in2_sh64 0 + +static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld8u(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_m2_8u 0 + +static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_m2_16s 0 + +static void in2_m2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_m2_16u 0 + +static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_m2_32s 0 + +static void in2_m2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_m2_32u 0 + +static void in2_m2_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_m2_64 0 + +static void in2_mri2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_mri2_16u 0 + +static void in2_mri2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_mri2_32s 0 + +static void in2_mri2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_mri2_32u 0 + +static void in2_mri2_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); +} +#define SPEC_in2_mri2_64 0 + +static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64(get_field(f, i2)); +} +#define SPEC_in2_i2 0 + +static void in2_i2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint8_t)get_field(f, i2)); +} +#define SPEC_in2_i2_8u 0 + +static void in2_i2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint16_t)get_field(f, i2)); +} +#define SPEC_in2_i2_16u 0 + +static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); +} +#define SPEC_in2_i2_32u 0 + +static void in2_i2_16u_shl(DisasContext *s, DisasFields *f, DisasOps *o) +{ + uint64_t i2 = (uint16_t)get_field(f, i2); + o->in2 = tcg_const_i64(i2 << s->insn->data); +} +#define SPEC_in2_i2_16u_shl 0 + +static void in2_i2_32u_shl(DisasContext *s, DisasFields *f, DisasOps *o) +{ + uint64_t i2 = (uint32_t)get_field(f, i2); + o->in2 = tcg_const_i64(i2 << s->insn->data); +} +#define SPEC_in2_i2_32u_shl 0 + +/* ====================================================================== */ + +/* Find opc within the table of insns. This is formulated as a switch + statement so that (1) we get compile-time notice of cut-paste errors + for duplicated opcodes, and (2) the compiler generates the binary + search tree, rather than us having to post-process the table. */ + +#define C(OPC, NM, FT, FC, I1, I2, P, W, OP, CC) \ + D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, 0) + +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) insn_ ## NM, + +enum DisasInsnEnum { +#include "insn-data.def" +}; + +#undef D +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \ + .opc = OPC, \ + .fmt = FMT_##FT, \ + .fac = FAC_##FC, \ + .spec = SPEC_in1_##I1 | SPEC_in2_##I2 | SPEC_prep_##P | SPEC_wout_##W, \ + .name = #NM, \ + .help_in1 = in1_##I1, \ + .help_in2 = in2_##I2, \ + .help_prep = prep_##P, \ + .help_wout = wout_##W, \ + .help_cout = cout_##CC, \ + .help_op = op_##OP, \ + .data = D \ + }, + +/* Allow 0 to be used for NULL in the table below. */ +#define in1_0 NULL +#define in2_0 NULL +#define prep_0 NULL +#define wout_0 NULL +#define cout_0 NULL +#define op_0 NULL + +#define SPEC_in1_0 0 +#define SPEC_in2_0 0 +#define SPEC_prep_0 0 +#define SPEC_wout_0 0 + +static const DisasInsn insn_info[] = { +#include "insn-data.def" +}; + +#undef D +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) \ + case OPC: return &insn_info[insn_ ## NM]; + +static const DisasInsn *lookup_opc(uint16_t opc) +{ + switch (opc) { +#include "insn-data.def" + default: + return NULL; + } +} + +#undef D +#undef C + +/* Extract a field from the insn. The INSN should be left-aligned in + the uint64_t so that we can more easily utilize the big-bit-endian + definitions we extract from the Principals of Operation. */ + +static void extract_field(DisasFields *o, const DisasField *f, uint64_t insn) +{ + uint32_t r, m; + + if (f->size == 0) { + return; + } + + /* Zero extract the field from the insn. */ + r = (insn << f->beg) >> (64 - f->size); + + /* Sign-extend, or un-swap the field as necessary. */ + switch (f->type) { + case 0: /* unsigned */ break; - case 0x70: /* STE R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_freg32(r1); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); + case 1: /* signed */ + assert(f->size <= 32); + m = 1u << (f->size - 1); + r = (r ^ m) - m; break; - case 0x71: /* MS R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); + case 2: /* dl+dh split, signed 20 bit. */ + r = ((int8_t)r << 12) | (r >> 8); break; - case 0x78: /* LE R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_freg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); + default: + abort(); + } + + /* Validate that the "compressed" encoding we selected above is valid. + I.e. we havn't make two different original fields overlap. */ + assert(((o->presentC >> f->indexC) & 1) == 0); + o->presentC |= 1 << f->indexC; + o->presentO |= 1 << f->indexO; + + o->c[f->indexC] = r; +} + +/* Lookup the insn at the current PC, extracting the operands into O and + returning the info struct for the insn. Returns NULL for invalid insn. */ + +static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, + DisasFields *f) +{ + uint64_t insn, pc = s->pc; + int op, op2, ilen; + const DisasInsn *info; + + insn = ld_code2(env, pc); + op = (insn >> 8) & 0xff; + ilen = get_ilen(op); + s->next_pc = s->pc + ilen; + + switch (ilen) { + case 2: + insn = insn << 48; break; -#ifndef CONFIG_USER_ONLY - case 0x80: /* SSM D2(B2) [S] */ - /* Set System Mask */ - check_privileged(env, s, ilc); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_andi_i64(tmp3, psw_mask, ~0xff00000000000000ULL); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - tcg_gen_shli_i64(tmp2, tmp2, 56); - tcg_gen_or_i64(psw_mask, tmp3, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); + case 4: + insn = ld_code4(env, pc) << 32; break; - case 0x82: /* LPSW D2(B2) [S] */ - /* Load PSW */ - check_privileged(env, s, ilc); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_addi_i64(tmp, tmp, 4); - tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s)); - gen_helper_load_psw(cpu_env, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - /* we need to keep cc_op intact */ - s->is_jmp = DISAS_JUMP; + case 6: + insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); break; - case 0x83: /* DIAG R1,R3,D2 [RS] */ - /* Diagnose call (KVM hypercall) */ - check_privileged(env, s, ilc); - potential_page_fault(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp32_1 = tcg_const_i32(insn & 0xfff); - tmp2 = load_reg(2); - tmp3 = load_reg(1); - gen_helper_diag(tmp2, cpu_env, tmp32_1, tmp2, tmp3); - store_reg(2, tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); + default: + abort(); + } + + /* We can't actually determine the insn format until we've looked up + the full insn opcode. Which we can't do without locating the + secondary opcode. Assume by default that OP2 is at bit 40; for + those smaller insns that don't actually have a secondary opcode + this will correctly result in OP2 = 0. */ + switch (op) { + case 0x01: /* E */ + case 0x80: /* S */ + case 0x82: /* S */ + case 0x93: /* S */ + case 0xb2: /* S, RRF, RRE */ + case 0xb3: /* RRE, RRD, RRF */ + case 0xb9: /* RRE, RRF */ + case 0xe5: /* SSE, SIL */ + op2 = (insn << 8) >> 56; + break; + case 0xa5: /* RI */ + case 0xa7: /* RI */ + case 0xc0: /* RIL */ + case 0xc2: /* RIL */ + case 0xc4: /* RIL */ + case 0xc6: /* RIL */ + case 0xc8: /* SSF */ + case 0xcc: /* RIL */ + op2 = (insn << 12) >> 60; + break; + case 0xd0 ... 0xdf: /* SS */ + case 0xe1: /* SS */ + case 0xe2: /* SS */ + case 0xe8: /* SS */ + case 0xe9: /* SS */ + case 0xea: /* SS */ + case 0xee ... 0xf3: /* SS */ + case 0xf8 ... 0xfd: /* SS */ + op2 = 0; break; -#endif - case 0x88: /* SRL R1,D2(B2) [RS] */ - case 0x89: /* SLL R1,D2(B2) [RS] */ - case 0x8a: /* SRA R1,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp32_2, tmp); - tcg_gen_andi_i32(tmp32_2, tmp32_2, 0x3f); - switch (opc) { - case 0x88: - tcg_gen_shr_i32(tmp32_1, tmp32_1, tmp32_2); - break; - case 0x89: - tcg_gen_shl_i32(tmp32_1, tmp32_1, tmp32_2); - break; - case 0x8a: - tcg_gen_sar_i32(tmp32_1, tmp32_1, tmp32_2); - set_cc_s32(s, tmp32_1); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); + default: + op2 = (insn << 40) >> 56; break; - case 0x8c: /* SRDL R1,D2(B2) [RS] */ - case 0x8d: /* SLDL R1,D2(B2) [RS] */ - case 0x8e: /* SRDA R1,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); /* shift */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - tcg_gen_concat_i32_i64(tmp2, tmp32_2, tmp32_1); /* operand */ - switch (opc) { - case 0x8c: - tcg_gen_shr_i64(tmp2, tmp2, tmp); - break; - case 0x8d: - tcg_gen_shl_i64(tmp2, tmp2, tmp); - break; - case 0x8e: - tcg_gen_sar_i64(tmp2, tmp2, tmp); - set_cc_s64(s, tmp2); - break; + } + + memset(f, 0, sizeof(*f)); + f->op = op; + f->op2 = op2; + + /* Lookup the instruction. */ + info = lookup_opc(op << 8 | op2); + + /* If we found it, extract the operands. */ + if (info != NULL) { + DisasFormat fmt = info->fmt; + int i; + + for (i = 0; i < NUM_C_FIELD; ++i) { + extract_field(f, &format_info[fmt].op[i], insn); } - tcg_gen_shri_i64(tmp, tmp2, 32); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - store_reg32(r1, tmp32_1); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - store_reg32(r1 + 1, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x98: /* LM R1,R3,D2(B2) [RS] */ - case 0x90: /* STM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_const_i64(4); - tmp4 = tcg_const_i64(0xffffffff00000000ULL); - for (i = r1;; i = (i + 1) % 16) { - if (opc == 0x98) { - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_and_i64(regs[i], regs[i], tmp4); - tcg_gen_or_i64(regs[i], regs[i], tmp2); - } else { - tcg_gen_qemu_st32(regs[i], tmp, get_mem_index(s)); - } - if (i == r3) { - break; + } + return info; +} + +static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) +{ + const DisasInsn *insn; + ExitStatus ret = NO_EXIT; + DisasFields f; + DisasOps o; + + /* Search for the insn in the table. */ + insn = extract_insn(env, s, &f); + + /* Not found means unimplemented/illegal opcode. */ + if (insn == NULL) { + qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n", + f.op, f.op2); + gen_illegal_opcode(s); + return EXIT_NORETURN; + } + + /* Check for insn specification exceptions. */ + if (insn->spec) { + int spec = insn->spec, excp = 0, r; + + if (spec & SPEC_r1_even) { + r = get_field(&f, r1); + if (r & 1) { + excp = PGM_SPECIFICATION; } - tcg_gen_add_i64(tmp, tmp, tmp3); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; - case 0x91: /* TM D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_const_i64(i2); - tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s)); - cmp_64(s, tmp, tmp2, CC_OP_TM_32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x92: /* MVI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_const_i64(i2); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x94: /* NI D1(B1),I2 [SI] */ - case 0x96: /* OI D1(B1),I2 [SI] */ - case 0x97: /* XI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - switch (opc) { - case 0x94: - tcg_gen_andi_i64(tmp2, tmp2, i2); - break; - case 0x96: - tcg_gen_ori_i64(tmp2, tmp2, i2); - break; - case 0x97: - tcg_gen_xori_i64(tmp2, tmp2, i2); - break; - default: - tcg_abort(); } - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - set_cc_nz_u64(s, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x95: /* CLI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - cmp_u64c(s, tmp2, i2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x9a: /* LAM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lam(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x9b: /* STAM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stam(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xa5: - insn = ld_code4(env, s->pc); - r1 = (insn >> 20) & 0xf; - op = (insn >> 16) & 0xf; - i2 = insn & 0xffff; - disas_a5(env, s, op, r1, i2); - break; - case 0xa7: - insn = ld_code4(env, s->pc); - r1 = (insn >> 20) & 0xf; - op = (insn >> 16) & 0xf; - i2 = (short)insn; - disas_a7(env, s, op, r1, i2); - break; - case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_mvcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xa9: /* CLCLE R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_clcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; -#ifndef CONFIG_USER_ONLY - case 0xac: /* STNSM D1(B1),I2 [SI] */ - case 0xad: /* STOSM D1(B1),I2 [SI] */ - check_privileged(env, s, ilc); - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_shri_i64(tmp2, psw_mask, 56); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - if (opc == 0xac) { - tcg_gen_andi_i64(psw_mask, psw_mask, - ((uint64_t)i2 << 56) | 0x00ffffffffffffffULL); - } else { - tcg_gen_ori_i64(psw_mask, psw_mask, (uint64_t)i2 << 56); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ - check_privileged(env, s, ilc); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = load_reg(r3); - tmp32_1 = tcg_const_i32(r1); - potential_page_fault(s); - gen_helper_sigp(cc_op, cpu_env, tmp, tmp32_1, tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0xb1: /* LRA R1,D2(X2, B2) [RX] */ - check_privileged(env, s, ilc); - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = tcg_const_i32(r1); - potential_page_fault(s); - gen_helper_lra(cc_op, cpu_env, tmp, tmp32_1); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; -#endif - case 0xb2: - insn = ld_code4(env, s->pc); - op = (insn >> 16) & 0xff; - switch (op) { - case 0x9c: /* STFPC D2(B2) [S] */ - d2 = insn & 0xfff; - b2 = (insn >> 12) & 0xf; - tmp32_1 = tcg_temp_new_i32(); - tmp = tcg_temp_new_i64(); - tmp2 = get_address(s, 0, b2, d2); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_qemu_st32(tmp, tmp2, get_mem_index(s)); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - default: - disas_b2(env, s, op, insn); - break; + if (spec & SPEC_r2_even) { + r = get_field(&f, r2); + if (r & 1) { + excp = PGM_SPECIFICATION; + } } - break; - case 0xb3: - insn = ld_code4(env, s->pc); - op = (insn >> 16) & 0xff; - r3 = (insn >> 12) & 0xf; /* aka m3 */ - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - disas_b3(env, s, op, r3, r1, r2); - break; -#ifndef CONFIG_USER_ONLY - case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */ - /* Store Control */ - check_privileged(env, s, ilc); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stctl(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */ - /* Load Control */ - check_privileged(env, s, ilc); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lctl(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; -#endif - case 0xb9: - insn = ld_code4(env, s->pc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - op = (insn >> 16) & 0xff; - disas_b9(env, s, op, r1, r2); - break; - case 0xba: /* CS R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_cs(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_clm(cc_op, cpu_env, tmp32_1, tmp32_2, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stcm(cpu_env, tmp32_1, tmp32_2, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xbf: /* ICM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - if (r3 == 15) { - /* effectively a 32-bit load */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = tcg_const_i32(r3); - tcg_gen_qemu_ld32u(tmp, tmp, get_mem_index(s)); - store_reg32_i64(r1, tmp); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - set_cc_icm(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - } else if (r3) { - uint32_t mask = 0x00ffffffUL; - uint32_t shift = 24; - int m3 = r3; - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_const_i32(r3); - tmp32_4 = tcg_const_i32(0); - while (m3) { - if (m3 & 8) { - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - if (shift) { - tcg_gen_shli_i32(tmp32_2, tmp32_2, shift); - } - tcg_gen_andi_i32(tmp32_1, tmp32_1, mask); - tcg_gen_or_i32(tmp32_1, tmp32_1, tmp32_2); - tcg_gen_or_i32(tmp32_4, tmp32_4, tmp32_2); - tcg_gen_addi_i64(tmp, tmp, 1); - } - m3 = (m3 << 1) & 0xf; - mask = (mask >> 8) | 0xff000000UL; - shift -= 8; + if (spec & SPEC_r3_even) { + r = get_field(&f, r3); + if (r & 1) { + excp = PGM_SPECIFICATION; } - store_reg32(r1, tmp32_1); - set_cc_icm(s, tmp32_3, tmp32_4); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i32(tmp32_4); - } else { - /* i.e. env->cc = 0 */ - gen_op_movi_cc(s, 0); } - break; - case 0xc0: - case 0xc2: - insn = ld_code6(env, s->pc); - r1 = (insn >> 36) & 0xf; - op = (insn >> 32) & 0xf; - i2 = (int)insn; - switch (opc) { - case 0xc0: - disas_c0(env, s, op, r1, i2); - break; - case 0xc2: - disas_c2(env, s, op, r1, i2); - break; - default: - tcg_abort(); + if (spec & SPEC_r1_f128) { + r = get_field(&f, r1); + if (r > 13) { + excp = PGM_SPECIFICATION; + } } - break; - case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ - case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ - case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ - case 0xd6: /* OC D1(L,B1),D2(B2) [SS] */ - case 0xd7: /* XC D1(L,B1),D2(B2) [SS] */ - case 0xdc: /* TR D1(L,B1),D2(B2) [SS] */ - case 0xf3: /* UNPK D1(L1,B1),D2(L2,B2) [SS] */ - insn = ld_code6(env, s->pc); - vl = tcg_const_i32((insn >> 32) & 0xff); - b1 = (insn >> 28) & 0xf; - b2 = (insn >> 12) & 0xf; - d1 = (insn >> 16) & 0xfff; - d2 = insn & 0xfff; - tmp = get_address(s, 0, b1, d1); - tmp2 = get_address(s, 0, b2, d2); - switch (opc) { - case 0xd2: - gen_op_mvc(s, (insn >> 32) & 0xff, tmp, tmp2); - break; - case 0xd4: - potential_page_fault(s); - gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xd5: - gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2); - break; - case 0xd6: - potential_page_fault(s); - gen_helper_oc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xd7: - potential_page_fault(s); - gen_helper_xc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xdc: - potential_page_fault(s); - gen_helper_tr(cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xf3: - potential_page_fault(s); - gen_helper_unpk(cpu_env, vl, tmp, tmp2); - break; - default: - tcg_abort(); + if (spec & SPEC_r2_f128) { + r = get_field(&f, r2); + if (r > 13) { + excp = PGM_SPECIFICATION; + } } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; -#ifndef CONFIG_USER_ONLY - case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ - case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ - check_privileged(env, s, ilc); - potential_page_fault(s); - insn = ld_code6(env, s->pc); - r1 = (insn >> 36) & 0xf; - r3 = (insn >> 32) & 0xf; - b1 = (insn >> 28) & 0xf; - d1 = (insn >> 16) & 0xfff; - b2 = (insn >> 12) & 0xf; - d2 = insn & 0xfff; - tmp = load_reg(r1); - /* XXX key in r3 */ - tmp2 = get_address(s, 0, b1, d1); - tmp3 = get_address(s, 0, b2, d2); - if (opc == 0xda) { - gen_helper_mvcp(cc_op, cpu_env, tmp, tmp2, tmp3); - } else { - gen_helper_mvcs(cc_op, cpu_env, tmp, tmp2, tmp3); + if (excp) { + gen_program_exception(s, excp); + return EXIT_NORETURN; } - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; -#endif - case 0xe3: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - x2 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = ((int)((((insn >> 16) & 0xfff) - | ((insn << 4) & 0xff000)) << 12)) >> 12; - disas_e3(env, s, op, r1, x2, b2, d2 ); - break; -#ifndef CONFIG_USER_ONLY - case 0xe5: - /* Test Protection */ - check_privileged(env, s, ilc); - insn = ld_code6(env, s->pc); - debug_insn(insn); - disas_e5(env, s, insn); - break; -#endif - case 0xeb: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - r3 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = ((int)((((insn >> 16) & 0xfff) - | ((insn << 4) & 0xff000)) << 12)) >> 12; - disas_eb(env, s, op, r1, r3, b2, d2); - break; - case 0xed: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - x2 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = (short)((insn >> 16) & 0xfff); - r1b = (insn >> 12) & 0xf; - disas_ed(env, s, op, r1, x2, b2, d2, r1b); - break; - default: - qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); - gen_illegal_opcode(env, s, ilc); - break; } - /* Instruction length is encoded in the opcode */ - s->pc += (ilc * 2); + /* Set up the strutures we use to communicate with the helpers. */ + s->insn = insn; + s->fields = &f; + o.g_out = o.g_out2 = o.g_in1 = o.g_in2 = false; + TCGV_UNUSED_I64(o.out); + TCGV_UNUSED_I64(o.out2); + TCGV_UNUSED_I64(o.in1); + TCGV_UNUSED_I64(o.in2); + TCGV_UNUSED_I64(o.addr1); + + /* Implement the instruction. */ + if (insn->help_in1) { + insn->help_in1(s, &f, &o); + } + if (insn->help_in2) { + insn->help_in2(s, &f, &o); + } + if (insn->help_prep) { + insn->help_prep(s, &f, &o); + } + if (insn->help_op) { + ret = insn->help_op(s, &o); + } + if (insn->help_wout) { + insn->help_wout(s, &f, &o); + } + if (insn->help_cout) { + insn->help_cout(s, &o); + } + + /* Free any temporaries created by the helpers. */ + if (!TCGV_IS_UNUSED_I64(o.out) && !o.g_out) { + tcg_temp_free_i64(o.out); + } + if (!TCGV_IS_UNUSED_I64(o.out2) && !o.g_out2) { + tcg_temp_free_i64(o.out2); + } + if (!TCGV_IS_UNUSED_I64(o.in1) && !o.g_in1) { + tcg_temp_free_i64(o.in1); + } + if (!TCGV_IS_UNUSED_I64(o.in2) && !o.g_in2) { + tcg_temp_free_i64(o.in2); + } + if (!TCGV_IS_UNUSED_I64(o.addr1)) { + tcg_temp_free_i64(o.addr1); + } + + /* Advance to the next instruction. */ + s->pc = s->next_pc; + return ret; } static inline void gen_intermediate_code_internal(CPUS390XState *env, @@ -5121,6 +4745,8 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, int j, lj = -1; int num_insns, max_insns; CPUBreakpoint *bp; + ExitStatus status; + bool do_debug; pc_start = tb->pc; @@ -5129,10 +4755,10 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, pc_start &= 0x7fffffff; } - dc.pc = pc_start; - dc.is_jmp = DISAS_NEXT; dc.tb = tb; + dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; + do_debug = dc.singlestep_enabled = env->singlestep_enabled; gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; @@ -5147,14 +4773,6 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, gen_icount_start(); do { - if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { - QTAILQ_FOREACH(bp, &env->breakpoints, entry) { - if (bp->pc == dc.pc) { - gen_debug(&dc); - break; - } - } - } if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { @@ -5168,7 +4786,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_ctx.gen_opc_instr_start[lj] = 1; tcg_ctx.gen_opc_icount[lj] = num_insns; } - if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + if (++num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); } @@ -5176,36 +4794,58 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_gen_debug_insn_start(dc.pc); } - disas_s390_insn(env, &dc); - - num_insns++; - if (env->singlestep_enabled) { - gen_debug(&dc); + status = NO_EXIT; + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc.pc) { + status = EXIT_PC_STALE; + do_debug = true; + break; + } + } + } + if (status == NO_EXIT) { + status = translate_one(env, &dc); } - } while (!dc.is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end - && dc.pc < next_page_start - && num_insns < max_insns && !env->singlestep_enabled - && !singlestep); - - if (!dc.is_jmp) { - update_psw_addr(&dc); - } - if (singlestep && dc.cc_op != CC_OP_DYNAMIC) { - gen_op_calc_cc(&dc); - } else { - /* next TB starts off with CC_OP_DYNAMIC, so make sure the cc op type - is in env */ - gen_op_set_cc_op(&dc); - } + /* If we reach a page boundary, are single stepping, + or exhaust instruction count, stop generation. */ + if (status == NO_EXIT + && (dc.pc >= next_page_start + || tcg_ctx.gen_opc_ptr >= gen_opc_end + || num_insns >= max_insns + || singlestep + || env->singlestep_enabled)) { + status = EXIT_PC_STALE; + } + } while (status == NO_EXIT); if (tb->cflags & CF_LAST_IO) { gen_io_end(); } - /* Generate the return instruction */ - if (dc.is_jmp != DISAS_TB_JUMP) { - tcg_gen_exit_tb(0); + + switch (status) { + case EXIT_GOTO_TB: + case EXIT_NORETURN: + break; + case EXIT_PC_STALE: + update_psw_addr(&dc); + /* FALLTHRU */ + case EXIT_PC_UPDATED: + /* Next TB starts off with CC_OP_DYNAMIC, so make sure the + cc op type is in env */ + update_cc_op(&dc); + /* Exit the TB, either by raising a debug exception or by return. */ + if (do_debug) { + gen_exception(EXCP_DEBUG); + } else { + tcg_gen_exit_tb(0); + } + break; + default: + abort(); } + gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { @@ -5218,6 +4858,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tb->size = dc.pc - pc_start; tb->icount = num_insns; } + #if defined(S390X_DEBUG_DISAS) if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("IN: %s\n", lookup_symbol(pc_start)); diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index e0838748a9..7aec3043e3 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -2099,7 +2099,7 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_st32_i64, { "ri", "r" } }, { INDEX_op_st_i64, { "re", "r" } }, - { INDEX_op_add_i64, { "r", "0", "re" } }, + { INDEX_op_add_i64, { "r", "r", "re" } }, { INDEX_op_mul_i64, { "r", "0", "re" } }, { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } }, { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } }, diff --git a/tests/Makefile b/tests/Makefile index b09a3437cd..d97a571c8b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -70,22 +70,20 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ tests/test-qmp-commands.o tests/test-visitor-serialization.o -test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) qemu-tool.o -test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o -test-qapi-obj-y += module.o +test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o $(test-obj-y): QEMU_INCLUDES += -Itests -tests/check-qint$(EXESUF): tests/check-qint.o qint.o -tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o -tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o -tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o -tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o -tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) qemu-tool.o -tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) iov.o libqemustub.a -tests/test-aio$(EXESUF): tests/test-aio.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a -tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a -tests/test-iov$(EXESUF): tests/test-iov.o iov.o +tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a +tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a +tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a +tests/check-qlist$(EXESUF): tests/check-qlist.o libqemuutil.a +tests/check-qfloat$(EXESUF): tests/check-qfloat.o libqemuutil.a +tests/check-qjson$(EXESUF): tests/check-qjson.o libqemuutil.a libqemustub.a +tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a +tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a +tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a +tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py @@ -98,18 +96,18 @@ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") -tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) -tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) -tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) -tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) -tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) -tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) -tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) +tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) qapi-types.o qapi-visit.o libqemuutil.a libqemustub.a +tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) -tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) -tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y) -tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/libqtest.o $(trace-obj-y) +tests/rtc-test$(EXESUF): tests/rtc-test.o +tests/m48t59-test$(EXESUF): tests/m48t59-test.o +tests/fdc-test$(EXESUF): tests/fdc-test.o +tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o # QTest rules @@ -117,7 +115,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) libqemustub.a +qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a $(check-qtest-y): $(qtest-obj-y) .PHONY: check-help diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c index 5179681ca5..d79f55472d 100644 --- a/tests/m48t59-test.c +++ b/tests/m48t59-test.c @@ -233,6 +233,11 @@ static void fuzz_registers(void) reg = (uint8_t)g_test_rand_int_range(0, 16); val = (uint8_t)g_test_rand_int_range(0, 256); + if (reg == 7) { + /* watchdog setup register, may trigger system reset, skip */ + continue; + } + cmos_write(reg, val); cmos_read(reg); } diff --git a/tests/rtc-test.c b/tests/rtc-test.c index 02edbf5727..e7123cafbc 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -201,6 +201,10 @@ static void set_year_20xx(void) g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11); g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20); + if (sizeof(time_t) == 4) { + return; + } + /* Set a date in 2080 to ensure there is no year-2038 overflow. */ cmos_write(RTC_REG_A, 0x76); cmos_write(RTC_YEAR, 0x80); diff --git a/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c index 1cfbdb080f..fae49f10eb 100644 --- a/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c @@ -26,8 +26,8 @@ int main() ach = 6, acl = 7; rs = 0xFFFF00FF; rt = 0xFFFF0002; - resulth = 0x05; - resultl = 0xfffe0206; + resulth = 0x06; + resultl = 0x206; __asm ("mthi %0, $ac1\n\t" "mtlo %1, $ac1\n\t" diff --git a/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c index f75699755c..514797cfd1 100644 --- a/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c @@ -23,5 +23,22 @@ int main() assert(ach == resulth); assert(acl == resultl); + ach = 6, acl = 7; + rs = 0xFFFF00FF; + rt = 0xFFFF0002; + resulth = 0x05; + resultl = 0xFFFFFF06; + __asm + ("mthi %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" + "dpax.w.ph $ac1, %2, %3\n\t" + "mfhi %0, $ac1\n\t" + "mflo %1, $ac1\n\t" + : "+r"(ach), "+r"(acl) + : "r"(rs), "r"(rt) + ); + assert(ach == resulth); + assert(acl == resultl); + return 0; } diff --git a/tests/tcg/mips/mips32-dspr2/dps_w_ph.c b/tests/tcg/mips/mips32-dspr2/dps_w_ph.c index 8303643d18..f51f9b9d13 100644 --- a/tests/tcg/mips/mips32-dspr2/dps_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dps_w_ph.c @@ -23,5 +23,22 @@ int main() assert(ach == resulth); assert(acl == resultl); + ach = 6, acl = 7; + rs = 0xFFFF00FF; + rt = 0xFFFF0002; + resulth = 0x05; + resultl = 0xFFFFFE08; + __asm + ("mthi %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" + "dps.w.ph $ac1, %2, %3\n\t" + "mfhi %0, $ac1\n\t" + "mflo %1, $ac1\n\t" + : "+r"(ach), "+r"(acl) + : "r"(rs), "r"(rt) + ); + assert(ach == resulth); + assert(acl == resultl); + return 0; } diff --git a/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c index 6db59a4ccd..bb49a4031d 100644 --- a/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c @@ -9,8 +9,8 @@ int main() rs = 0xBC0123AD; rt = 0x01643721; - resulth = 0x04; - resultl = 0xD751F050; + resulth = 0x05; + resultl = 0xE72F050; __asm ("mthi %0, $ac1\n\t" "mtlo %1, $ac1\n\t" diff --git a/trace-events b/trace-events index 4023a4c094..6eabbac0cc 100644 --- a/trace-events +++ b/trace-events @@ -307,8 +307,6 @@ usb_uhci_frame_loop_stop_idle(void) "" usb_uhci_frame_loop_continue(void) "" usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%04x" usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%04x" -usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%08x" -usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%08x" usb_uhci_queue_add(uint32_t token) "token 0x%x" usb_uhci_queue_del(uint32_t token, const char *reason) "token 0x%x: %s" usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" @@ -735,6 +733,14 @@ mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x" mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64 "" mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)" +# hw/pc87312.c +pc87312_io_read(uint32_t addr, uint32_t val) "read addr=%x val=%x" +pc87312_io_write(uint32_t addr, uint32_t val) "write addr=%x val=%x" +pc87312_info_floppy(uint32_t base) "base 0x%x" +pc87312_info_ide(uint32_t base) "base 0x%x" +pc87312_info_parallel(uint32_t base, uint32_t irq) "base 0x%x, irq %u" +pc87312_info_serial(int n, uint32_t base, uint32_t irq) "id=%d, base 0x%x, irq %u" + # xen-all.c xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx" xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "%#"PRIx64" size %#lx, log_dirty %i" diff --git a/trace/Makefile.objs b/trace/Makefile.objs index b791723696..27fe26b5c2 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -1,12 +1,9 @@ # -*- mode: makefile -*- ###################################################################### -# Auto-generated tracing routines +# Auto-generated header for tracing routines -ifeq ($(TRACE_BACKEND),dtrace) -TRACE_H_EXTRA_DEPS=$(obj)/generated-tracers-dtrace.h -endif -$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp $(TRACE_H_EXTRA_DEPS) +$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --format=h \ @@ -14,6 +11,10 @@ $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) +###################################################################### +# Auto-generated tracing routines (non-DTrace) + +ifneq ($(TRACE_BACKEND),dtrace) $(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp $(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ @@ -23,9 +24,6 @@ $(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h - -ifneq ($(TRACE_BACKEND),dtrace) -trace-obj-y += generated-tracers.o endif @@ -35,36 +33,26 @@ endif # Normal practice is to name DTrace probe file with a '.d' extension # but that gets picked up by QEMU's Makefile as an external dependency # rule file. So we use '.dtrace' instead -$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp -$(obj)/generated-tracers-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak +ifeq ($(TRACE_BACKEND),dtrace) +$(obj)/generated-tracers.dtrace: $(obj)/generated-tracers.dtrace-timestamp +$(obj)/generated-tracers.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --format=d \ --backend=$(TRACE_BACKEND) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) -$(obj)/generated-tracers-dtrace.h: trace/generated-tracers-dtrace.dtrace +$(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers.dtrace $(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@") -$(obj)/generated-tracers-dtrace.o: trace/generated-tracers-dtrace.dtrace - $(call quiet-command,dtrace -o $@ -G -s $<, " GEN $@") - -trace-obj-$(CONFIG_TRACE_DTRACE) += generated-tracers-dtrace.o - - -ifeq ($(LIBTOOL),) -$(obj)/generated-tracers-dtrace.lo: $(obj)/generated-tracers-dtrace.dtrace - @echo "missing libtool. please install and rerun configure."; exit 1 -else -$(obj)/generated-tracers-dtrace.lo: $(obj)/generated-tracers-dtrace.dtrace - $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN $@") +$(obj)/generated-tracers.o: $(obj)/generated-tracers.dtrace endif - ###################################################################### # Backend code -trace-obj-$(CONFIG_TRACE_DEFAULT) += default.o -trace-obj-$(CONFIG_TRACE_SIMPLE) += simple.o -trace-obj-$(CONFIG_TRACE_STDERR) += stderr.o -trace-obj-y += control.o +util-obj-$(CONFIG_TRACE_DEFAULT) += default.o +util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o +util-obj-$(CONFIG_TRACE_STDERR) += stderr.o +util-obj-y += control.o +util-obj-y += generated-tracers.o diff --git a/ui/spice-core.c b/ui/spice-core.c index d83de2a46e..3f2c5650cd 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -417,6 +417,90 @@ static SpiceChannelList *qmp_query_spice_channels(void) return head; } +static QemuOptsList qemu_spice_opts = { + .name = "spice", + .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), + .desc = { + { + .name = "port", + .type = QEMU_OPT_NUMBER, + },{ + .name = "tls-port", + .type = QEMU_OPT_NUMBER, + },{ + .name = "addr", + .type = QEMU_OPT_STRING, + },{ + .name = "ipv4", + .type = QEMU_OPT_BOOL, + },{ + .name = "ipv6", + .type = QEMU_OPT_BOOL, + },{ + .name = "password", + .type = QEMU_OPT_STRING, + },{ + .name = "disable-ticketing", + .type = QEMU_OPT_BOOL, + },{ + .name = "disable-copy-paste", + .type = QEMU_OPT_BOOL, + },{ + .name = "sasl", + .type = QEMU_OPT_BOOL, + },{ + .name = "x509-dir", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-key-file", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-key-password", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-cert-file", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-cacert-file", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-dh-key-file", + .type = QEMU_OPT_STRING, + },{ + .name = "tls-ciphers", + .type = QEMU_OPT_STRING, + },{ + .name = "tls-channel", + .type = QEMU_OPT_STRING, + },{ + .name = "plaintext-channel", + .type = QEMU_OPT_STRING, + },{ + .name = "image-compression", + .type = QEMU_OPT_STRING, + },{ + .name = "jpeg-wan-compression", + .type = QEMU_OPT_STRING, + },{ + .name = "zlib-glz-wan-compression", + .type = QEMU_OPT_STRING, + },{ + .name = "streaming-video", + .type = QEMU_OPT_STRING, + },{ + .name = "agent-mouse", + .type = QEMU_OPT_BOOL, + },{ + .name = "playback-compression", + .type = QEMU_OPT_BOOL, + }, { + .name = "seamless-migration", + .type = QEMU_OPT_BOOL, + }, + { /* end of list */ } + }, +}; + SpiceInfo *qmp_query_spice(Error **errp) { QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); diff --git a/util/Makefile.objs b/util/Makefile.objs new file mode 100644 index 0000000000..5baeb53af6 --- /dev/null +++ b/util/Makefile.objs @@ -0,0 +1,10 @@ +util-obj-y = osdep.o cutils.o qemu-timer-common.o +util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win32.o +util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o +util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o +util-obj-y += bitmap.o bitops.o +util-obj-y += acl.o +util-obj-y += error.o qemu-error.o +util-obj-$(CONFIG_POSIX) += compatfd.o +util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o +util-obj-y += qemu-option.o qemu-progress.o diff --git a/bitmap.c b/util/bitmap.c index 687841dcec..687841dcec 100644 --- a/bitmap.c +++ b/util/bitmap.c diff --git a/bitops.c b/util/bitops.c index 4c3a836a01..4c3a836a01 100644 --- a/bitops.c +++ b/util/bitops.c diff --git a/cache-utils.c b/util/cache-utils.c index b94013a8cb..b94013a8cb 100644 --- a/cache-utils.c +++ b/util/cache-utils.c diff --git a/compatfd.c b/util/compatfd.c index 9cf3f2834d..9cf3f2834d 100644 --- a/compatfd.c +++ b/util/compatfd.c diff --git a/cutils.c b/util/cutils.c index 80bb1dcbf7..80bb1dcbf7 100644 --- a/cutils.c +++ b/util/cutils.c diff --git a/envlist.c b/util/envlist.c index ff99fc44e9..ff99fc44e9 100644 --- a/envlist.c +++ b/util/envlist.c diff --git a/error.c b/util/error.c index 519f6b6ce0..519f6b6ce0 100644 --- a/error.c +++ b/util/error.c diff --git a/event_notifier-posix.c b/util/event_notifier-posix.c index 713d7560d0..713d7560d0 100644 --- a/event_notifier-posix.c +++ b/util/event_notifier-posix.c diff --git a/event_notifier-win32.c b/util/event_notifier-win32.c index 6dbb530cfa..6dbb530cfa 100644 --- a/event_notifier-win32.c +++ b/util/event_notifier-win32.c diff --git a/host-utils.c b/util/host-utils.c index 5e3915abba..5e3915abba 100644 --- a/host-utils.c +++ b/util/host-utils.c diff --git a/module.c b/util/module.c index 7acc33d076..7acc33d076 100644 --- a/module.c +++ b/util/module.c diff --git a/notify.c b/util/notify.c index 7b7692acb2..7b7692acb2 100644 --- a/notify.c +++ b/util/notify.c diff --git a/osdep.c b/util/osdep.c index 5b51a0322e..5b51a0322e 100644 --- a/osdep.c +++ b/util/osdep.c diff --git a/oslib-posix.c b/util/oslib-posix.c index 4f5ec6788b..4f5ec6788b 100644 --- a/oslib-posix.c +++ b/util/oslib-posix.c diff --git a/oslib-win32.c b/util/oslib-win32.c index e7e283e875..e7e283e875 100644 --- a/oslib-win32.c +++ b/util/oslib-win32.c @@ -58,9 +58,10 @@ static struct pathelem *new_entry(const char *root, #define streq(a,b) (strcmp((a), (b)) == 0) /* Not all systems provide this feature */ -#if defined(DT_DIR) && defined(DT_UNKNOWN) +#if defined(DT_DIR) && defined(DT_UNKNOWN) && defined(DT_LNK) # define dirent_type(dirent) ((dirent)->d_type) -# define is_dir_maybe(type) ((type) == DT_DIR || (type) == DT_UNKNOWN) +# define is_dir_maybe(type) \ + ((type) == DT_DIR || (type) == DT_UNKNOWN || (type) == DT_LNK) #else # define dirent_type(dirent) (1) # define is_dir_maybe(type) (type) diff --git a/util/qemu-config.c b/util/qemu-config.c new file mode 100644 index 0000000000..47c81f72d3 --- /dev/null +++ b/util/qemu-config.c @@ -0,0 +1,215 @@ +#include "qemu-common.h" +#include "qemu/error-report.h" +#include "qemu/option.h" +#include "qemu/config-file.h" +#include "hw/qdev.h" +#include "qapi/error.h" + +static QemuOptsList *vm_config_groups[32]; + +static QemuOptsList *find_list(QemuOptsList **lists, const char *group, + Error **errp) +{ + int i; + + for (i = 0; lists[i] != NULL; i++) { + if (strcmp(lists[i]->name, group) == 0) + break; + } + if (lists[i] == NULL) { + error_set(errp, QERR_INVALID_OPTION_GROUP, group); + } + return lists[i]; +} + +QemuOptsList *qemu_find_opts(const char *group) +{ + QemuOptsList *ret; + Error *local_err = NULL; + + ret = find_list(vm_config_groups, group, &local_err); + if (error_is_set(&local_err)) { + error_report("%s\n", error_get_pretty(local_err)); + error_free(local_err); + } + + return ret; +} + +QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) +{ + return find_list(vm_config_groups, group, errp); +} + +void qemu_add_opts(QemuOptsList *list) +{ + int entries, i; + + entries = ARRAY_SIZE(vm_config_groups); + entries--; /* keep list NULL terminated */ + for (i = 0; i < entries; i++) { + if (vm_config_groups[i] == NULL) { + vm_config_groups[i] = list; + return; + } + } + fprintf(stderr, "ran out of space in vm_config_groups"); + abort(); +} + +int qemu_set_option(const char *str) +{ + char group[64], id[64], arg[64]; + QemuOptsList *list; + QemuOpts *opts; + int rc, offset; + + rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset); + if (rc < 3 || str[offset] != '=') { + error_report("can't parse: \"%s\"", str); + return -1; + } + + list = qemu_find_opts(group); + if (list == NULL) { + return -1; + } + + opts = qemu_opts_find(list, id); + if (!opts) { + error_report("there is no %s \"%s\" defined", + list->name, id); + return -1; + } + + if (qemu_opt_set(opts, arg, str+offset+1) == -1) { + return -1; + } + return 0; +} + +struct ConfigWriteData { + QemuOptsList *list; + FILE *fp; +}; + +static int config_write_opt(const char *name, const char *value, void *opaque) +{ + struct ConfigWriteData *data = opaque; + + fprintf(data->fp, " %s = \"%s\"\n", name, value); + return 0; +} + +static int config_write_opts(QemuOpts *opts, void *opaque) +{ + struct ConfigWriteData *data = opaque; + const char *id = qemu_opts_id(opts); + + if (id) { + fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id); + } else { + fprintf(data->fp, "[%s]\n", data->list->name); + } + qemu_opt_foreach(opts, config_write_opt, data, 0); + fprintf(data->fp, "\n"); + return 0; +} + +void qemu_config_write(FILE *fp) +{ + struct ConfigWriteData data = { .fp = fp }; + QemuOptsList **lists = vm_config_groups; + int i; + + fprintf(fp, "# qemu config file\n\n"); + for (i = 0; lists[i] != NULL; i++) { + data.list = lists[i]; + qemu_opts_foreach(data.list, config_write_opts, &data, 0); + } +} + +int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) +{ + char line[1024], group[64], id[64], arg[64], value[1024]; + Location loc; + QemuOptsList *list = NULL; + Error *local_err = NULL; + QemuOpts *opts = NULL; + int res = -1, lno = 0; + + loc_push_none(&loc); + while (fgets(line, sizeof(line), fp) != NULL) { + loc_set_file(fname, ++lno); + if (line[0] == '\n') { + /* skip empty lines */ + continue; + } + if (line[0] == '#') { + /* comment */ + continue; + } + if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) { + /* group with id */ + list = find_list(lists, group, &local_err); + if (error_is_set(&local_err)) { + error_report("%s\n", error_get_pretty(local_err)); + error_free(local_err); + goto out; + } + opts = qemu_opts_create(list, id, 1, NULL); + continue; + } + if (sscanf(line, "[%63[^]]]", group) == 1) { + /* group without id */ + list = find_list(lists, group, &local_err); + if (error_is_set(&local_err)) { + error_report("%s\n", error_get_pretty(local_err)); + error_free(local_err); + goto out; + } + opts = qemu_opts_create_nofail(list); + continue; + } + if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) { + /* arg = value */ + if (opts == NULL) { + error_report("no group defined"); + goto out; + } + if (qemu_opt_set(opts, arg, value) != 0) { + goto out; + } + continue; + } + error_report("parse error"); + goto out; + } + if (ferror(fp)) { + error_report("error reading file"); + goto out; + } + res = 0; +out: + loc_pop(&loc); + return res; +} + +int qemu_read_config_file(const char *filename) +{ + FILE *f = fopen(filename, "r"); + int ret; + + if (f == NULL) { + return -errno; + } + + ret = qemu_config_parse(f, vm_config_groups, filename); + fclose(f); + + if (ret == 0) { + return 0; + } else { + return -EINVAL; + } +} diff --git a/qemu-error.c b/util/qemu-error.c index 08a36f480c..08a36f480c 100644 --- a/qemu-error.c +++ b/util/qemu-error.c diff --git a/qemu-option.c b/util/qemu-option.c index f532b765a0..f532b765a0 100644 --- a/qemu-option.c +++ b/util/qemu-option.c diff --git a/qemu-progress.c b/util/qemu-progress.c index 9a3f96cd47..9a3f96cd47 100644 --- a/qemu-progress.c +++ b/util/qemu-progress.c diff --git a/qemu-sockets.c b/util/qemu-sockets.c index 3537bf3d45..3537bf3d45 100644 --- a/qemu-sockets.c +++ b/util/qemu-sockets.c diff --git a/qemu-thread-posix.c b/util/qemu-thread-posix.c index 4489abf1d8..4489abf1d8 100644 --- a/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c diff --git a/qemu-thread-win32.c b/util/qemu-thread-win32.c index 517878dcc1..517878dcc1 100644 --- a/qemu-thread-win32.c +++ b/util/qemu-thread-win32.c diff --git a/qemu-timer-common.c b/util/qemu-timer-common.c index 16f5e758b2..16f5e758b2 100644 --- a/qemu-timer-common.c +++ b/util/qemu-timer-common.c @@ -299,6 +299,195 @@ static struct { { .driver = "qxl-vga", .flag = &default_vga }, }; +static QemuOptsList qemu_rtc_opts = { + .name = "rtc", + .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head), + .desc = { + { + .name = "base", + .type = QEMU_OPT_STRING, + },{ + .name = "clock", + .type = QEMU_OPT_STRING, + },{ + .name = "driftfix", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +static 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_trace_opts = { + .name = "trace", + .implied_opt_name = "trace", + .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head), + .desc = { + { + .name = "events", + .type = QEMU_OPT_STRING, + },{ + .name = "file", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_option_rom_opts = { + .name = "option-rom", + .implied_opt_name = "romfile", + .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head), + .desc = { + { + .name = "bootindex", + .type = QEMU_OPT_NUMBER, + }, { + .name = "romfile", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_machine_opts = { + .name = "machine", + .implied_opt_name = "type", + .merge_lists = true, + .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head), + .desc = { + { + .name = "type", + .type = QEMU_OPT_STRING, + .help = "emulated machine" + }, { + .name = "accel", + .type = QEMU_OPT_STRING, + .help = "accelerator list", + }, { + .name = "kernel_irqchip", + .type = QEMU_OPT_BOOL, + .help = "use KVM in-kernel irqchip", + }, { + .name = "kvm_shadow_mem", + .type = QEMU_OPT_SIZE, + .help = "KVM shadow MMU size", + }, { + .name = "kernel", + .type = QEMU_OPT_STRING, + .help = "Linux kernel image file", + }, { + .name = "initrd", + .type = QEMU_OPT_STRING, + .help = "Linux initial ramdisk file", + }, { + .name = "append", + .type = QEMU_OPT_STRING, + .help = "Linux kernel command line", + }, { + .name = "dtb", + .type = QEMU_OPT_STRING, + .help = "Linux kernel device tree file", + }, { + .name = "dumpdtb", + .type = QEMU_OPT_STRING, + .help = "Dump current dtb to a file and quit", + }, { + .name = "phandle_start", + .type = QEMU_OPT_STRING, + .help = "The first phandle ID we may generate dynamically", + }, { + .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", + }, { + .name = "mem-merge", + .type = QEMU_OPT_BOOL, + .help = "enable/disable memory merge support", + },{ + .name = "usb", + .type = QEMU_OPT_BOOL, + .help = "Set on/off to enable/disable usb", + }, + { /* End of list */ } + }, +}; + +static QemuOptsList qemu_boot_opts = { + .name = "boot-opts", + .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head), + .desc = { + /* the three names below are not used now */ + { + .name = "order", + .type = QEMU_OPT_STRING, + }, { + .name = "once", + .type = QEMU_OPT_STRING, + }, { + .name = "menu", + .type = QEMU_OPT_STRING, + /* following are really used */ + }, { + .name = "splash", + .type = QEMU_OPT_STRING, + }, { + .name = "splash-time", + .type = QEMU_OPT_STRING, + }, { + .name = "reboot-timeout", + .type = QEMU_OPT_STRING, + }, + { /*End of list */ } + }, +}; + +static QemuOptsList qemu_add_fd_opts = { + .name = "add-fd", + .head = QTAILQ_HEAD_INITIALIZER(qemu_add_fd_opts.head), + .desc = { + { + .name = "fd", + .type = QEMU_OPT_NUMBER, + .help = "file descriptor of which a duplicate is added to fd set", + },{ + .name = "set", + .type = QEMU_OPT_NUMBER, + .help = "ID of the fd set to add fd to", + },{ + .name = "opaque", + .type = QEMU_OPT_STRING, + .help = "free-form string used to describe fd", + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_object_opts = { + .name = "object", + .implied_opt_name = "qom-type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head), + .desc = { + { } + }, +}; + const char *qemu_get_vm_name(void) { return qemu_name; @@ -448,21 +637,18 @@ StatusInfo *qmp_query_status(Error **errp) void qemu_get_timedate(struct tm *tm, int offset) { time_t ti; - struct tm *ret; time(&ti); ti += offset; if (rtc_date_offset == -1) { if (rtc_utc) - ret = gmtime(&ti); + gmtime_r(&ti, tm); else - ret = localtime(&ti); + localtime_r(&ti, tm); } else { ti -= rtc_date_offset; - ret = gmtime(&ti); + gmtime_r(&ti, tm); } - - memcpy(tm, ret, sizeof(struct tm)); } int qemu_timedate_diff(struct tm *tm) @@ -2569,6 +2755,22 @@ int main(int argc, char **argv, char **envp) module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_drive_opts); + qemu_add_opts(&qemu_chardev_opts); + qemu_add_opts(&qemu_device_opts); + qemu_add_opts(&qemu_netdev_opts); + qemu_add_opts(&qemu_net_opts); + qemu_add_opts(&qemu_rtc_opts); + qemu_add_opts(&qemu_global_opts); + qemu_add_opts(&qemu_mon_opts); + qemu_add_opts(&qemu_trace_opts); + qemu_add_opts(&qemu_option_rom_opts); + qemu_add_opts(&qemu_machine_opts); + qemu_add_opts(&qemu_boot_opts); + qemu_add_opts(&qemu_sandbox_opts); + qemu_add_opts(&qemu_add_fd_opts); + qemu_add_opts(&qemu_object_opts); + runstate_init(); init_clocks(); @@ -3762,6 +3964,9 @@ int main(int argc, char **argv, char **envp) } configure_icount(icount_option); + /* clean up network at qemu process termination */ + atexit(&net_cleanup); + if (net_init_clients() < 0) { exit(1); } @@ -4014,7 +4219,6 @@ int main(int argc, char **argv, char **envp) main_loop(); bdrv_close_all(); pause_all_vcpus(); - net_cleanup(); res_free(); return 0; |