aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS7
-rw-r--r--Makefile10
-rw-r--r--QMP/README88
-rw-r--r--block.c2
-rw-r--r--block/iscsi.c6
-rw-r--r--block/qcow2-snapshot.c2
-rw-r--r--blockdev.c2
-rw-r--r--bsd-user/qemu.h6
-rwxr-xr-xconfigure28
-rw-r--r--docs/qmp/README87
-rw-r--r--docs/qmp/qmp-events.txt (renamed from QMP/qmp-events.txt)34
-rw-r--r--docs/qmp/qmp-spec.txt (renamed from QMP/qmp-spec.txt)65
-rw-r--r--docs/specs/acpi_cpu_hotplug.txt2
-rw-r--r--exec.c3
-rw-r--r--hmp.c2
-rw-r--r--hw/block/virtio-blk.c24
-rw-r--r--hw/char/Makefile.objs2
-rw-r--r--hw/char/sclpconsole-lm.c398
-rw-r--r--hw/char/sclpconsole.c88
-rw-r--r--hw/display/Makefile.objs3
-rw-r--r--hw/display/qxl.c12
-rw-r--r--hw/display/qxl.h3
-rw-r--r--hw/i386/kvm/clock.c2
-rw-r--r--hw/i386/kvmvapic.c17
-rw-r--r--hw/net/e1000.c70
-rw-r--r--hw/net/pcnet-pci.c4
-rw-r--r--hw/pci-host/q35.c2
-rw-r--r--hw/s390x/event-facility.c17
-rw-r--r--hw/s390x/sclpquiesce.c29
-rw-r--r--hw/scsi/lsi53c895a.c32
-rw-r--r--hw/usb/combined-packet.c1
-rw-r--r--hw/usb/core.c3
-rw-r--r--hw/usb/hcd-xhci.c45
-rw-r--r--hw/usb/host-bsd.c639
-rw-r--r--hw/usb/host-linux.c1911
-rw-r--r--include/hw/pci-host/q35.h2
-rw-r--r--include/hw/pci/pci_ids.h1
-rw-r--r--include/hw/s390x/ebcdic.h104
-rw-r--r--include/hw/s390x/event-facility.h88
-rw-r--r--include/hw/virtio/virtio-blk.h1
-rw-r--r--include/qemu/timer.h17
-rw-r--r--include/sysemu/kvm.h29
-rw-r--r--kvm-all.c82
-rw-r--r--kvm-stub.c1
-rw-r--r--libcacard/Makefile3
-rw-r--r--libcacard/vscclient.c3
-rw-r--r--linux-headers/asm-arm64/kvm.h168
-rw-r--r--linux-headers/asm-arm64/kvm_para.h1
-rw-r--r--linux-headers/asm-mips/kvm.h81
-rw-r--r--linux-headers/asm-x86/kvm_para.h1
-rw-r--r--linux-headers/linux/kvm.h4
-rw-r--r--linux-headers/linux/kvm_para.h1
-rw-r--r--linux-headers/linux/vfio.h80
-rw-r--r--linux-headers/linux/virtio_config.h3
-rw-r--r--linux-user/alpha/syscall_nr.h4
-rw-r--r--linux-user/ioctls.h1
-rw-r--r--linux-user/linuxload.c8
-rw-r--r--linux-user/main.c92
-rw-r--r--linux-user/qemu.h8
-rw-r--r--linux-user/strace.list9
-rw-r--r--linux-user/syscall.c210
-rw-r--r--linux-user/syscall_defs.h12
-rw-r--r--pc-bios/s390-ccw.imgbin9432 -> 9336 bytes
-rw-r--r--pc-bios/s390-ccw/virtio.c7
-rw-r--r--pc-bios/s390-ccw/virtio.h1
-rw-r--r--qemu-timer.c92
-rw-r--r--qom/cpu.c1
-rwxr-xr-xscripts/qmp/qemu-ga-client (renamed from QMP/qemu-ga-client)0
-rwxr-xr-xscripts/qmp/qmp (renamed from QMP/qmp)0
-rwxr-xr-xscripts/qmp/qmp-shell (renamed from QMP/qmp-shell)2
-rw-r--r--scripts/qmp/qmp.py (renamed from QMP/qmp.py)2
-rwxr-xr-xscripts/qmp/qom-fuse (renamed from QMP/qom-fuse)0
-rwxr-xr-xscripts/qmp/qom-get (renamed from QMP/qom-get)0
-rwxr-xr-xscripts/qmp/qom-list (renamed from QMP/qom-list)0
-rwxr-xr-xscripts/qmp/qom-set (renamed from QMP/qom-set)0
-rw-r--r--target-i386/cpu-qom.h3
-rw-r--r--target-i386/cpu.c21
-rw-r--r--target-i386/helper.c6
-rw-r--r--target-i386/machine.c6
-rw-r--r--target-ppc/translate.c2
-rw-r--r--target-s390x/arch_dump.c1
-rw-r--r--target-s390x/cpu.h11
-rw-r--r--target-s390x/ioinst.c110
-rw-r--r--target-s390x/ioinst.h26
-rw-r--r--target-s390x/kvm.c54
-rw-r--r--target-s390x/misc_helper.c107
-rw-r--r--tcg/sparc/tcg-target.h2
-rw-r--r--tci.c12
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/test-coroutine.c45
-rw-r--r--trace-events9
-rw-r--r--translate-all.c5
-rw-r--r--util/iov.c10
-rw-r--r--util/osdep.c7
94 files changed, 1963 insertions, 3240 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index bee4b6e3c1..5c3c70c89b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -767,6 +767,12 @@ M: Blue Swirl <blauwirbel@gmail.com>
S: Odd Fixes
F: scripts/checkpatch.pl
+Seccomp
+M: Eduardo Otubo <otubo@linux.vnet.ibm.com>
+S: Supported
+F: qemu-seccomp.c
+F: include/sysemu/seccomp.h
+
Usermode Emulation
------------------
BSD user
@@ -843,6 +849,7 @@ TCI target
M: Stefan Weil <sw@weilnetz.de>
S: Maintained
F: tcg/tci/
+F: tci.c
Stable branches
---------------
diff --git a/Makefile b/Makefile
index 362fe3e66e..60fb87e2dd 100644
--- a/Makefile
+++ b/Makefile
@@ -65,7 +65,7 @@ LIBS+=-lz $(LIBS_TOOLS)
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
ifdef BUILD_DOCS
-DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
+DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qmp-commands.txt
ifdef CONFIG_VIRTFS
DOCS+=fsdev/virtfs-proxy-helper.1
endif
@@ -236,7 +236,8 @@ clean:
find . -name '*.[oda]' -type f -exec rm -f {} +
find . -name '*.l[oa]' -type f -exec rm -f {} +
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
- rm -Rf .libs
+ rm -f fsdev/*.pod
+ rm -rf .libs */.libs
rm -f qemu-img-cmds.h
@# May not be present in GENERATED_HEADERS
rm -f trace/generated-tracers-dtrace.dtrace*
@@ -261,6 +262,7 @@ qemu-%.tar.bz2:
distclean: clean
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
rm -f config-all-devices.mak config-all-disas.mak
+ rm -f po/*.mo
rm -f roms/seabios/config.mak roms/vgabios/config.mak
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.cps qemu-doc.dvi
rm -f qemu-doc.fn qemu-doc.fns qemu-doc.info qemu-doc.ky qemu-doc.kys
@@ -304,7 +306,7 @@ endif
install-doc: $(DOCS)
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
- $(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
+ $(INSTALL_DATA) qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
ifdef CONFIG_POSIX
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
@@ -398,7 +400,7 @@ qemu-options.texi: $(SRC_PATH)/qemu-options.hx
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
-QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
+qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@," GEN $@")
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
diff --git a/QMP/README b/QMP/README
deleted file mode 100644
index c95a08c234..0000000000
--- a/QMP/README
+++ /dev/null
@@ -1,88 +0,0 @@
- QEMU Monitor Protocol
- =====================
-
-Introduction
--------------
-
-The QEMU Monitor Protocol (QMP) allows applications to communicate with
-QEMU's Monitor.
-
-QMP is JSON[1] based and currently has the following features:
-
-- Lightweight, text-based, easy to parse data format
-- Asynchronous messages support (ie. events)
-- Capabilities Negotiation
-
-For detailed information on QMP's usage, please, refer to the following files:
-
-o qmp-spec.txt QEMU Monitor Protocol current specification
-o qmp-commands.txt QMP supported commands (auto-generated at build-time)
-o qmp-events.txt List of available asynchronous events
-
-There is also a simple Python script called 'qmp-shell' available.
-
-IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
-section in the qmp-commands.txt file before making any serious use of QMP.
-
-
-[1] http://www.json.org
-
-Usage
------
-
-To enable QMP, you need a QEMU monitor instance in "control mode". There are
-two ways of doing this.
-
-The simplest one is using the '-qmp' command-line option. The following
-example makes QMP available on localhost port 4444:
-
- $ qemu [...] -qmp tcp:localhost:4444,server
-
-However, in order to have more complex combinations, like multiple monitors,
-the '-mon' command-line option should be used along with the '-chardev' one.
-For instance, the following example creates one user monitor on stdio and one
-QMP monitor on localhost port 4444.
-
- $ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
- -chardev socket,id=mon1,host=localhost,port=4444,server \
- -mon chardev=mon1,mode=control
-
-Please, refer to QEMU's manpage for more information.
-
-Simple Testing
---------------
-
-To manually test QMP one can connect with telnet and issue commands by hand:
-
-$ telnet localhost 4444
-Trying 127.0.0.1...
-Connected to localhost.
-Escape character is '^]'.
-{"QMP": {"version": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}, "capabilities": []}}
-{ "execute": "qmp_capabilities" }
-{"return": {}}
-{ "execute": "query-version" }
-{"return": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}}
-
-Development Process
--------------------
-
-When changing QMP's interface (by adding new commands, events or modifying
-existing ones) it's mandatory to update the relevant documentation, which is
-one (or more) of the files listed in the 'Introduction' section*.
-
-Also, it's strongly recommended to send the documentation patch first, before
-doing any code change. This is so because:
-
- 1. Avoids the code dictating the interface
-
- 2. Review can improve your interface. Letting that happen before
- you implement it can save you work.
-
-* The qmp-commands.txt file is generated from the qmp-commands.hx one, which
- is the file that should be edited.
-
-Homepage
---------
-
-http://wiki.qemu.org/QMP
diff --git a/block.c b/block.c
index e176c6f3bc..ea4956d6c7 100644
--- a/block.c
+++ b/block.c
@@ -2669,7 +2669,7 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
goto out;
}
- total_sectors = len >> BDRV_SECTOR_BITS;
+ total_sectors = (len + BDRV_SECTOR_SIZE - 1) >> BDRV_SECTOR_BITS;
max_nb_sectors = MAX(0, total_sectors - sector_num);
if (max_nb_sectors > 0) {
ret = drv->bdrv_co_readv(bs, sector_num,
diff --git a/block/iscsi.c b/block/iscsi.c
index b6b47c649c..4460382811 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -811,6 +811,8 @@ iscsi_getlength(BlockDriverState *bs)
return len;
}
+#if defined(SCSI_PROVISIONING_TYPE_DEALLOCATED)
+
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors, int *pnum)
@@ -901,6 +903,8 @@ out:
return ret;
}
+#endif /* SCSI_PROVISIONING_TYPE_DEALLOCATED */
+
static int
coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
int nb_sectors)
@@ -1524,7 +1528,9 @@ static BlockDriver bdrv_iscsi = {
.bdrv_getlength = iscsi_getlength,
.bdrv_truncate = iscsi_truncate,
+#if defined(SCSI_PROVISIONING_TYPE_DEALLOCATED)
.bdrv_co_get_block_status = iscsi_co_get_block_status,
+#endif
.bdrv_co_discard = iscsi_co_discard,
.bdrv_aio_readv = iscsi_aio_readv,
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 7d144205c3..5e8a7794f4 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -192,7 +192,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
/* The snapshot list position has not yet been updated, so these clusters
* must indeed be completely free */
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT, offset,
- s->snapshots_size);
+ snapshots_size);
if (ret < 0) {
return ret;
}
diff --git a/blockdev.c b/blockdev.c
index 80605a2bac..8aa66a949c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -443,7 +443,7 @@ static DriveInfo *blockdev_init(QemuOpts *all_opts,
if (qemu_opt_get_bool(opts, "cache.direct", false)) {
bdrv_flags |= BDRV_O_NOCACHE;
}
- if (qemu_opt_get_bool(opts, "cache.no-flush", true)) {
+ if (qemu_opt_get_bool(opts, "cache.no-flush", false)) {
bdrv_flags |= BDRV_O_NO_FLUSH;
}
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 325f564f80..ddc74ed0d7 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -323,9 +323,9 @@ abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
/* Functions for accessing guest memory. The tget and tput functions
- read/write single values, byteswapping as necessary. The lock_user
+ read/write single values, byteswapping as necessary. The lock_user function
gets a pointer to a contiguous area of guest memory, but does not perform
- and byteswapping. lock_user may return either a pointer to the guest
+ any byteswapping. lock_user may return either a pointer to the guest
memory, or a temporary buffer. */
/* Lock an area of guest memory into the host. If copy is true then the
@@ -381,7 +381,7 @@ static inline void *lock_user_string(abi_ulong guest_addr)
return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
}
-/* Helper macros for locking/ulocking a target struct. */
+/* Helper macros for locking/unlocking a target struct. */
#define lock_user_struct(type, host_ptr, guest_addr, copy) \
(host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy))
#define unlock_user_struct(host_ptr, guest_addr, copy) \
diff --git a/configure b/configure
index 3096d961f8..96e1de0ecd 100755
--- a/configure
+++ b/configure
@@ -561,7 +561,6 @@ Haiku)
audio_possible_drivers="oss alsa sdl esd pa"
linux="yes"
linux_user="yes"
- usb="linux"
kvm="yes"
vhost_net="yes"
vhost_scsi="yes"
@@ -574,9 +573,6 @@ esac
if [ "$bsd" = "yes" ] ; then
if [ "$darwin" != "yes" ] ; then
- if [ "$targetos" != "FreeBSD" ]; then
- usb="bsd"
- fi
bsd_user="yes"
fi
fi
@@ -3122,7 +3118,6 @@ fi
if test "$libusb" != "no" ; then
if $pkg_config --atleast-version=1.0.13 libusb-1.0; then
libusb="yes"
- usb="libusb"
libusb_cflags=$($pkg_config --cflags libusb-1.0)
libusb_libs=$($pkg_config --libs libusb-1.0)
QEMU_CFLAGS="$QEMU_CFLAGS $libusb_cflags"
@@ -3516,7 +3511,7 @@ if test "$gcov" = "yes" ; then
CFLAGS="-fprofile-arcs -ftest-coverage -g $CFLAGS"
LDFLAGS="-fprofile-arcs -ftest-coverage $LDFLAGS"
elif test "$debug" = "no" ; then
- CFLAGS="-O2 -D_FORTIFY_SOURCE=2 $CFLAGS"
+ CFLAGS="-O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
fi
@@ -4158,24 +4153,11 @@ if test "$virtio_blk_data_plane" = "yes" ; then
fi
# USB host support
-case "$usb" in
-linux)
- echo "HOST_USB=linux legacy" >> $config_host_mak
-;;
-bsd)
- echo "HOST_USB=bsd" >> $config_host_mak
-;;
-libusb)
- if test "$linux" = "yes"; then
- echo "HOST_USB=libusb linux legacy" >> $config_host_mak
- else
- echo "HOST_USB=libusb legacy" >> $config_host_mak
- fi
-;;
-*)
+if test "$libusb" = "yes"; then
+ echo "HOST_USB=libusb legacy" >> $config_host_mak
+else
echo "HOST_USB=stub" >> $config_host_mak
-;;
-esac
+fi
# TPM passthrough support?
if test "$tpm" = "yes"; then
diff --git a/docs/qmp/README b/docs/qmp/README
new file mode 100644
index 0000000000..85c4bc17bf
--- /dev/null
+++ b/docs/qmp/README
@@ -0,0 +1,87 @@
+ QEMU Machine Protocol
+ =====================
+
+Introduction
+------------
+
+The QEMU Machine Protocol (QMP) allows applications to operate a
+QEMU instance.
+
+QMP is JSON[1] based and features the following:
+
+- Lightweight, text-based, easy to parse data format
+- Asynchronous messages support (ie. events)
+- Capabilities Negotiation
+
+For detailed information on QMP's usage, please, refer to the following files:
+
+o qmp-spec.txt QEMU Machine Protocol current specification
+o qmp-commands.txt QMP supported commands (auto-generated at build-time)
+o qmp-events.txt List of available asynchronous events
+
+[1] http://www.json.org
+
+Usage
+-----
+
+You can use the -qmp option to enable QMP. For example, the following
+makes QMP available on localhost port 4444:
+
+$ qemu [...] -qmp tcp:localhost:4444,server,nowait
+
+However, for more flexibility and to make use of more options, the -mon
+command-line option should be used. For instance, the following example
+creates one HMP instance (human monitor) on stdio and one QMP instance
+on localhost port 4444:
+
+$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
+ -chardev socket,id=mon1,host=localhost,port=4444,server,nowait \
+ -mon chardev=mon1,mode=control,pretty=on
+
+Please, refer to QEMU's manpage for more information.
+
+Simple Testing
+--------------
+
+To manually test QMP one can connect with telnet and issue commands by hand:
+
+$ telnet localhost 4444
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+{
+ "QMP": {
+ "version": {
+ "qemu": {
+ "micro": 50,
+ "minor": 6,
+ "major": 1
+ },
+ "package": ""
+ },
+ "capabilities": [
+ ]
+ }
+}
+
+{ "execute": "qmp_capabilities" }
+{
+ "return": {
+ }
+}
+
+{ "execute": "query-status" }
+{
+ "return": {
+ "status": "prelaunch",
+ "singlestep": false,
+ "running": false
+ }
+}
+
+Please, refer to the qapi-schema.json file for a complete command reference.
+
+QMP wiki page
+-------------
+
+http://wiki.qemu.org/QMP
diff --git a/QMP/qmp-events.txt b/docs/qmp/qmp-events.txt
index 4b24ec900d..6b87e9786a 100644
--- a/QMP/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -1,4 +1,4 @@
- QEMU Monitor Protocol Events
+ QEMU Machine Protocol Events
============================
BALLOON_CHANGE
@@ -159,7 +159,7 @@ Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
event.
DEVICE_DELETED
------------------
+--------------
Emitted whenever the device removal completion is acknowledged
by the guest.
@@ -194,8 +194,22 @@ Data:
},
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+GUEST_PANICKED
+--------------
+
+Emitted when guest OS panic is detected.
+
+Data:
+
+- "action": Action that has been taken (json-string, currently always "pause").
+
+Example:
+
+{ "event": "GUEST_PANICKED",
+ "data": { "action": "pause" } }
+
NIC_RX_FILTER_CHANGED
------------------
+---------------------
The event is emitted once until the query command is executed,
the first event will always be emitted.
@@ -486,17 +500,3 @@ Example:
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events.
-
-GUEST_PANICKED
---------------
-
-Emitted when guest OS panic is detected.
-
-Data:
-
-- "action": Action that has been taken (json-string, currently always "pause").
-
-Example:
-
-{ "event": "GUEST_PANICKED",
- "data": { "action": "pause" } }
diff --git a/QMP/qmp-spec.txt b/docs/qmp/qmp-spec.txt
index a27789692b..22568c644e 100644
--- a/QMP/qmp-spec.txt
+++ b/docs/qmp/qmp-spec.txt
@@ -1,21 +1,17 @@
- QEMU Monitor Protocol Specification - Version 0.1
+ QEMU Machine Protocol Specification
1. Introduction
===============
-This document specifies the QEMU Monitor Protocol (QMP), a JSON-based protocol
-which is available for applications to control QEMU at the machine-level.
-
-To enable QMP support, QEMU has to be run in "control mode". This is done by
-starting QEMU with the appropriate command-line options. Please, refer to the
-QEMU manual page for more information.
+This document specifies the QEMU Machine Protocol (QMP), a JSON-based protocol
+which is available for applications to operate QEMU at the machine-level.
2. Protocol Specification
=========================
This section details the protocol format. For the purpose of this document
-"Client" is any application which is communicating with QEMU in control mode,
-and "Server" is QEMU itself.
+"Client" is any application which is using QMP to communicate with QEMU and
+"Server" is QEMU itself.
JSON data structures, when mentioned in this document, are always in the
following format:
@@ -47,14 +43,14 @@ that the connection has been successfully established and that the Server is
ready for capabilities negotiation (for more information refer to section
'4. Capabilities Negotiation').
-The format is:
+The greeting message format is:
{ "QMP": { "version": json-object, "capabilities": json-array } }
Where,
- The "version" member contains the Server's version information (the format
- is the same of the 'query-version' command)
+ is the same of the query-version command)
- The "capabilities" member specify the availability of features beyond the
baseline specification
@@ -83,10 +79,7 @@ of a command execution: success or error.
2.4.1 success
-------------
-The success response is issued when the command execution has finished
-without errors.
-
-The format is:
+The format of a success response is:
{ "return": json-object, "id": json-value }
@@ -96,15 +89,12 @@ The format is:
in a per-command basis or an empty json-object if the command does not
return data
- The "id" member contains the transaction identification associated
- with the command execution (if issued by the Client)
+ with the command execution if issued by the Client
2.4.2 error
-----------
-The error response is issued when the command execution could not be
-completed because of an error condition.
-
-The format is:
+The format of an error response is:
{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
@@ -114,7 +104,7 @@ The format is:
- The "desc" member is a human-readable error message. Clients should
not attempt to parse this message.
- The "id" member contains the transaction identification associated with
- the command execution (if issued by the Client)
+ the command execution if issued by the Client
NOTE: Some errors can occur before the Server is able to read the "id" member,
in these cases the "id" member will not be part of the error response, even
@@ -124,9 +114,9 @@ if provided by the client.
-----------------------
As a result of state changes, the Server may send messages unilaterally
-to the Client at any time. They are called 'asynchronous events'.
+to the Client at any time. They are called "asynchronous events".
-The format is:
+The format of asynchronous events is:
{ "event": json-string, "data": json-object,
"timestamp": { "seconds": json-number, "microseconds": json-number } }
@@ -147,36 +137,37 @@ qmp-events.txt file.
===============
This section provides some examples of real QMP usage, in all of them
-'C' stands for 'Client' and 'S' stands for 'Server'.
+"C" stands for "Client" and "S" stands for "Server".
3.1 Server greeting
-------------------
-S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
+S: { "QMP": { "version": { "qemu": { "micro": 50, "minor": 6, "major": 1 },
+ "package": ""}, "capabilities": []}}
3.2 Simple 'stop' execution
---------------------------
C: { "execute": "stop" }
-S: {"return": {}}
+S: { "return": {} }
3.3 KVM information
-------------------
C: { "execute": "query-kvm", "id": "example" }
-S: {"return": {"enabled": true, "present": true}, "id": "example"}
+S: { "return": { "enabled": true, "present": true }, "id": "example"}
3.4 Parsing error
------------------
C: { "execute": }
-S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
+S: { "error": { "class": "GenericError", "desc": "Invalid JSON syntax" } }
3.5 Powerdown event
-------------------
-S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
-"POWERDOWN"}
+S: { "timestamp": { "seconds": 1258551470, "microseconds": 802384 },
+ "event": "POWERDOWN" }
4. Capabilities Negotiation
----------------------------
@@ -184,17 +175,17 @@ S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
When a Client successfully establishes a connection, the Server is in
Capabilities Negotiation mode.
-In this mode only the 'qmp_capabilities' command is allowed to run, all
-other commands will return the CommandNotFound error. Asynchronous messages
-are not delivered either.
+In this mode only the qmp_capabilities command is allowed to run, all
+other commands will return the CommandNotFound error. Asynchronous
+messages are not delivered either.
-Clients should use the 'qmp_capabilities' command to enable capabilities
+Clients should use the qmp_capabilities command to enable capabilities
advertised in the Server's greeting (section '2.2 Server Greeting') they
support.
-When the 'qmp_capabilities' command is issued, and if it does not return an
+When the qmp_capabilities command is issued, and if it does not return an
error, the Server enters in Command mode where capabilities changes take
-effect, all commands (except 'qmp_capabilities') are allowed and asynchronous
+effect, all commands (except qmp_capabilities) are allowed and asynchronous
messages are delivered.
5 Compatibility Considerations
@@ -245,7 +236,7 @@ arguments, errors, asynchronous events, and so forth.
Any new names downstream wishes to add must begin with '__'. To
ensure compatibility with other downstreams, it is strongly
-recommended that you prefix your downstram names with '__RFQDN_' where
+recommended that you prefix your downstream names with '__RFQDN_' where
RFQDN is a valid, reverse fully qualified domain name which you
control. For example, a qemu-kvm specific monitor command would be:
diff --git a/docs/specs/acpi_cpu_hotplug.txt b/docs/specs/acpi_cpu_hotplug.txt
index 5dec0c5010..f6f577457d 100644
--- a/docs/specs/acpi_cpu_hotplug.txt
+++ b/docs/specs/acpi_cpu_hotplug.txt
@@ -10,7 +10,7 @@ ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
Generic ACPI GPE block. Bit 2 (GPE.2) used to notify CPU
hot-add/remove event to ACPI BIOS, via SCI interrupt.
-CPU present bitmap (IO port 0xaf00-0xae1f, 1-byte access):
+CPU present bitmap (IO port 0xaf00-0xaf1f, 1-byte access):
---------------------------------------------------------------
One bit per CPU. Bit position reflects corresponding CPU APIC ID.
Read-only.
diff --git a/exec.c b/exec.c
index 26469120d9..26681ce021 100644
--- a/exec.c
+++ b/exec.c
@@ -1184,6 +1184,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
qemu_ram_setup_dump(new_block->host, size);
qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
+ qemu_madvise(new_block->host, size, QEMU_MADV_DONTFORK);
if (kvm_enabled())
kvm_setup_guest_memory(new_block->host, size);
@@ -1229,9 +1230,11 @@ void qemu_ram_free(ram_addr_t addr)
;
} else if (xen_enabled()) {
xen_invalidate_map_cache_entry(block->host);
+#ifndef _WIN32
} else if (block->fd >= 0) {
munmap(block->host, block->length);
close(block->fd);
+#endif
} else {
qemu_anon_ram_free(block->host, block->length);
}
diff --git a/hmp.c b/hmp.c
index 2a902951df..589150773e 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1163,7 +1163,7 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
qmp_block_stream(device, base != NULL, base,
qdict_haskey(qdict, "speed"), speed,
- BLOCKDEV_ON_ERROR_REPORT, true, &error);
+ true, BLOCKDEV_ON_ERROR_REPORT, &error);
hmp_handle_error(mon, &error);
}
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index e2f55cc946..49a23c33f7 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -460,9 +460,9 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running,
static void virtio_blk_reset(VirtIODevice *vdev)
{
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
VirtIOBlock *s = VIRTIO_BLK(vdev);
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
if (s->dataplane) {
virtio_blk_data_plane_stop(s->dataplane);
}
@@ -473,6 +473,7 @@ static void virtio_blk_reset(VirtIODevice *vdev)
* are per-device request lists.
*/
bdrv_drain_all();
+ bdrv_set_enable_write_cache(s->bs, s->original_wce);
}
/* coalesce internal state, copy to pci i/o region 0
@@ -564,7 +565,25 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
}
features = vdev->guest_features;
- bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
+
+ /* A guest that supports VIRTIO_BLK_F_CONFIG_WCE must be able to send
+ * cache flushes. Thus, the "auto writethrough" behavior is never
+ * necessary for guests that support the VIRTIO_BLK_F_CONFIG_WCE feature.
+ * Leaving it enabled would break the following sequence:
+ *
+ * Guest started with "-drive cache=writethrough"
+ * Guest sets status to 0
+ * Guest sets DRIVER bit in status field
+ * Guest reads host features (WCE=0, CONFIG_WCE=1)
+ * Guest writes guest features (WCE=0, CONFIG_WCE=1)
+ * Guest writes 1 to the WCE configuration field (writeback mode)
+ * Guest sets DRIVER_OK bit in status field
+ *
+ * s->bs would erroneously be placed in writethrough mode.
+ */
+ if (!(features & (1 << VIRTIO_BLK_F_CONFIG_WCE))) {
+ bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
+ }
}
static void virtio_blk_save(QEMUFile *f, void *opaque)
@@ -674,6 +693,7 @@ static int virtio_blk_device_init(VirtIODevice *vdev)
}
blkconf_serial(&blk->conf, &blk->serial);
+ s->original_wce = bdrv_enable_write_cache(blk->conf.bs);
if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) {
return -1;
}
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index f8f3dbca3e..cbd6a006f4 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -22,6 +22,6 @@ common-obj-$(CONFIG_IMX) += imx_serial.o
common-obj-$(CONFIG_LM32) += lm32_juart.o
common-obj-$(CONFIG_LM32) += lm32_uart.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
-common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o
+common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o
obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
new file mode 100644
index 0000000000..93390675d6
--- /dev/null
+++ b/hw/char/sclpconsole-lm.c
@@ -0,0 +1,398 @@
+/*
+ * SCLP event types
+ * Operations Command - Line Mode input
+ * Message - Line Mode output
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * Heinz Graalfs <graalfs@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/qdev.h"
+#include "qemu/thread.h"
+#include "qemu/error-report.h"
+#include "sysemu/char.h"
+
+#include "hw/s390x/sclp.h"
+#include "hw/s390x/event-facility.h"
+#include "hw/s390x/ebcdic.h"
+
+#define SIZE_BUFFER 4096
+#define NEWLINE "\n"
+
+typedef struct OprtnsCommand {
+ EventBufferHeader header;
+ MDMSU message_unit;
+ char data[0];
+} QEMU_PACKED OprtnsCommand;
+
+/* max size for line-mode data in 4K SCCB page */
+#define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand))
+
+typedef struct SCLPConsoleLM {
+ SCLPEvent event;
+ CharDriverState *chr;
+ bool echo; /* immediate echo of input if true */
+ uint32_t write_errors; /* errors writing to char layer */
+ uint32_t length; /* length of byte stream in buffer */
+ uint8_t buf[SIZE_CONSOLE_BUFFER];
+ qemu_irq irq_console_read;
+} SCLPConsoleLM;
+
+/*
+* Character layer call-back functions
+ *
+ * Allow 1 character at a time
+ *
+ * Accumulate bytes from character layer in console buffer,
+ * event_pending is set when a newline character is encountered
+ *
+ * The maximum command line length is limited by the maximum
+ * space available in an SCCB
+ */
+
+static int chr_can_read(void *opaque)
+{
+ SCLPConsoleLM *scon = opaque;
+
+ if (scon->event.event_pending) {
+ return 0;
+ } else if (SIZE_CONSOLE_BUFFER - scon->length) {
+ return 1;
+ }
+ return 0;
+}
+
+static void receive_from_chr_layer(SCLPConsoleLM *scon, const uint8_t *buf,
+ int size)
+{
+ assert(size == 1);
+
+ if (*buf == '\r' || *buf == '\n') {
+ scon->event.event_pending = true;
+ return;
+ }
+ scon->buf[scon->length] = *buf;
+ scon->length += 1;
+ if (scon->echo) {
+ qemu_chr_fe_write(scon->chr, buf, size);
+ }
+}
+
+/*
+ * Send data from a char device over to the guest
+ */
+static void chr_read(void *opaque, const uint8_t *buf, int size)
+{
+ SCLPConsoleLM *scon = opaque;
+
+ receive_from_chr_layer(scon, buf, size);
+ if (scon->event.event_pending) {
+ /* trigger SCLP read operation */
+ qemu_irq_raise(scon->irq_console_read);
+ }
+}
+
+/* functions to be called by event facility */
+
+static bool can_handle_event(uint8_t type)
+{
+ return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD;
+}
+
+static unsigned int send_mask(void)
+{
+ return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD;
+}
+
+static unsigned int receive_mask(void)
+{
+ return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD;
+}
+
+/*
+ * Triggered by SCLP's read_event_data
+ * - convert ASCII byte stream to EBCDIC and
+ * - copy converted data into provided (SCLP) buffer
+ */
+static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
+ int avail)
+{
+ int len;
+
+ SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ len = cons->length;
+ /* data need to fit into provided SCLP buffer */
+ if (len > avail) {
+ return 1;
+ }
+
+ ebcdic_put(buf, (char *)&cons->buf, len);
+ *size = len;
+ cons->length = 0;
+ /* data provided and no more data pending */
+ event->event_pending = false;
+ return 0;
+}
+
+static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+ int *slen)
+{
+ int avail, rc;
+ size_t src_len;
+ uint8_t *to;
+ OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr;
+
+ if (!event->event_pending) {
+ /* no data pending */
+ return 0;
+ }
+
+ to = (uint8_t *)&oc->data;
+ avail = *slen - sizeof(OprtnsCommand);
+ rc = get_console_data(event, to, &src_len, avail);
+ if (rc) {
+ /* data didn't fit, try next SCCB */
+ return 1;
+ }
+
+ oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU;
+ oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU));
+
+ oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU;
+ oc->message_unit.cpmsu.length =
+ cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector));
+
+ oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD;
+ oc->message_unit.text_command.length =
+ cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector)));
+
+ oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG;
+ oc->message_unit.self_def_text_message.length =
+ cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector)));
+
+ oc->message_unit.text_message.key = GDS_KEY_TEXTMSG;
+ oc->message_unit.text_message.length =
+ cpu_to_be16(sizeof(GdsSubvector) + src_len);
+
+ oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len);
+ oc->header.type = SCLP_EVENT_OPRTNS_COMMAND;
+ *slen = avail - src_len;
+
+ return 1;
+}
+
+/*
+ * Triggered by SCLP's write_event_data
+ * - write console data to character layer
+ * returns < 0 if an error occurred
+ */
+static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
+{
+ int ret = 0;
+ const uint8_t *buf_offset;
+
+ SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ if (!scon->chr) {
+ /* If there's no backend, we can just say we consumed all data. */
+ return len;
+ }
+
+ buf_offset = buf;
+ while (len > 0) {
+ ret = qemu_chr_fe_write(scon->chr, buf, len);
+ if (ret == 0) {
+ /* a pty doesn't seem to be connected - no error */
+ len = 0;
+ } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
+ len -= ret;
+ buf_offset += ret;
+ } else {
+ len = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int process_mdb(SCLPEvent *event, MDBO *mdbo)
+{
+ int rc;
+ int len;
+ uint8_t buffer[SIZE_BUFFER];
+
+ len = be16_to_cpu(mdbo->length);
+ len -= sizeof(mdbo->length) + sizeof(mdbo->type)
+ + sizeof(mdbo->mto.line_type_flags)
+ + sizeof(mdbo->mto.alarm_control)
+ + sizeof(mdbo->mto._reserved);
+
+ assert(len <= SIZE_BUFFER);
+
+ /* convert EBCDIC SCLP contents to ASCII console message */
+ ascii_put(buffer, mdbo->mto.message, len);
+ rc = write_console_data(event, (uint8_t *)NEWLINE, 1);
+ if (rc < 0) {
+ return rc;
+ }
+ return write_console_data(event, buffer, len);
+}
+
+static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
+{
+ int len;
+ int written;
+ int errors = 0;
+ MDBO *mdbo;
+ SclpMsg *data = (SclpMsg *) ebh;
+ SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ len = be16_to_cpu(data->mdb.header.length);
+ if (len < sizeof(data->mdb.header)) {
+ return SCLP_RC_INCONSISTENT_LENGTHS;
+ }
+ len -= sizeof(data->mdb.header);
+
+ /* first check message buffers */
+ mdbo = data->mdb.mdbo;
+ while (len > 0) {
+ if (be16_to_cpu(mdbo->length) > len
+ || be16_to_cpu(mdbo->length) == 0) {
+ return SCLP_RC_INCONSISTENT_LENGTHS;
+ }
+ len -= be16_to_cpu(mdbo->length);
+ mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
+ }
+
+ /* then execute */
+ len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header);
+ mdbo = data->mdb.mdbo;
+ while (len > 0) {
+ switch (be16_to_cpu(mdbo->type)) {
+ case MESSAGE_TEXT:
+ /* message text object */
+ written = process_mdb(event, mdbo);
+ if (written < 0) {
+ /* character layer error */
+ errors++;
+ }
+ break;
+ default: /* ignore */
+ break;
+ }
+ len -= be16_to_cpu(mdbo->length);
+ mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
+ }
+ if (errors) {
+ scon->write_errors += errors;
+ }
+ data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED;
+
+ return SCLP_RC_NORMAL_COMPLETION;
+}
+
+static void trigger_console_data(void *opaque, int n, int level)
+{
+ sclp_service_interrupt(0);
+}
+
+/* functions for live migration */
+
+static const VMStateDescription vmstate_sclplmconsole = {
+ .name = "sclplmconsole",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(event.event_pending, SCLPConsoleLM),
+ VMSTATE_UINT32(write_errors, SCLPConsoleLM),
+ VMSTATE_UINT32(length, SCLPConsoleLM),
+ VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+/* qemu object creation and initialization functions */
+
+/* tell character layer our call-back functions */
+
+static int console_init(SCLPEvent *event)
+{
+ static bool console_available;
+
+ SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ if (console_available) {
+ error_report("Multiple line-mode operator consoles are not supported");
+ return -1;
+ }
+ console_available = true;
+
+ if (scon->chr) {
+ qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon);
+ }
+ scon->irq_console_read = *qemu_allocate_irqs(trigger_console_data, NULL, 1);
+
+ return 0;
+}
+
+static int console_exit(SCLPEvent *event)
+{
+ return 0;
+}
+
+static void console_reset(DeviceState *dev)
+{
+ SCLPEvent *event = SCLP_EVENT(dev);
+ SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
+
+ event->event_pending = false;
+ scon->length = 0;
+ scon->write_errors = 0;
+}
+
+static Property console_properties[] = {
+ DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr),
+ DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0),
+ DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void console_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
+
+ dc->props = console_properties;
+ dc->reset = console_reset;
+ dc->vmsd = &vmstate_sclplmconsole;
+ ec->init = console_init;
+ ec->exit = console_exit;
+ ec->get_send_mask = send_mask;
+ ec->get_receive_mask = receive_mask;
+ ec->can_handle_event = can_handle_event;
+ ec->read_event_data = read_event_data;
+ ec->write_event_data = write_event_data;
+}
+
+static const TypeInfo sclp_console_info = {
+ .name = "sclplmconsole",
+ .parent = TYPE_SCLP_EVENT,
+ .instance_size = sizeof(SCLPConsoleLM),
+ .class_init = console_class_init,
+ .class_size = sizeof(SCLPEventClass),
+};
+
+static void register_types(void)
+{
+ type_register_static(&sclp_console_info);
+}
+
+type_init(register_types)
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index eb3988c2e4..16d77c5e27 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -31,12 +31,11 @@ typedef struct ASCIIConsoleData {
typedef struct SCLPConsole {
SCLPEvent event;
CharDriverState *chr;
- /* io vector */
- uint8_t *iov; /* iov buffer pointer */
- uint8_t *iov_sclp; /* pointer to SCLP read offset */
- uint8_t *iov_bs; /* pointer byte stream read offset */
- uint32_t iov_data_len; /* length of byte stream in buffer */
- uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
+ uint8_t iov[SIZE_BUFFER_VT220];
+ uint32_t iov_sclp; /* offset in buf for SCLP read operation */
+ uint32_t iov_bs; /* offset in buf for char layer read operation */
+ uint32_t iov_data_len; /* length of byte stream in buffer */
+ uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
qemu_irq irq_read_vt220;
} SCLPConsole;
@@ -47,7 +46,7 @@ static int chr_can_read(void *opaque)
{
SCLPConsole *scon = opaque;
- return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0;
+ return SIZE_BUFFER_VT220 - scon->iov_data_len;
}
/* Receive n bytes from character layer, save in iov buffer,
@@ -55,13 +54,11 @@ static int chr_can_read(void *opaque)
static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
int size)
{
- assert(scon->iov);
-
/* read data must fit into current buffer */
assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
/* put byte-stream from character layer into buffer */
- memcpy(scon->iov_bs, buf, size);
+ memcpy(&scon->iov[scon->iov_bs], buf, size);
scon->iov_data_len += size;
scon->iov_sclp_rest += size;
scon->iov_bs += size;
@@ -80,34 +77,11 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
qemu_irq_raise(scon->irq_read_vt220);
}
-static void chr_event(void *opaque, int event)
-{
- SCLPConsole *scon = opaque;
-
- switch (event) {
- case CHR_EVENT_OPENED:
- if (!scon->iov) {
- scon->iov = g_malloc0(SIZE_BUFFER_VT220);
- scon->iov_sclp = scon->iov;
- scon->iov_bs = scon->iov;
- scon->iov_data_len = 0;
- scon->iov_sclp_rest = 0;
- }
- break;
- case CHR_EVENT_CLOSED:
- if (scon->iov) {
- g_free(scon->iov);
- scon->iov = NULL;
- }
- break;
- }
-}
-
/* functions to be called by event facility */
-static int event_type(void)
+static bool can_handle_event(uint8_t type)
{
- return SCLP_EVENT_ASCII_CONSOLE_DATA;
+ return type == SCLP_EVENT_ASCII_CONSOLE_DATA;
}
static unsigned int send_mask(void)
@@ -134,17 +108,17 @@ static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
/* if all data fit into provided SCLP buffer */
if (avail >= cons->iov_sclp_rest) {
/* copy character byte-stream to SCLP buffer */
- memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
+ memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest);
*size = cons->iov_sclp_rest + 1;
- cons->iov_sclp = cons->iov;
- cons->iov_bs = cons->iov;
+ cons->iov_sclp = 0;
+ cons->iov_bs = 0;
cons->iov_data_len = 0;
cons->iov_sclp_rest = 0;
event->event_pending = false;
/* data provided and no more data pending */
} else {
/* if provided buffer is too small, just copy part */
- memcpy(buf, cons->iov_sclp, avail);
+ memcpy(buf, &cons->iov[cons->iov_sclp], avail);
*size = avail + 1;
cons->iov_sclp_rest -= avail;
cons->iov_sclp += avail;
@@ -223,9 +197,26 @@ static void trigger_ascii_console_data(void *opaque, int n, int level)
sclp_service_interrupt(0);
}
+static const VMStateDescription vmstate_sclpconsole = {
+ .name = "sclpconsole",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(event.event_pending, SCLPConsole),
+ VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
+ VMSTATE_UINT32(iov_sclp, SCLPConsole),
+ VMSTATE_UINT32(iov_bs, SCLPConsole),
+ VMSTATE_UINT32(iov_data_len, SCLPConsole),
+ VMSTATE_UINT32(iov_sclp_rest, SCLPConsole),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
/* qemu object creation and initialization functions */
/* tell character layer our call-back functions */
+
static int console_init(SCLPEvent *event)
{
static bool console_available;
@@ -237,10 +228,9 @@ static int console_init(SCLPEvent *event)
return -1;
}
console_available = true;
- event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
if (scon->chr) {
qemu_chr_add_handlers(scon->chr, chr_can_read,
- chr_read, chr_event, scon);
+ chr_read, NULL, scon);
}
scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
NULL, 1);
@@ -248,6 +238,18 @@ static int console_init(SCLPEvent *event)
return 0;
}
+static void console_reset(DeviceState *dev)
+{
+ SCLPEvent *event = SCLP_EVENT(dev);
+ SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+ event->event_pending = false;
+ scon->iov_sclp = 0;
+ scon->iov_bs = 0;
+ scon->iov_data_len = 0;
+ scon->iov_sclp_rest = 0;
+}
+
static int console_exit(SCLPEvent *event)
{
return 0;
@@ -264,11 +266,13 @@ static void console_class_init(ObjectClass *klass, void *data)
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
dc->props = console_properties;
+ dc->reset = console_reset;
+ dc->vmsd = &vmstate_sclpconsole;
ec->init = console_init;
ec->exit = console_exit;
ec->get_send_mask = send_mask;
ec->get_receive_mask = receive_mask;
- ec->event_type = event_type;
+ ec->can_handle_event = can_handle_event;
ec->read_event_data = read_event_data;
ec->write_event_data = write_event_data;
}
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 6e9fb3b695..540df82600 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -31,5 +31,4 @@ obj-$(CONFIG_TCX) += tcx.o
obj-$(CONFIG_VGA) += vga.o
-common-obj-$(CONFIG_QXL) += qxl-logger.o qxl-render.o
-obj-$(CONFIG_QXL) += qxl.o
+common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index c50e285e21..ee2db0da1a 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -313,9 +313,7 @@ static ram_addr_t qxl_rom_size(void)
sizeof(qxl_modes);
uint32_t rom_size = 8192; /* two pages */
- required_rom_size = MAX(required_rom_size, TARGET_PAGE_SIZE);
- required_rom_size = msb_mask(required_rom_size * 2 - 1);
- assert(required_rom_size <= rom_size);
+ QEMU_BUILD_BUG_ON(required_rom_size > rom_size);
return rom_size;
}
@@ -364,7 +362,7 @@ static void init_qxl_rom(PCIQXLDevice *d)
num_pages = d->vga.vram_size;
num_pages -= ram_header_size;
num_pages -= surface0_area_size;
- num_pages = num_pages / TARGET_PAGE_SIZE;
+ num_pages = num_pages / QXL_PAGE_SIZE;
rom->draw_area_offset = cpu_to_le32(0);
rom->surface0_area_size = cpu_to_le32(surface0_area_size);
@@ -416,9 +414,8 @@ static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
intptr_t offset;
offset = ptr - base;
- offset &= ~(TARGET_PAGE_SIZE-1);
assert(offset < qxl->vga.vram_size);
- qxl_set_dirty(&qxl->vga.vram, offset, offset + TARGET_PAGE_SIZE);
+ qxl_set_dirty(&qxl->vga.vram, offset, offset + 3);
}
/* can be called from spice server thread context */
@@ -528,7 +525,8 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
info->num_memslots = NUM_MEMSLOTS;
info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
info->internal_groupslot_id = 0;
- info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
+ info->qxl_ram_size =
+ le32_to_cpu(qxl->shadow_rom.num_pages) << QXL_PAGE_BITS;
info->n_surfaces = qxl->ssd.num_surfaces;
}
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
index 8e9b0c299e..84f0182383 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -27,6 +27,9 @@ enum qxl_mode {
#define QXL_NUM_DIRTY_RECTS 64
+#define QXL_PAGE_BITS 12
+#define QXL_PAGE_SIZE (1 << QXL_PAGE_BITS);
+
typedef struct PCIQXLDevice {
PCIDevice pci;
SimpleSpiceDisplay ssd;
diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
index 92aabb83b5..383938d1bc 100644
--- a/hw/i386/kvm/clock.c
+++ b/hw/i386/kvm/clock.c
@@ -39,7 +39,7 @@ static void kvmclock_vm_state_change(void *opaque, int running,
RunState state)
{
KVMClockState *s = opaque;
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL);
int ret;
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index d3a6fbe1f9..1c2dbf59cf 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -510,9 +510,8 @@ static void vapic_reset(DeviceState *dev)
{
VAPICROMState *s = VAPIC(dev);
- if (s->state == VAPIC_ACTIVE) {
- s->state = VAPIC_STANDBY;
- }
+ s->state = VAPIC_INACTIVE;
+ s->rom_state_paddr = 0;
vapic_enable_tpr_reporting(false);
}
@@ -578,7 +577,7 @@ static int patch_hypercalls(VAPICROMState *s)
* enable write access to the option ROM so that variables can be updated by
* the guest.
*/
-static void vapic_map_rom_writable(VAPICROMState *s)
+static int vapic_map_rom_writable(VAPICROMState *s)
{
hwaddr rom_paddr = s->rom_state_paddr & ROM_BLOCK_MASK;
MemoryRegionSection section;
@@ -599,6 +598,9 @@ static void vapic_map_rom_writable(VAPICROMState *s)
/* read ROM size from RAM region */
ram = memory_region_get_ram_ptr(section.mr);
rom_size = ram[rom_paddr + 2] * ROM_BLOCK_SIZE;
+ if (rom_size == 0) {
+ return -1;
+ }
s->rom_size = rom_size;
/* We need to round to avoid creating subpages
@@ -612,11 +614,15 @@ static void vapic_map_rom_writable(VAPICROMState *s)
memory_region_add_subregion_overlap(as, rom_paddr, &s->rom, 1000);
s->rom_mapped_writable = true;
memory_region_unref(section.mr);
+
+ return 0;
}
static int vapic_prepare(VAPICROMState *s)
{
- vapic_map_rom_writable(s);
+ if (vapic_map_rom_writable(s) < 0) {
+ return -1;
+ }
if (patch_hypercalls(s) < 0) {
return -1;
@@ -659,6 +665,7 @@ static void vapic_write(void *opaque, hwaddr addr, uint64_t data,
}
if (vapic_prepare(s) < 0) {
s->state = VAPIC_INACTIVE;
+ s->rom_state_paddr = 0;
break;
}
break;
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index d3f274cc28..151d25e0b7 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -32,6 +32,7 @@
#include "hw/loader.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
+#include "qemu/iov.h"
#include "e1000_regs.h"
@@ -64,6 +65,8 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
/* this is the size past which hardware will drop packets when setting LPE=1 */
#define MAXIMUM_ETHERNET_LPE_SIZE 16384
+#define MAXIMUM_ETHERNET_HDR_LEN (14+4)
+
/*
* HW models:
* E1000_DEV_ID_82540EM works with Windows and Linux
@@ -899,7 +902,7 @@ static uint64_t rx_desc_base(E1000State *s)
}
static ssize_t
-e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
{
E1000State *s = qemu_get_nic_opaque(nc);
PCIDevice *d = PCI_DEVICE(s);
@@ -908,8 +911,12 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
unsigned int n, rdt;
uint32_t rdh_start;
uint16_t vlan_special = 0;
- uint8_t vlan_status = 0, vlan_offset = 0;
+ uint8_t vlan_status = 0;
uint8_t min_buf[MIN_BUF_SIZE];
+ struct iovec min_iov;
+ uint8_t *filter_buf = iov->iov_base;
+ size_t size = iov_size(iov, iovcnt);
+ size_t iov_ofs = 0;
size_t desc_offset;
size_t desc_size;
size_t total_size;
@@ -924,10 +931,16 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
/* Pad to minimum Ethernet frame length */
if (size < sizeof(min_buf)) {
- memcpy(min_buf, buf, size);
+ iov_to_buf(iov, iovcnt, 0, min_buf, size);
memset(&min_buf[size], 0, sizeof(min_buf) - size);
- buf = min_buf;
- size = sizeof(min_buf);
+ min_iov.iov_base = filter_buf = min_buf;
+ min_iov.iov_len = size = sizeof(min_buf);
+ iovcnt = 1;
+ iov = &min_iov;
+ } else if (iov->iov_len < MAXIMUM_ETHERNET_HDR_LEN) {
+ /* This is very unlikely, but may happen. */
+ iov_to_buf(iov, iovcnt, 0, min_buf, MAXIMUM_ETHERNET_HDR_LEN);
+ filter_buf = min_buf;
}
/* Discard oversized packets if !LPE and !SBP. */
@@ -938,14 +951,24 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
return size;
}
- if (!receive_filter(s, buf, size))
+ if (!receive_filter(s, filter_buf, size)) {
return size;
+ }
- if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
- vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
- memmove((uint8_t *)buf + 4, buf, 12);
+ if (vlan_enabled(s) && is_vlan_packet(s, filter_buf)) {
+ vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(filter_buf
+ + 14)));
+ iov_ofs = 4;
+ if (filter_buf == iov->iov_base) {
+ memmove(filter_buf + 4, filter_buf, 12);
+ } else {
+ iov_from_buf(iov, iovcnt, 4, filter_buf, 12);
+ while (iov->iov_len <= iov_ofs) {
+ iov_ofs -= iov->iov_len;
+ iov++;
+ }
+ }
vlan_status = E1000_RXD_STAT_VP;
- vlan_offset = 4;
size -= 4;
}
@@ -967,12 +990,23 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
desc.status |= (vlan_status | E1000_RXD_STAT_DD);
if (desc.buffer_addr) {
if (desc_offset < size) {
+ size_t iov_copy;
+ hwaddr ba = le64_to_cpu(desc.buffer_addr);
size_t copy_size = size - desc_offset;
if (copy_size > s->rxbuf_size) {
copy_size = s->rxbuf_size;
}
- pci_dma_write(d, le64_to_cpu(desc.buffer_addr),
- buf + desc_offset + vlan_offset, copy_size);
+ do {
+ iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
+ pci_dma_write(d, ba, iov->iov_base + iov_ofs, iov_copy);
+ copy_size -= iov_copy;
+ ba += iov_copy;
+ iov_ofs += iov_copy;
+ if (iov_ofs == iov->iov_len) {
+ iov++;
+ iov_ofs = 0;
+ }
+ } while (copy_size);
}
desc_offset += desc_size;
desc.length = cpu_to_le16(desc_size);
@@ -1022,6 +1056,17 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
return size;
}
+static ssize_t
+e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+ const struct iovec iov = {
+ .iov_base = (uint8_t *)buf,
+ .iov_len = size
+ };
+
+ return e1000_receive_iov(nc, &iov, 1);
+}
+
static uint32_t
mac_readreg(E1000State *s, int index)
{
@@ -1448,6 +1493,7 @@ static NetClientInfo net_e1000_info = {
.size = sizeof(NICState),
.can_receive = e1000_can_receive,
.receive = e1000_receive,
+ .receive_iov = e1000_receive_iov,
.cleanup = e1000_cleanup,
.link_status_changed = e1000_set_link_status,
};
diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c
index a8931652b3..865f2f0c59 100644
--- a/hw/net/pcnet-pci.c
+++ b/hw/net/pcnet-pci.c
@@ -134,7 +134,7 @@ static void pcnet_ioport_write(void *opaque, hwaddr addr,
static const MemoryRegionOps pcnet_io_ops = {
.read = pcnet_ioport_read,
.write = pcnet_ioport_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static void pcnet_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
@@ -256,7 +256,7 @@ static const MemoryRegionOps pcnet_mmio_ops = {
.read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl },
.write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel },
},
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static void pci_physical_memory_write(void *dma_opaque, hwaddr addr,
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 54735043b7..0cb652d7f0 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -372,7 +372,7 @@ static void mch_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_mch;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_Q35_MCH;
- k->revision = MCH_HOST_BRIDGE_REVISION_DEFUALT;
+ k->revision = MCH_HOST_BRIDGE_REVISION_DEFAULT;
k->class_id = PCI_CLASS_BRIDGE_HOST;
}
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index a3aceef8f5..25951a020a 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -120,7 +120,7 @@ static uint16_t handle_write_event_buf(SCLPEventFacility *ef,
ec = SCLP_EVENT_GET_CLASS(event);
if (ec->write_event_data &&
- ec->event_type() == event_buf->type) {
+ ec->can_handle_event(event_buf->type)) {
rc = ec->write_event_data(event, event_buf);
break;
}
@@ -183,7 +183,7 @@ static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb,
{
uint16_t rc;
int slen;
- unsigned elen = 0;
+ unsigned elen;
BusChild *kid;
SCLPEvent *event;
SCLPEventClass *ec;
@@ -203,11 +203,11 @@ static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb,
if (mask & ec->get_send_mask()) {
if (ec->read_event_data(event, event_buf, &slen)) {
+ elen = be16_to_cpu(event_buf->length);
+ event_buf = (EventBufferHeader *) ((char *)event_buf + elen);
rc = SCLP_RC_NORMAL_COMPLETION;
}
}
- elen = be16_to_cpu(event_buf->length);
- event_buf = (void *) event_buf + elen;
}
if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
@@ -338,10 +338,19 @@ static int init_event_facility(S390SCLPDevice *sdev)
return 0;
}
+static void reset_event_facility(DeviceState *dev)
+{
+ S390SCLPDevice *sdev = SCLP_S390_DEVICE(dev);
+
+ sdev->ef->receive_mask = 0;
+}
+
static void init_event_facility_class(ObjectClass *klass, void *data)
{
+ DeviceClass *dc = DEVICE_CLASS(klass);
S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
+ dc->reset = reset_event_facility;
k->init = init_event_facility;
}
diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c
index 5fadc86d42..a3c4bd6272 100644
--- a/hw/s390x/sclpquiesce.c
+++ b/hw/s390x/sclpquiesce.c
@@ -22,9 +22,9 @@ typedef struct SignalQuiesce {
uint8_t unit;
} QEMU_PACKED SignalQuiesce;
-static int event_type(void)
+static bool can_handle_event(uint8_t type)
{
- return SCLP_EVENT_SIGNAL_QUIESCE;
+ return type == SCLP_EVENT_SIGNAL_QUIESCE;
}
static unsigned int send_mask(void)
@@ -65,6 +65,17 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
return 1;
}
+static const VMStateDescription vmstate_sclpquiesce = {
+ .name = "sclpquiesce",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(event_pending, SCLPEvent),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
typedef struct QuiesceNotifier QuiesceNotifier;
static struct QuiesceNotifier {
@@ -84,8 +95,6 @@ static void quiesce_powerdown_req(Notifier *n, void *opaque)
static int quiesce_init(SCLPEvent *event)
{
- event->event_type = SCLP_EVENT_SIGNAL_QUIESCE;
-
qn.notifier.notify = quiesce_powerdown_req;
qn.event = event;
@@ -94,15 +103,25 @@ static int quiesce_init(SCLPEvent *event)
return 0;
}
+static void quiesce_reset(DeviceState *dev)
+{
+ SCLPEvent *event = SCLP_EVENT(dev);
+
+ event->event_pending = false;
+}
+
static void quiesce_class_init(ObjectClass *klass, void *data)
{
+ DeviceClass *dc = DEVICE_CLASS(klass);
SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
+ dc->reset = quiesce_reset;
+ dc->vmsd = &vmstate_sclpquiesce;
k->init = quiesce_init;
k->get_send_mask = send_mask;
k->get_receive_mask = receive_mask;
- k->event_type = event_type;
+ k->can_handle_event = can_handle_event;
k->read_event_data = read_event_data;
k->write_event_data = NULL;
}
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 5affc82d2b..36e5f50360 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -7,8 +7,11 @@
* This code is licensed under the LGPL.
*/
-/* ??? Need to check if the {read,write}[wl] routines work properly on
- big-endian targets. */
+/* Note:
+ * LSI53C810 emulation is incorrect, in the sense that it supports
+ * features added in later evolutions. This should not be a problem,
+ * as well-behaved operating systems will not try to use them.
+ */
#include <assert.h>
@@ -278,6 +281,7 @@ typedef struct {
uint32_t script_ram[2048];
} LSIState;
+#define TYPE_LSI53C810 "lsi53c810"
#define TYPE_LSI53C895A "lsi53c895a"
#define LSI53C895A(obj) \
@@ -1515,7 +1519,7 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset)
used for diagnostics, so should be ok. */
return 0;
case 0xc: /* DSTAT */
- tmp = s->dstat | 0x80;
+ tmp = s->dstat | LSI_DSTAT_DFE;
if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
s->dstat = 0;
lsi_update_irq(s);
@@ -1699,8 +1703,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
s->sxfer = val;
break;
case 0x06: /* SDID */
- if ((val & 0xf) != (s->ssid & 0xf))
+ if ((s->ssid & 0x80) && (val & 0xf) != (s->ssid & 0xf)) {
BADF("Destination ID does not match SSID\n");
+ }
s->sdid = val & 0xf;
break;
case 0x07: /* GPREG0 */
@@ -1742,6 +1747,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
case 0x17: /* MBOX1 */
s->mbox1 = val;
break;
+ case 0x18: /* CTEST0 */
+ /* nothing to do */
+ break;
case 0x1a: /* CTEST2 */
s->ctest2 = val & LSI_CTEST2_PCICIE;
break;
@@ -2106,7 +2114,7 @@ static int lsi_scsi_init(PCIDevice *dev)
"lsi-io", 256);
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
- pci_register_bar(dev, 1, 0, &s->mmio_io);
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_io);
pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
QTAILQ_INIT(&s->queue);
@@ -2144,9 +2152,23 @@ static const TypeInfo lsi_info = {
.class_init = lsi_class_init,
};
+static void lsi53c810_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->device_id = PCI_DEVICE_ID_LSI_53C810;
+}
+
+static TypeInfo lsi53c810_info = {
+ .name = TYPE_LSI53C810,
+ .parent = TYPE_LSI53C895A,
+ .class_init = lsi53c810_class_init,
+};
+
static void lsi53c895a_register_types(void)
{
type_register_static(&lsi_info);
+ type_register_static(&lsi53c810_info);
}
type_init(lsi53c895a_register_types)
diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c
index 13f6602ad2..ad77705f8c 100644
--- a/hw/usb/combined-packet.c
+++ b/hw/usb/combined-packet.c
@@ -39,6 +39,7 @@ static void usb_combined_packet_remove(USBCombinedPacket *combined,
p->combined = NULL;
QTAILQ_REMOVE(&combined->packets, p, combined_entry);
if (QTAILQ_EMPTY(&combined->packets)) {
+ qemu_iovec_destroy(&combined->iov);
g_free(combined);
}
}
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 31960c28a8..cf59a1abcf 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -622,6 +622,7 @@ void usb_ep_reset(USBDevice *dev)
dev->ep_ctl.nr = 0;
dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
dev->ep_ctl.ifnum = 0;
+ dev->ep_ctl.max_packet_size = 64;
dev->ep_ctl.dev = dev;
dev->ep_ctl.pipeline = false;
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
@@ -633,6 +634,8 @@ void usb_ep_reset(USBDevice *dev)
dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
dev->ep_in[ep].ifnum = USB_INTERFACE_INVALID;
dev->ep_out[ep].ifnum = USB_INTERFACE_INVALID;
+ dev->ep_in[ep].max_packet_size = 0;
+ dev->ep_out[ep].max_packet_size = 0;
dev->ep_in[ep].dev = dev;
dev->ep_out[ep].dev = dev;
dev->ep_in[ep].pipeline = false;
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index f02231dc87..469c24d768 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -509,6 +509,8 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
unsigned int epid);
static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v);
static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v);
+static USBEndpoint *xhci_epid_to_usbep(XHCIState *xhci,
+ unsigned int slotid, unsigned int epid);
static const char *TRBType_names[] = {
[TRB_RESERVED] = "TRB_RESERVED",
@@ -1138,7 +1140,7 @@ static void xhci_reset_streams(XHCIEPContext *epctx)
static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base)
{
assert(epctx->pstreams == NULL);
- epctx->nr_pstreams = 2 << epctx->max_pstreams;
+ epctx->nr_pstreams = 2 << (epctx->max_pstreams + 1);
epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base);
}
@@ -1245,6 +1247,9 @@ static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci,
epctx->epid = epid;
for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
+ epctx->transfers[i].xhci = xhci;
+ epctx->transfers[i].slotid = slotid;
+ epctx->transfers[i].epid = epid;
usb_packet_init(&epctx->transfers[i].packet);
}
epctx->kick_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_ep_kick_timer, epctx);
@@ -1358,13 +1363,12 @@ 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]);
epctx->transfers[xferi].packet.ep = NULL;
xferi = (xferi + 1) % TD_QUEUE;
}
+
+ ep = xhci_epid_to_usbep(xhci, slotid, epid);
if (ep) {
usb_device_ep_stopped(ep->dev, ep);
}
@@ -1376,6 +1380,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
{
XHCISlot *slot;
XHCIEPContext *epctx;
+ int i;
trace_usb_xhci_ep_disable(slotid, epid);
assert(slotid >= 1 && slotid <= xhci->numslots);
@@ -1396,6 +1401,10 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
xhci_free_streams(epctx);
}
+ for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
+ usb_packet_cleanup(&epctx->transfers[i].packet);
+ }
+
xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED);
timer_free(epctx->kick_timer);
@@ -1696,7 +1705,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
static int xhci_setup_packet(XHCITransfer *xfer)
{
XHCIState *xhci = xfer->xhci;
- USBDevice *dev;
USBEndpoint *ep;
int dir;
@@ -1704,15 +1712,13 @@ static int xhci_setup_packet(XHCITransfer *xfer)
if (xfer->packet.ep) {
ep = xfer->packet.ep;
- dev = ep->dev;
} else {
- if (!xhci->slots[xfer->slotid-1].uport) {
+ ep = xhci_epid_to_usbep(xhci, xfer->slotid, xfer->epid);
+ if (!ep) {
fprintf(stderr, "xhci: slot %d has no device\n",
xfer->slotid);
return -1;
}
- dev = xhci->slots[xfer->slotid-1].uport->dev;
- ep = usb_ep_get(dev, dir, xfer->epid >> 1);
}
xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
@@ -1720,7 +1726,7 @@ static int xhci_setup_packet(XHCITransfer *xfer)
xfer->trbs[0].addr, false, xfer->int_req);
usb_packet_map(&xfer->packet, &xfer->sgl);
DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
- xfer->packet.pid, dev->addr, ep->nr);
+ xfer->packet.pid, ep->dev->addr, ep->nr);
return 0;
}
@@ -2060,9 +2066,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
for (i = 0; i < length; i++) {
assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL));
}
- xfer->xhci = xhci;
- xfer->epid = epid;
- xfer->slotid = slotid;
xfer->streamid = streamid;
if (epid == 1) {
@@ -2075,7 +2078,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
} else {
if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
- ep = xfer->packet.ep;
} else {
if (!xfer->timed_xfer) {
fprintf(stderr, "xhci: error firing data transfer\n");
@@ -2092,6 +2094,8 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
break;
}
}
+
+ ep = xhci_epid_to_usbep(xhci, slotid, epid);
if (ep) {
usb_device_flush_ep_queue(ep->dev, ep);
}
@@ -3321,6 +3325,19 @@ static int xhci_find_epid(USBEndpoint *ep)
}
}
+static USBEndpoint *xhci_epid_to_usbep(XHCIState *xhci,
+ unsigned int slotid, unsigned int epid)
+{
+ assert(slotid >= 1 && slotid <= xhci->numslots);
+
+ if (!xhci->slots[slotid - 1].uport) {
+ return NULL;
+ }
+
+ return usb_ep_get(xhci->slots[slotid - 1].uport->dev,
+ (epid & 1) ? USB_TOKEN_IN : USB_TOKEN_OUT, epid >> 1);
+}
+
static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
unsigned int stream)
{
diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c
deleted file mode 100644
index 39f22810b3..0000000000
--- a/hw/usb/host-bsd.c
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * BSD host USB redirector
- *
- * Copyright (c) 2006 Lonnie Mendez
- * Portions of code and concepts borrowed from
- * usb-linux.c and libusb's bsd.c and are copyright their respective owners.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu-common.h"
-#include "monitor/monitor.h"
-#include "hw/usb.h"
-
-/* usb.h declares these */
-#undef USB_SPEED_HIGH
-#undef USB_SPEED_FULL
-#undef USB_SPEED_LOW
-
-#include <sys/ioctl.h>
-#ifndef __DragonFly__
-#include <dev/usb/usb.h>
-#else
-#include <bus/usb/usb.h>
-#endif
-
-/* This value has maximum potential at 16.
- * You should also set hw.usb.debug to gain
- * more detailed view.
- */
-//#define DEBUG
-#define UGEN_DEBUG_LEVEL 0
-
-
-typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
- int vendor_id, int product_id,
- const char *product_name, int speed);
-static int usb_host_find_device(int *pbus_num, int *paddr,
- const char *devname);
-
-typedef struct USBHostDevice {
- USBDevice dev;
- int ep_fd[USB_MAX_ENDPOINTS];
- int devfd;
- char devpath[32];
-} USBHostDevice;
-
-
-static int ensure_ep_open(USBHostDevice *dev, int ep, int mode)
-{
- char buf[32];
- int fd;
-
- /* Get the address for this endpoint */
- ep = UE_GET_ADDR(ep);
-
- if (dev->ep_fd[ep] < 0) {
-#if defined(__FreeBSD__) || defined(__DragonFly__)
- snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->devpath, ep);
-#else
- snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->devpath, ep);
-#endif
- /* Try to open it O_RDWR first for those devices which have in and out
- * endpoints with the same address (eg 0x02 and 0x82)
- */
- fd = open(buf, O_RDWR);
- if (fd < 0 && errno == ENXIO)
- fd = open(buf, mode);
- if (fd < 0) {
-#ifdef DEBUG
- printf("ensure_ep_open: failed to open device endpoint %s: %s\n",
- buf, strerror(errno));
-#endif
- }
- dev->ep_fd[ep] = fd;
- }
-
- return dev->ep_fd[ep];
-}
-
-static void ensure_eps_closed(USBHostDevice *dev)
-{
- int epnum = 1;
-
- if (!dev)
- return;
-
- while (epnum < USB_MAX_ENDPOINTS) {
- if (dev->ep_fd[epnum] >= 0) {
- close(dev->ep_fd[epnum]);
- dev->ep_fd[epnum] = -1;
- }
- epnum++;
- }
-}
-
-static void usb_host_handle_reset(USBDevice *dev)
-{
-#if 0
- USBHostDevice *s = (USBHostDevice *)dev;
-#endif
-}
-
-/* XXX:
- * -check device states against transfer requests
- * and return appropriate response
- */
-static void usb_host_handle_control(USBDevice *dev,
- USBPacket *p,
- int request,
- int value,
- int index,
- int length,
- uint8_t *data)
-{
- USBHostDevice *s = (USBHostDevice *)dev;
- struct usb_ctl_request req;
- struct usb_alt_interface aiface;
- int ret, timeout = 50;
-
- if ((request >> 8) == UT_WRITE_DEVICE &&
- (request & 0xff) == UR_SET_ADDRESS) {
-
- /* specific SET_ADDRESS support */
- dev->addr = value;
- } else if ((request >> 8) == UT_WRITE_DEVICE &&
- (request & 0xff) == UR_SET_CONFIG) {
-
- ensure_eps_closed(s); /* can't do this without all eps closed */
-
- ret = ioctl(s->devfd, USB_SET_CONFIG, &value);
- if (ret < 0) {
-#ifdef DEBUG
- printf("handle_control: failed to set configuration - %s\n",
- strerror(errno));
-#endif
- p->status = USB_RET_STALL;
- }
- } else if ((request >> 8) == UT_WRITE_INTERFACE &&
- (request & 0xff) == UR_SET_INTERFACE) {
-
- aiface.uai_interface_index = index;
- aiface.uai_alt_no = value;
-
- ensure_eps_closed(s); /* can't do this without all eps closed */
- ret = ioctl(s->devfd, USB_SET_ALTINTERFACE, &aiface);
- if (ret < 0) {
-#ifdef DEBUG
- printf("handle_control: failed to set alternate interface - %s\n",
- strerror(errno));
-#endif
- p->status = USB_RET_STALL;
- }
- } else {
- req.ucr_request.bmRequestType = request >> 8;
- req.ucr_request.bRequest = request & 0xff;
- USETW(req.ucr_request.wValue, value);
- USETW(req.ucr_request.wIndex, index);
- USETW(req.ucr_request.wLength, length);
- req.ucr_data = data;
- req.ucr_flags = USBD_SHORT_XFER_OK;
-
- ret = ioctl(s->devfd, USB_SET_TIMEOUT, &timeout);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
- if (ret < 0 && errno != EINVAL) {
-#else
- if (ret < 0) {
-#endif
-#ifdef DEBUG
- printf("handle_control: setting timeout failed - %s\n",
- strerror(errno));
-#endif
- }
-
- ret = ioctl(s->devfd, USB_DO_REQUEST, &req);
- /* ugen returns EIO for usbd_do_request_ no matter what
- * happens with the transfer */
- if (ret < 0) {
-#ifdef DEBUG
- printf("handle_control: error after request - %s\n",
- strerror(errno));
-#endif
- p->status = USB_RET_NAK; /* STALL */
- } else {
- p->actual_length = req.ucr_actlen;
- }
- }
-}
-
-static void usb_host_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBHostDevice *s = (USBHostDevice *)dev;
- int ret, fd, mode;
- int one = 1, shortpacket = 0, timeout = 50;
- sigset_t new_mask, old_mask;
- uint8_t devep = p->ep->nr;
-
- /* protect data transfers from SIGALRM signal */
- sigemptyset(&new_mask);
- sigaddset(&new_mask, SIGALRM);
- sigprocmask(SIG_BLOCK, &new_mask, &old_mask);
-
- if (p->pid == USB_TOKEN_IN) {
- devep |= 0x80;
- mode = O_RDONLY;
- shortpacket = 1;
- } else {
- mode = O_WRONLY;
- }
-
- fd = ensure_ep_open(s, devep, mode);
- if (fd < 0) {
- sigprocmask(SIG_SETMASK, &old_mask, NULL);
- p->status = USB_RET_NODEV;
- return;
- }
-
- if (ioctl(fd, USB_SET_TIMEOUT, &timeout) < 0) {
-#ifdef DEBUG
- printf("handle_data: failed to set timeout - %s\n",
- strerror(errno));
-#endif
- }
-
- if (shortpacket) {
- if (ioctl(fd, USB_SET_SHORT_XFER, &one) < 0) {
-#ifdef DEBUG
- printf("handle_data: failed to set short xfer mode - %s\n",
- strerror(errno));
-#endif
- sigprocmask(SIG_SETMASK, &old_mask, NULL);
- }
- }
-
- if (p->pid == USB_TOKEN_IN)
- ret = readv(fd, p->iov.iov, p->iov.niov);
- else
- ret = writev(fd, p->iov.iov, p->iov.niov);
-
- sigprocmask(SIG_SETMASK, &old_mask, NULL);
-
- if (ret < 0) {
-#ifdef DEBUG
- printf("handle_data: error after %s data - %s\n",
- pid == USB_TOKEN_IN ? "reading" : "writing", strerror(errno));
-#endif
- switch(errno) {
- case ETIMEDOUT:
- case EINTR:
- p->status = USB_RET_NAK;
- break;
- default:
- p->status = USB_RET_STALL;
- }
- } else {
- p->actual_length = ret;
- }
-}
-
-static void usb_host_handle_destroy(USBDevice *opaque)
-{
- USBHostDevice *s = (USBHostDevice *)opaque;
- int i;
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- if (s->ep_fd[i] >= 0)
- close(s->ep_fd[i]);
-
- if (s->devfd < 0)
- return;
-
- close(s->devfd);
-
- g_free(s);
-}
-
-static int usb_host_initfn(USBDevice *dev)
-{
- dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
- return 0;
-}
-
-USBDevice *usb_host_device_open(USBBus *guest_bus, const char *devname)
-{
- struct usb_device_info bus_info, dev_info;
- USBDevice *d = NULL, *ret = NULL;
- USBHostDevice *dev;
- char ctlpath[PATH_MAX + 1];
- char buspath[PATH_MAX + 1];
- int bfd, dfd, bus, address, i;
- int ugendebug = UGEN_DEBUG_LEVEL;
-
- if (usb_host_find_device(&bus, &address, devname) < 0) {
- goto fail;
- }
-
- snprintf(buspath, PATH_MAX, "/dev/usb%d", bus);
-
- bfd = open(buspath, O_RDWR);
- if (bfd < 0) {
-#ifdef DEBUG
- printf("usb_host_device_open: failed to open usb bus - %s\n",
- strerror(errno));
-#endif
- goto fail;
- }
-
- bus_info.udi_addr = address;
- if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0) {
-#ifdef DEBUG
- printf("usb_host_device_open: failed to grab bus information - %s\n",
- strerror(errno));
-#endif
- goto fail_bfd;
- }
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
- snprintf(ctlpath, PATH_MAX, "/dev/%s", bus_info.udi_devnames[0]);
-#else
- snprintf(ctlpath, PATH_MAX, "/dev/%s.00", bus_info.udi_devnames[0]);
-#endif
-
- dfd = open(ctlpath, O_RDWR);
- if (dfd < 0) {
- dfd = open(ctlpath, O_RDONLY);
- if (dfd < 0) {
-#ifdef DEBUG
- printf("usb_host_device_open: failed to open usb device %s - %s\n",
- ctlpath, strerror(errno));
-#endif
- }
- goto fail_dfd;
- }
-
- if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
-#ifdef DEBUG
- printf("usb_host_device_open: failed to grab device info - %s\n",
- strerror(errno));
-#endif
- goto fail_dfd;
- }
-
- d = usb_create(guest_bus, "usb-host");
- dev = DO_UPCAST(USBHostDevice, dev, d);
-
- if (dev_info.udi_speed == 1) {
- dev->dev.speed = USB_SPEED_LOW - 1;
- dev->dev.speedmask = USB_SPEED_MASK_LOW;
- } else {
- dev->dev.speed = USB_SPEED_FULL - 1;
- dev->dev.speedmask = USB_SPEED_MASK_FULL;
- }
-
- if (strncmp(dev_info.udi_product, "product", 7) != 0) {
- pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
- dev_info.udi_product);
- } else {
- snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
- "host:%s", devname);
- }
-
- pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/");
- pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]);
-
- /* Mark the endpoints as not yet open */
- for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
- dev->ep_fd[i] = -1;
- }
-
- ioctl(dfd, USB_SETDEBUG, &ugendebug);
-
- ret = (USBDevice *)dev;
-
-fail_dfd:
- close(dfd);
-fail_bfd:
- close(bfd);
-fail:
- return ret;
-}
-
-static void usb_host_class_initfn(ObjectClass *klass, void *data)
-{
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->product_desc = "USB Host Device";
- uc->init = usb_host_initfn;
- uc->handle_reset = usb_host_handle_reset;
- uc->handle_control = usb_host_handle_control;
- uc->handle_data = usb_host_handle_data;
- uc->handle_destroy = usb_host_handle_destroy;
-}
-
-static const TypeInfo usb_host_dev_info = {
- .name = "usb-host",
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBHostDevice),
- .class_init = usb_host_class_initfn,
-};
-
-static void usb_host_register_types(void)
-{
- type_register_static(&usb_host_dev_info);
-}
-
-type_init(usb_host_register_types)
-
-static int usb_host_scan(void *opaque, USBScanFunc *func)
-{
- struct usb_device_info bus_info;
- struct usb_device_info dev_info;
- uint16_t vendor_id, product_id, class_id, speed;
- int bfd, dfd, bus, address;
- char busbuf[20], devbuf[20], product_name[256];
- int ret = 0;
-
- for (bus = 0; bus < 10; bus++) {
-
- snprintf(busbuf, sizeof(busbuf) - 1, "/dev/usb%d", bus);
- bfd = open(busbuf, O_RDWR);
- if (bfd < 0)
- continue;
-
- for (address = 1; address < 127; address++) {
-
- bus_info.udi_addr = address;
- if (ioctl(bfd, USB_DEVICEINFO, &bus_info) < 0)
- continue;
-
- /* only list devices that can be used by generic layer */
- if (strncmp(bus_info.udi_devnames[0], "ugen", 4) != 0)
- continue;
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
- snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s", bus_info.udi_devnames[0]);
-#else
- snprintf(devbuf, sizeof(devbuf) - 1, "/dev/%s.00", bus_info.udi_devnames[0]);
-#endif
-
- dfd = open(devbuf, O_RDONLY);
- if (dfd < 0) {
-#ifdef DEBUG
- printf("usb_host_scan: couldn't open device %s - %s\n", devbuf,
- strerror(errno));
-#endif
- continue;
- }
-
- if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0)
- printf("usb_host_scan: couldn't get device information for %s - %s\n",
- devbuf, strerror(errno));
-
- /* XXX: might need to fixup endianness of word values before copying over */
-
- vendor_id = dev_info.udi_vendorNo;
- product_id = dev_info.udi_productNo;
- class_id = dev_info.udi_class;
- speed = dev_info.udi_speed;
-
- if (strncmp(dev_info.udi_product, "product", 7) != 0)
- pstrcpy(product_name, sizeof(product_name),
- dev_info.udi_product);
- else
- product_name[0] = '\0';
-
- ret = func(opaque, bus, address, class_id, vendor_id,
- product_id, product_name, speed);
-
- close(dfd);
-
- if (ret)
- goto the_end;
- }
-
- close(bfd);
- }
-
-the_end:
- return ret;
-}
-
-typedef struct FindDeviceState {
- int vendor_id;
- int product_id;
- int bus_num;
- int addr;
-} FindDeviceState;
-
-static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
- int class_id,
- int vendor_id, int product_id,
- const char *product_name, int speed)
-{
- FindDeviceState *s = opaque;
- if (vendor_id == s->vendor_id &&
- product_id == s->product_id) {
- s->bus_num = bus_num;
- s->addr = addr;
- return 1;
- } else {
- return 0;
- }
-}
-
-
-/* the syntax is :
- 'bus.addr' (decimal numbers) or
- 'vendor_id:product_id' (hexa numbers) */
-static int usb_host_find_device(int *pbus_num, int *paddr,
- const char *devname)
-{
- const char *p;
- int ret;
- FindDeviceState fs;
-
- p = strchr(devname, '.');
- if (p) {
- *pbus_num = strtoul(devname, NULL, 0);
- *paddr = strtoul(p + 1, NULL, 0);
- return 0;
- }
- p = strchr(devname, ':');
- if (p) {
- fs.vendor_id = strtoul(devname, NULL, 16);
- fs.product_id = strtoul(p + 1, NULL, 16);
- ret = usb_host_scan(&fs, usb_host_find_device_scan);
- if (ret) {
- *pbus_num = fs.bus_num;
- *paddr = fs.addr;
- return 0;
- }
- }
- return -1;
-}
-
-/**********************/
-/* USB host device info */
-
-struct usb_class_info {
- int class;
- const char *class_name;
-};
-
-static const struct usb_class_info usb_class_info[] = {
- { USB_CLASS_AUDIO, "Audio"},
- { USB_CLASS_COMM, "Communication"},
- { USB_CLASS_HID, "HID"},
- { USB_CLASS_HUB, "Hub" },
- { USB_CLASS_PHYSICAL, "Physical" },
- { USB_CLASS_PRINTER, "Printer" },
- { USB_CLASS_MASS_STORAGE, "Storage" },
- { USB_CLASS_CDC_DATA, "Data" },
- { USB_CLASS_APP_SPEC, "Application Specific" },
- { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
- { USB_CLASS_STILL_IMAGE, "Still Image" },
- { USB_CLASS_CSCID, "Smart Card" },
- { USB_CLASS_CONTENT_SEC, "Content Security" },
- { -1, NULL }
-};
-
-static const char *usb_class_str(uint8_t class)
-{
- const struct usb_class_info *p;
- for (p = usb_class_info; p->class != -1; p++) {
- if (p->class == class)
- break;
- }
- return p->class_name;
-}
-
-static void usb_info_device(Monitor *mon, int bus_num, int addr, int class_id,
- int vendor_id, int product_id,
- const char *product_name,
- int speed)
-{
- const char *class_str, *speed_str;
-
- switch(speed) {
- case USB_SPEED_LOW:
- speed_str = "1.5";
- break;
- case USB_SPEED_FULL:
- speed_str = "12";
- break;
- case USB_SPEED_HIGH:
- speed_str = "480";
- break;
- default:
- speed_str = "?";
- break;
- }
-
- monitor_printf(mon, " Device %d.%d, speed %s Mb/s\n",
- bus_num, addr, speed_str);
- class_str = usb_class_str(class_id);
- if (class_str)
- monitor_printf(mon, " %s:", class_str);
- else
- monitor_printf(mon, " Class %02x:", class_id);
- monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
- if (product_name[0] != '\0')
- monitor_printf(mon, ", %s", product_name);
- monitor_printf(mon, "\n");
-}
-
-static int usb_host_info_device(void *opaque,
- int bus_num, int addr,
- int class_id,
- int vendor_id, int product_id,
- const char *product_name,
- int speed)
-{
- Monitor *mon = opaque;
-
- usb_info_device(mon, bus_num, addr, class_id, vendor_id, product_id,
- product_name, speed);
- return 0;
-}
-
-void usb_host_info(Monitor *mon, const QDict *qdict)
-{
- usb_host_scan(mon, usb_host_info_device);
-}
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
deleted file mode 100644
index 65cd3b444c..0000000000
--- a/hw/usb/host-linux.c
+++ /dev/null
@@ -1,1911 +0,0 @@
-/*
- * Linux host USB redirector
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * Copyright (c) 2008 Max Krasnyansky
- * Support for host device auto connect & disconnect
- * Major rewrite to support fully async operation
- *
- * Copyright 2008 TJ <linux@tjworld.net>
- * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition
- * to the legacy /proc/bus/usb USB device discovery and handling
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-#include <dirent.h>
-#include <sys/ioctl.h>
-
-#include <linux/usbdevice_fs.h>
-#include <linux/version.h>
-#include "hw/usb.h"
-#include "hw/usb/desc.h"
-#include "hw/usb/host.h"
-
-#ifdef CONFIG_USB_LIBUSB
-# define DEVNAME "usb-host-linux"
-#else
-# define DEVNAME "usb-host"
-#endif
-
-/* We redefine it to avoid version problems */
-struct usb_ctrltransfer {
- uint8_t bRequestType;
- uint8_t bRequest;
- uint16_t wValue;
- uint16_t wIndex;
- uint16_t wLength;
- uint32_t timeout;
- void *data;
-};
-
-typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
- int class_id, int vendor_id, int product_id,
- const char *product_name, int speed);
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
-
-#define PRODUCT_NAME_SZ 32
-#define MAX_PORTLEN 16
-
-/* endpoint association data */
-#define ISO_FRAME_DESC_PER_URB 32
-
-/* devio.c limits single requests to 16k */
-#define MAX_USBFS_BUFFER_SIZE 16384
-
-typedef struct AsyncURB AsyncURB;
-
-struct endp_data {
- uint8_t halted;
- uint8_t iso_started;
- AsyncURB *iso_urb;
- int iso_urb_idx;
- int iso_buffer_used;
- int inflight;
-};
-
-enum USBHostDeviceOptions {
- USB_HOST_OPT_PIPELINE,
-};
-
-typedef struct USBHostDevice {
- USBDevice dev;
- int fd;
- int hub_fd;
- int hub_port;
-
- uint8_t descr[8192];
- int descr_len;
- int closing;
- uint32_t iso_urb_count;
- uint32_t options;
- Notifier exit;
- QEMUBH *bh;
-
- struct endp_data ep_in[USB_MAX_ENDPOINTS];
- struct endp_data ep_out[USB_MAX_ENDPOINTS];
- QLIST_HEAD(, AsyncURB) aurbs;
-
- /* Host side address */
- int bus_num;
- int addr;
- char port[MAX_PORTLEN];
- struct USBAutoFilter match;
- int32_t bootindex;
- int seen, errcount;
-
- QTAILQ_ENTRY(USBHostDevice) next;
-} USBHostDevice;
-
-static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs);
-
-static int usb_host_close(USBHostDevice *dev);
-static void usb_host_auto_check(void *unused);
-static int usb_host_read_file(char *line, size_t line_size,
- const char *device_file, const char *device_name);
-static void usb_linux_update_endp_table(USBHostDevice *s);
-
-static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
-{
- static const int usbfs[] = {
- [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL,
- [USB_ENDPOINT_XFER_ISOC] = USBDEVFS_URB_TYPE_ISO,
- [USB_ENDPOINT_XFER_BULK] = USBDEVFS_URB_TYPE_BULK,
- [USB_ENDPOINT_XFER_INT] = USBDEVFS_URB_TYPE_INTERRUPT,
- };
- uint8_t type = p->ep->type;
- assert(type < ARRAY_SIZE(usbfs));
- return usbfs[type];
-}
-
-static int usb_host_do_reset(USBHostDevice *dev)
-{
- struct timeval s, e;
- uint32_t usecs;
- int ret;
-
- gettimeofday(&s, NULL);
- ret = ioctl(dev->fd, USBDEVFS_RESET);
- gettimeofday(&e, NULL);
- usecs = (e.tv_sec - s.tv_sec) * 1000000;
- usecs += e.tv_usec - s.tv_usec;
- if (usecs > 1000000) {
- /* more than a second, something is fishy, broken usb device? */
- fprintf(stderr, "husb: device %d:%d reset took %d.%06d seconds\n",
- dev->bus_num, dev->addr, usecs / 1000000, usecs % 1000000);
- }
- return ret;
-}
-
-static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
-{
- struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
- assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
- assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
- return eps + ep - 1;
-}
-
-static int is_isoc(USBHostDevice *s, int pid, int ep)
-{
- return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC;
-}
-
-static int is_valid(USBHostDevice *s, int pid, int ep)
-{
- return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID;
-}
-
-static int is_halted(USBHostDevice *s, int pid, int ep)
-{
- return get_endp(s, pid, ep)->halted;
-}
-
-static void clear_halt(USBHostDevice *s, int pid, int ep)
-{
- trace_usb_host_ep_clear_halt(s->bus_num, s->addr, ep);
- get_endp(s, pid, ep)->halted = 0;
-}
-
-static void set_halt(USBHostDevice *s, int pid, int ep)
-{
- if (ep != 0) {
- trace_usb_host_ep_set_halt(s->bus_num, s->addr, ep);
- get_endp(s, pid, ep)->halted = 1;
- }
-}
-
-static int is_iso_started(USBHostDevice *s, int pid, int ep)
-{
- return get_endp(s, pid, ep)->iso_started;
-}
-
-static void clear_iso_started(USBHostDevice *s, int pid, int ep)
-{
- trace_usb_host_iso_stop(s->bus_num, s->addr, ep);
- get_endp(s, pid, ep)->iso_started = 0;
-}
-
-static void set_iso_started(USBHostDevice *s, int pid, int ep)
-{
- struct endp_data *e = get_endp(s, pid, ep);
-
- trace_usb_host_iso_start(s->bus_num, s->addr, ep);
- if (!e->iso_started) {
- e->iso_started = 1;
- e->inflight = 0;
- }
-}
-
-static int change_iso_inflight(USBHostDevice *s, int pid, int ep, int value)
-{
- struct endp_data *e = get_endp(s, pid, ep);
-
- e->inflight += value;
- return e->inflight;
-}
-
-static void set_iso_urb(USBHostDevice *s, int pid, int ep, AsyncURB *iso_urb)
-{
- get_endp(s, pid, ep)->iso_urb = iso_urb;
-}
-
-static AsyncURB *get_iso_urb(USBHostDevice *s, int pid, int ep)
-{
- return get_endp(s, pid, ep)->iso_urb;
-}
-
-static void set_iso_urb_idx(USBHostDevice *s, int pid, int ep, int i)
-{
- get_endp(s, pid, ep)->iso_urb_idx = i;
-}
-
-static int get_iso_urb_idx(USBHostDevice *s, int pid, int ep)
-{
- return get_endp(s, pid, ep)->iso_urb_idx;
-}
-
-static void set_iso_buffer_used(USBHostDevice *s, int pid, int ep, int i)
-{
- get_endp(s, pid, ep)->iso_buffer_used = i;
-}
-
-static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
-{
- return get_endp(s, pid, ep)->iso_buffer_used;
-}
-
-/*
- * Async URB state.
- * We always allocate iso packet descriptors even for bulk transfers
- * to simplify allocation and casts.
- */
-struct AsyncURB
-{
- struct usbdevfs_urb urb;
- struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
- USBHostDevice *hdev;
- QLIST_ENTRY(AsyncURB) next;
-
- /* For regular async urbs */
- USBPacket *packet;
- int more; /* large transfer, more urbs follow */
-
- /* For buffered iso handling */
- int iso_frame_idx; /* -1 means in flight */
-};
-
-static AsyncURB *async_alloc(USBHostDevice *s)
-{
- AsyncURB *aurb = g_malloc0(sizeof(AsyncURB));
- aurb->hdev = s;
- QLIST_INSERT_HEAD(&s->aurbs, aurb, next);
- return aurb;
-}
-
-static void async_free(AsyncURB *aurb)
-{
- QLIST_REMOVE(aurb, next);
- g_free(aurb);
-}
-
-static void do_disconnect(USBHostDevice *s)
-{
- usb_host_close(s);
- usb_host_auto_check(NULL);
-}
-
-static void async_complete(void *opaque)
-{
- USBHostDevice *s = opaque;
- AsyncURB *aurb;
- int urbs = 0;
-
- while (1) {
- USBPacket *p;
-
- int r = ioctl(s->fd, USBDEVFS_REAPURBNDELAY, &aurb);
- if (r < 0) {
- if (errno == EAGAIN) {
- if (urbs > 2) {
- /* indicates possible latency issues */
- trace_usb_host_iso_many_urbs(s->bus_num, s->addr, urbs);
- }
- return;
- }
- if (errno == ENODEV) {
- if (!s->closing) {
- trace_usb_host_disconnect(s->bus_num, s->addr);
- do_disconnect(s);
- }
- return;
- }
-
- perror("USBDEVFS_REAPURBNDELAY");
- return;
- }
-
- DPRINTF("husb: async completed. aurb %p status %d alen %d\n",
- aurb, aurb->urb.status, aurb->urb.actual_length);
-
- /* If this is a buffered iso urb mark it as complete and don't do
- anything else (it is handled further in usb_host_handle_iso_data) */
- if (aurb->iso_frame_idx == -1) {
- int inflight;
- int pid = (aurb->urb.endpoint & USB_DIR_IN) ?
- USB_TOKEN_IN : USB_TOKEN_OUT;
- int ep = aurb->urb.endpoint & 0xf;
- if (aurb->urb.status == -EPIPE) {
- set_halt(s, pid, ep);
- }
- aurb->iso_frame_idx = 0;
- urbs++;
- inflight = change_iso_inflight(s, pid, ep, -1);
- if (inflight == 0 && is_iso_started(s, pid, ep)) {
- /* can be latency issues, or simply end of stream */
- trace_usb_host_iso_out_of_bufs(s->bus_num, s->addr, ep);
- }
- continue;
- }
-
- p = aurb->packet;
- trace_usb_host_urb_complete(s->bus_num, s->addr, aurb, aurb->urb.status,
- aurb->urb.actual_length, aurb->more);
-
- if (p) {
- switch (aurb->urb.status) {
- case 0:
- p->actual_length += aurb->urb.actual_length;
- if (!aurb->more) {
- /* Clear previous ASYNC status */
- p->status = USB_RET_SUCCESS;
- }
- break;
-
- case -EPIPE:
- set_halt(s, p->pid, p->ep->nr);
- p->status = USB_RET_STALL;
- break;
-
- case -EOVERFLOW:
- p->status = USB_RET_BABBLE;
- break;
-
- default:
- p->status = USB_RET_IOERROR;
- break;
- }
-
- if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, aurb->urb.actual_length);
- usb_generic_async_ctrl_complete(&s->dev, p);
- } else if (!aurb->more) {
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, aurb->urb.actual_length);
- usb_packet_complete(&s->dev, p);
- }
- }
-
- async_free(aurb);
- }
-}
-
-static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
-{
- USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
- AsyncURB *aurb;
-
- trace_usb_host_req_canceled(s->bus_num, s->addr, p);
-
- QLIST_FOREACH(aurb, &s->aurbs, next) {
- if (p != aurb->packet) {
- continue;
- }
-
- trace_usb_host_urb_canceled(s->bus_num, s->addr, aurb);
-
- /* Mark it as dead (see async_complete above) */
- aurb->packet = NULL;
-
- int r = ioctl(s->fd, USBDEVFS_DISCARDURB, aurb);
- if (r < 0) {
- DPRINTF("husb: async. discard urb failed errno %d\n", errno);
- }
- }
-}
-
-static int usb_host_open_device(int bus, int addr)
-{
- const char *usbfs = NULL;
- char filename[32];
- struct stat st;
- int fd, rc;
-
- rc = stat("/dev/bus/usb", &st);
- if (rc == 0 && S_ISDIR(st.st_mode)) {
- /* udev-created device nodes available */
- usbfs = "/dev/bus/usb";
- } else {
- /* fallback: usbfs mounted below /proc */
- usbfs = "/proc/bus/usb";
- }
-
- snprintf(filename, sizeof(filename), "%s/%03d/%03d",
- usbfs, bus, addr);
- fd = open(filename, O_RDWR | O_NONBLOCK);
- if (fd < 0) {
- fprintf(stderr, "husb: open %s: %s\n", filename, strerror(errno));
- }
- return fd;
-}
-
-static int usb_host_claim_port(USBHostDevice *s)
-{
-#ifdef USBDEVFS_CLAIM_PORT
- char *h, hub_name[64], line[1024];
- int hub_addr, ret;
-
- snprintf(hub_name, sizeof(hub_name), "%d-%s",
- s->match.bus_num, s->match.port);
-
- /* try strip off last ".$portnr" to get hub */
- h = strrchr(hub_name, '.');
- if (h != NULL) {
- s->hub_port = atoi(h+1);
- *h = '\0';
- } else {
- /* no dot in there -> it is the root hub */
- snprintf(hub_name, sizeof(hub_name), "usb%d",
- s->match.bus_num);
- s->hub_port = atoi(s->match.port);
- }
-
- if (!usb_host_read_file(line, sizeof(line), "devnum",
- hub_name)) {
- return -1;
- }
- if (sscanf(line, "%d", &hub_addr) != 1) {
- return -1;
- }
-
- s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr);
- if (s->hub_fd < 0) {
- return -1;
- }
-
- ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
- if (ret < 0) {
- close(s->hub_fd);
- s->hub_fd = -1;
- return -1;
- }
-
- trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
- return 0;
-#else
- return -1;
-#endif
-}
-
-static void usb_host_release_port(USBHostDevice *s)
-{
- if (s->hub_fd == -1) {
- return;
- }
-#ifdef USBDEVFS_RELEASE_PORT
- ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
-#endif
- close(s->hub_fd);
- s->hub_fd = -1;
-}
-
-static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
-{
- /* earlier Linux 2.4 do not support that */
-#ifdef USBDEVFS_DISCONNECT
- struct usbdevfs_ioctl ctrl;
- int ret, interface;
-
- for (interface = 0; interface < nb_interfaces; interface++) {
- ctrl.ioctl_code = USBDEVFS_DISCONNECT;
- ctrl.ifno = interface;
- ctrl.data = 0;
- ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
- if (ret < 0 && errno != ENODATA) {
- perror("USBDEVFS_DISCONNECT");
- return -1;
- }
- }
-#endif
- return 0;
-}
-
-static int usb_linux_get_num_interfaces(USBHostDevice *s)
-{
- char device_name[64], line[1024];
- int num_interfaces = 0;
-
- sprintf(device_name, "%d-%s", s->bus_num, s->port);
- if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
- device_name)) {
- return -1;
- }
- if (sscanf(line, "%d", &num_interfaces) != 1) {
- return -1;
- }
- return num_interfaces;
-}
-
-static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
-{
- const char *op = NULL;
- int dev_descr_len, config_descr_len;
- int interface, nb_interfaces;
- int ret, i;
-
- for (i = 0; i < USB_MAX_INTERFACES; i++) {
- dev->dev.altsetting[i] = 0;
- }
-
- if (configuration == 0) { /* address state - ignore */
- dev->dev.ninterfaces = 0;
- dev->dev.configuration = 0;
- return 1;
- }
-
- DPRINTF("husb: claiming interfaces. config %d\n", configuration);
-
- i = 0;
- dev_descr_len = dev->descr[0];
- if (dev_descr_len > dev->descr_len) {
- fprintf(stderr, "husb: update iface failed. descr too short\n");
- return 0;
- }
-
- i += dev_descr_len;
- while (i < dev->descr_len) {
- DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n",
- i, dev->descr_len,
- dev->descr[i], dev->descr[i+1]);
-
- if (dev->descr[i+1] != USB_DT_CONFIG) {
- i += dev->descr[i];
- continue;
- }
- config_descr_len = dev->descr[i];
-
- DPRINTF("husb: config #%d need %d\n", dev->descr[i + 5], configuration);
-
- if (configuration == dev->descr[i + 5]) {
- configuration = dev->descr[i + 5];
- break;
- }
-
- i += config_descr_len;
- }
-
- if (i >= dev->descr_len) {
- fprintf(stderr,
- "husb: update iface failed. no matching configuration\n");
- return 0;
- }
- nb_interfaces = dev->descr[i + 4];
-
- if (usb_host_disconnect_ifaces(dev, nb_interfaces) < 0) {
- goto fail;
- }
-
- /* XXX: only grab if all interfaces are free */
- for (interface = 0; interface < nb_interfaces; interface++) {
- op = "USBDEVFS_CLAIMINTERFACE";
- ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
- if (ret < 0) {
- goto fail;
- }
- }
-
- trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
- nb_interfaces, configuration);
-
- dev->dev.ninterfaces = nb_interfaces;
- dev->dev.configuration = configuration;
- return 1;
-
-fail:
- if (errno == ENODEV) {
- do_disconnect(dev);
- }
- perror(op);
- return 0;
-}
-
-static int usb_host_release_interfaces(USBHostDevice *s)
-{
- int ret, i;
-
- trace_usb_host_release_interfaces(s->bus_num, s->addr);
-
- for (i = 0; i < s->dev.ninterfaces; i++) {
- ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
- if (ret < 0) {
- perror("USBDEVFS_RELEASEINTERFACE");
- return 0;
- }
- }
- return 1;
-}
-
-static void usb_host_handle_reset(USBDevice *dev)
-{
- USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
-
- trace_usb_host_reset(s->bus_num, s->addr);
-
- usb_host_do_reset(s);
-
- usb_host_claim_interfaces(s, 0);
- usb_linux_update_endp_table(s);
-}
-
-static void usb_host_handle_destroy(USBDevice *dev)
-{
- USBHostDevice *s = (USBHostDevice *)dev;
-
- usb_host_release_port(s);
- usb_host_close(s);
- QTAILQ_REMOVE(&hostdevs, s, next);
- qemu_remove_exit_notifier(&s->exit);
-}
-
-/* iso data is special, we need to keep enough urbs in flight to make sure
- that the controller never runs out of them, otherwise the device will
- likely suffer a buffer underrun / overrun. */
-static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
-{
- AsyncURB *aurb;
- int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep);
-
- aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
- for (i = 0; i < s->iso_urb_count; i++) {
- aurb[i].urb.endpoint = ep;
- aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len;
- aurb[i].urb.buffer = g_malloc(aurb[i].urb.buffer_length);
- aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO;
- aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP;
- aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB;
- for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++)
- aurb[i].urb.iso_frame_desc[j].length = len;
- if (pid == USB_TOKEN_IN) {
- aurb[i].urb.endpoint |= 0x80;
- /* Mark as fully consumed (idle) */
- aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB;
- }
- }
- set_iso_urb(s, pid, ep, aurb);
-
- return aurb;
-}
-
-static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep)
-{
- AsyncURB *aurb;
- int i, ret, killed = 0, free = 1;
-
- aurb = get_iso_urb(s, pid, ep);
- if (!aurb) {
- return;
- }
-
- for (i = 0; i < s->iso_urb_count; i++) {
- /* in flight? */
- if (aurb[i].iso_frame_idx == -1) {
- ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]);
- if (ret < 0) {
- perror("USBDEVFS_DISCARDURB");
- free = 0;
- continue;
- }
- killed++;
- }
- }
-
- /* Make sure any urbs we've killed are reaped before we free them */
- if (killed) {
- async_complete(s);
- }
-
- for (i = 0; i < s->iso_urb_count; i++) {
- g_free(aurb[i].urb.buffer);
- }
-
- if (free)
- g_free(aurb);
- else
- printf("husb: leaking iso urbs because of discard failure\n");
- set_iso_urb(s, pid, ep, NULL);
- set_iso_urb_idx(s, pid, ep, 0);
- clear_iso_started(s, pid, ep);
-}
-
-static void urb_status_to_usb_ret(int status, USBPacket *p)
-{
- switch (status) {
- case -EPIPE:
- p->status = USB_RET_STALL;
- break;
- case -EOVERFLOW:
- p->status = USB_RET_BABBLE;
- break;
- default:
- p->status = USB_RET_IOERROR;
- }
-}
-
-static void usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
-{
- AsyncURB *aurb;
- int i, j, max_packet_size, offset, len;
- uint8_t *buf;
-
- max_packet_size = p->ep->max_packet_size;
- if (max_packet_size == 0) {
- p->status = USB_RET_NAK;
- return;
- }
-
- aurb = get_iso_urb(s, p->pid, p->ep->nr);
- if (!aurb) {
- aurb = usb_host_alloc_iso(s, p->pid, p->ep->nr);
- }
-
- i = get_iso_urb_idx(s, p->pid, p->ep->nr);
- j = aurb[i].iso_frame_idx;
- if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) {
- if (in) {
- /* Check urb status */
- if (aurb[i].urb.status) {
- urb_status_to_usb_ret(aurb[i].urb.status, p);
- /* Move to the next urb */
- aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1;
- /* Check frame status */
- } else if (aurb[i].urb.iso_frame_desc[j].status) {
- urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status, p);
- /* Check the frame fits */
- } else if (aurb[i].urb.iso_frame_desc[j].actual_length
- > p->iov.size) {
- printf("husb: received iso data is larger then packet\n");
- p->status = USB_RET_BABBLE;
- /* All good copy data over */
- } else {
- len = aurb[i].urb.iso_frame_desc[j].actual_length;
- buf = aurb[i].urb.buffer +
- j * aurb[i].urb.iso_frame_desc[0].length;
- usb_packet_copy(p, buf, len);
- }
- } else {
- len = p->iov.size;
- offset = (j == 0) ? 0 : get_iso_buffer_used(s, p->pid, p->ep->nr);
-
- /* Check the frame fits */
- if (len > max_packet_size) {
- printf("husb: send iso data is larger then max packet size\n");
- p->status = USB_RET_NAK;
- return;
- }
-
- /* All good copy data over */
- usb_packet_copy(p, aurb[i].urb.buffer + offset, len);
- aurb[i].urb.iso_frame_desc[j].length = len;
- offset += len;
- set_iso_buffer_used(s, p->pid, p->ep->nr, offset);
-
- /* Start the stream once we have buffered enough data */
- if (!is_iso_started(s, p->pid, p->ep->nr) && i == 1 && j == 8) {
- set_iso_started(s, p->pid, p->ep->nr);
- }
- }
- aurb[i].iso_frame_idx++;
- if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
- i = (i + 1) % s->iso_urb_count;
- set_iso_urb_idx(s, p->pid, p->ep->nr, i);
- }
- } else {
- if (in) {
- set_iso_started(s, p->pid, p->ep->nr);
- } else {
- DPRINTF("hubs: iso out error no free buffer, dropping packet\n");
- }
- }
-
- if (is_iso_started(s, p->pid, p->ep->nr)) {
- /* (Re)-submit all fully consumed / filled urbs */
- for (i = 0; i < s->iso_urb_count; i++) {
- if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) {
- if (ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]) < 0) {
- perror("USBDEVFS_SUBMITURB");
- if (!in || p->status == USB_RET_SUCCESS) {
- switch(errno) {
- case ETIMEDOUT:
- p->status = USB_RET_NAK;
- break;
- case EPIPE:
- default:
- p->status = USB_RET_STALL;
- }
- }
- break;
- }
- aurb[i].iso_frame_idx = -1;
- change_iso_inflight(s, p->pid, p->ep->nr, 1);
- }
- }
- }
-}
-
-static void usb_host_handle_data(USBDevice *dev, USBPacket *p)
-{
- USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
- struct usbdevfs_urb *urb;
- AsyncURB *aurb;
- int ret, rem, prem, v;
- uint8_t *pbuf;
- uint8_t ep;
-
- trace_usb_host_req_data(s->bus_num, s->addr, p,
- p->pid == USB_TOKEN_IN,
- p->ep->nr, p->iov.size);
-
- if (!is_valid(s, p->pid, p->ep->nr)) {
- p->status = USB_RET_NAK;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- return;
- }
-
- if (p->pid == USB_TOKEN_IN) {
- ep = p->ep->nr | 0x80;
- } else {
- ep = p->ep->nr;
- }
-
- if (is_halted(s, p->pid, p->ep->nr)) {
- unsigned int arg = ep;
- ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
- if (ret < 0) {
- perror("USBDEVFS_CLEAR_HALT");
- p->status = USB_RET_NAK;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- return;
- }
- clear_halt(s, p->pid, p->ep->nr);
- }
-
- if (is_isoc(s, p->pid, p->ep->nr)) {
- usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN);
- return;
- }
-
- v = 0;
- prem = 0;
- pbuf = NULL;
- rem = p->iov.size;
- do {
- if (prem == 0 && rem > 0) {
- assert(v < p->iov.niov);
- prem = p->iov.iov[v].iov_len;
- pbuf = p->iov.iov[v].iov_base;
- assert(prem <= rem);
- v++;
- }
- aurb = async_alloc(s);
- aurb->packet = p;
-
- urb = &aurb->urb;
- urb->endpoint = ep;
- urb->type = usb_host_usbfs_type(s, p);
- urb->usercontext = s;
- urb->buffer = pbuf;
- urb->buffer_length = prem;
-
- if (urb->buffer_length > MAX_USBFS_BUFFER_SIZE) {
- urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
- }
- pbuf += urb->buffer_length;
- prem -= urb->buffer_length;
- rem -= urb->buffer_length;
- if (rem) {
- aurb->more = 1;
- }
-
- trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
- urb->buffer_length, aurb->more);
- ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
-
- DPRINTF("husb: data submit: ep 0x%x, len %u, more %d, packet %p, aurb %p\n",
- urb->endpoint, urb->buffer_length, aurb->more, p, aurb);
-
- if (ret < 0) {
- perror("USBDEVFS_SUBMITURB");
- async_free(aurb);
-
- switch(errno) {
- case ETIMEDOUT:
- p->status = USB_RET_NAK;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- break;
- case EPIPE:
- default:
- p->status = USB_RET_STALL;
- trace_usb_host_req_complete(s->bus_num, s->addr, p,
- p->status, p->actual_length);
- }
- return;
- }
- } while (rem > 0);
-
- p->status = USB_RET_ASYNC;
-}
-
-static int ctrl_error(void)
-{
- if (errno == ETIMEDOUT) {
- return USB_RET_NAK;
- } else {
- return USB_RET_STALL;
- }
-}
-
-static void usb_host_set_address(USBHostDevice *s, int addr)
-{
- trace_usb_host_set_address(s->bus_num, s->addr, addr);
- s->dev.addr = addr;
-}
-
-static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p)
-{
- int ret, first = 1;
-
- trace_usb_host_set_config(s->bus_num, s->addr, config);
-
- usb_host_release_interfaces(s);
-
-again:
- ret = ioctl(s->fd, USBDEVFS_SETCONFIGURATION, &config);
-
- DPRINTF("husb: ctrl set config %d ret %d errno %d\n", config, ret, errno);
-
- if (ret < 0 && errno == EBUSY && first) {
- /* happens if usb device is in use by host drivers */
- int count = usb_linux_get_num_interfaces(s);
- if (count > 0) {
- DPRINTF("husb: busy -> disconnecting %d interfaces\n", count);
- usb_host_disconnect_ifaces(s, count);
- first = 0;
- goto again;
- }
- }
-
- if (ret < 0) {
- p->status = ctrl_error();
- return;
- }
- usb_host_claim_interfaces(s, config);
- usb_linux_update_endp_table(s);
-}
-
-static void usb_host_set_interface(USBHostDevice *s, int iface, int alt,
- USBPacket *p)
-{
- struct usbdevfs_setinterface si;
- int i, ret;
-
- trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
-
- for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
- if (is_isoc(s, USB_TOKEN_IN, i)) {
- usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
- }
- if (is_isoc(s, USB_TOKEN_OUT, i)) {
- usb_host_stop_n_free_iso(s, USB_TOKEN_OUT, i);
- }
- }
-
- if (iface >= USB_MAX_INTERFACES) {
- p->status = USB_RET_STALL;
- return;
- }
-
- si.interface = iface;
- si.altsetting = alt;
- ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
-
- DPRINTF("husb: ctrl set iface %d altset %d ret %d errno %d\n",
- iface, alt, ret, errno);
-
- if (ret < 0) {
- p->status = ctrl_error();
- return;
- }
-
- s->dev.altsetting[iface] = alt;
- usb_linux_update_endp_table(s);
-}
-
-static void usb_host_handle_control(USBDevice *dev, USBPacket *p,
- int request, int value, int index, int length, uint8_t *data)
-{
- USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
- struct usbdevfs_urb *urb;
- AsyncURB *aurb;
- int ret;
-
- /*
- * Process certain standard device requests.
- * These are infrequent and are processed synchronously.
- */
-
- /* Note request is (bRequestType << 8) | bRequest */
- trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
-
- switch (request) {
- case DeviceOutRequest | USB_REQ_SET_ADDRESS:
- usb_host_set_address(s, value);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- usb_host_set_config(s, value & 0xff, p);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- usb_host_set_interface(s, index, value, p);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status);
- return;
-
- case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
- if (value == 0) { /* clear halt */
- int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
- ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index);
- clear_halt(s, pid, index & 0x0f);
- trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0);
- return;
- }
- }
-
- /* The rest are asynchronous */
- if (length > sizeof(dev->data_buf)) {
- fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
- length, sizeof(dev->data_buf));
- p->status = USB_RET_STALL;
- return;
- }
-
- aurb = async_alloc(s);
- aurb->packet = p;
-
- /*
- * Setup ctrl transfer.
- *
- * s->ctrl is laid out such that data buffer immediately follows
- * 'req' struct which is exactly what usbdevfs expects.
- */
- urb = &aurb->urb;
-
- urb->type = USBDEVFS_URB_TYPE_CONTROL;
- urb->endpoint = p->ep->nr;
-
- urb->buffer = &dev->setup_buf;
- urb->buffer_length = length + 8;
-
- urb->usercontext = s;
-
- trace_usb_host_urb_submit(s->bus_num, s->addr, aurb,
- urb->buffer_length, aurb->more);
- ret = ioctl(s->fd, USBDEVFS_SUBMITURB, urb);
-
- DPRINTF("husb: submit ctrl. len %u aurb %p\n", urb->buffer_length, aurb);
-
- if (ret < 0) {
- DPRINTF("husb: submit failed. errno %d\n", errno);
- async_free(aurb);
-
- switch(errno) {
- case ETIMEDOUT:
- p->status = USB_RET_NAK;
- break;
- case EPIPE:
- default:
- p->status = USB_RET_STALL;
- break;
- }
- return;
- }
-
- p->status = USB_RET_ASYNC;
-}
-
-static void usb_linux_update_endp_table(USBHostDevice *s)
-{
- static const char *tname[] = {
- [USB_ENDPOINT_XFER_CONTROL] = "control",
- [USB_ENDPOINT_XFER_ISOC] = "isoc",
- [USB_ENDPOINT_XFER_BULK] = "bulk",
- [USB_ENDPOINT_XFER_INT] = "int",
- };
- uint8_t devep, type;
- uint16_t mps, v, p;
- int ep, pid;
- unsigned int i, configuration = -1, interface = -1, altsetting = -1;
- struct endp_data *epd;
- USBDescriptor *d;
- bool active = false;
-
- usb_ep_reset(&s->dev);
-
- for (i = 0;; i += d->bLength) {
- if (i+2 >= s->descr_len) {
- break;
- }
- d = (void *)(s->descr + i);
- if (d->bLength < 2) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "descriptor too short");
- return;
- }
- if (i + d->bLength > s->descr_len) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "descriptor too long");
- return;
- }
- switch (d->bDescriptorType) {
- case 0:
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "invalid descriptor type");
- return;
- case USB_DT_DEVICE:
- if (d->bLength < 0x12) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "device descriptor too short");
- return;
- }
- v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo;
- p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo;
- trace_usb_host_parse_device(s->bus_num, s->addr, v, p);
- break;
- case USB_DT_CONFIG:
- if (d->bLength < 0x09) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "config descriptor too short");
- return;
- }
- configuration = d->u.config.bConfigurationValue;
- active = (configuration == s->dev.configuration);
- trace_usb_host_parse_config(s->bus_num, s->addr,
- configuration, active);
- break;
- case USB_DT_INTERFACE:
- if (d->bLength < 0x09) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "interface descriptor too short");
- return;
- }
- interface = d->u.interface.bInterfaceNumber;
- altsetting = d->u.interface.bAlternateSetting;
- active = (configuration == s->dev.configuration) &&
- (altsetting == s->dev.altsetting[interface]);
- trace_usb_host_parse_interface(s->bus_num, s->addr,
- interface, altsetting, active);
- break;
- case USB_DT_ENDPOINT:
- if (d->bLength < 0x07) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "endpoint descriptor too short");
- return;
- }
- devep = d->u.endpoint.bEndpointAddress;
- pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
- ep = devep & 0xf;
- if (ep == 0) {
- trace_usb_host_parse_error(s->bus_num, s->addr,
- "invalid endpoint address");
- return;
- }
-
- type = d->u.endpoint.bmAttributes & 0x3;
- mps = d->u.endpoint.wMaxPacketSize_lo |
- (d->u.endpoint.wMaxPacketSize_hi << 8);
- trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep,
- (devep & USB_DIR_IN) ? "in" : "out",
- tname[type], active);
-
- if (active) {
- usb_ep_set_max_packet_size(&s->dev, pid, ep, mps);
- assert(usb_ep_get_type(&s->dev, pid, ep) ==
- USB_ENDPOINT_XFER_INVALID);
- usb_ep_set_type(&s->dev, pid, ep, type);
- usb_ep_set_ifnum(&s->dev, pid, ep, interface);
- if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
- (type == USB_ENDPOINT_XFER_BULK) &&
- (pid == USB_TOKEN_OUT)) {
- usb_ep_set_pipeline(&s->dev, pid, ep, true);
- }
-
- epd = get_endp(s, pid, ep);
- epd->halted = 0;
- }
-
- break;
- default:
- trace_usb_host_parse_unknown(s->bus_num, s->addr,
- d->bLength, d->bDescriptorType);
- break;
- }
- }
-}
-
-/*
- * Check if we can safely redirect a usb2 device to a usb1 virtual controller,
- * this function assumes this is safe, if:
- * 1) There are no isoc endpoints
- * 2) There are no interrupt endpoints with a max_packet_size > 64
- * Note bulk endpoints with a max_packet_size > 64 in theory also are not
- * usb1 compatible, but in practice this seems to work fine.
- */
-static int usb_linux_full_speed_compat(USBHostDevice *dev)
-{
- int i, packet_size;
-
- /*
- * usb_linux_update_endp_table only registers info about ep in the current
- * interface altsettings, so we need to parse the descriptors again.
- */
- for (i = 0; (i + 5) < dev->descr_len; i += dev->descr[i]) {
- if (dev->descr[i + 1] == USB_DT_ENDPOINT) {
- switch (dev->descr[i + 3] & 0x3) {
- case 0x00: /* CONTROL */
- break;
- case 0x01: /* ISO */
- return 0;
- case 0x02: /* BULK */
- break;
- case 0x03: /* INTERRUPT */
- packet_size = dev->descr[i + 4] + (dev->descr[i + 5] << 8);
- if (packet_size > 64)
- return 0;
- break;
- }
- }
- }
- return 1;
-}
-
-static int usb_host_open(USBHostDevice *dev, int bus_num,
- int addr, const char *port,
- const char *prod_name, int speed)
-{
- int fd = -1, ret;
-
- trace_usb_host_open_started(bus_num, addr);
-
- if (dev->fd != -1) {
- goto fail;
- }
-
- fd = usb_host_open_device(bus_num, addr);
- if (fd < 0) {
- goto fail;
- }
- DPRINTF("husb: opened %s\n", buf);
-
- dev->bus_num = bus_num;
- dev->addr = addr;
- pstrcpy(dev->port, sizeof(dev->port), port);
- dev->fd = fd;
-
- /* read the device description */
- dev->descr_len = read(fd, dev->descr, sizeof(dev->descr));
- if (dev->descr_len <= 0) {
- perror("husb: reading device data failed");
- goto fail;
- }
-
-#ifdef DEBUG
- {
- int x;
- printf("=== begin dumping device descriptor data ===\n");
- for (x = 0; x < dev->descr_len; x++) {
- printf("%02x ", dev->descr[x]);
- }
- printf("\n=== end dumping device descriptor data ===\n");
- }
-#endif
-
-
- /* start unconfigured -- we'll wait for the guest to set a configuration */
- if (!usb_host_claim_interfaces(dev, 0)) {
- goto fail;
- }
-
- usb_ep_init(&dev->dev);
- usb_linux_update_endp_table(dev);
-
- if (speed == -1) {
- struct usbdevfs_connectinfo ci;
-
- ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
- if (ret < 0) {
- perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
- goto fail;
- }
-
- if (ci.slow) {
- speed = USB_SPEED_LOW;
- } else {
- speed = USB_SPEED_HIGH;
- }
- }
- dev->dev.speed = speed;
- dev->dev.speedmask = (1 << speed);
- if (dev->dev.speed == USB_SPEED_HIGH && usb_linux_full_speed_compat(dev)) {
- dev->dev.speedmask |= USB_SPEED_MASK_FULL;
- }
-
- trace_usb_host_open_success(bus_num, addr);
-
- if (!prod_name || prod_name[0] == '\0') {
- snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
- "host:%d.%d", bus_num, addr);
- } else {
- pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
- prod_name);
- }
-
- ret = usb_device_attach(&dev->dev);
- if (ret) {
- goto fail;
- }
-
- /* USB devio uses 'write' flag to check for async completions */
- qemu_set_fd_handler(dev->fd, NULL, async_complete, dev);
-
- return 0;
-
-fail:
- trace_usb_host_open_failure(bus_num, addr);
- if (dev->fd != -1) {
- close(dev->fd);
- dev->fd = -1;
- }
- return -1;
-}
-
-static int usb_host_close(USBHostDevice *dev)
-{
- int i;
-
- if (dev->fd == -1) {
- return -1;
- }
-
- trace_usb_host_close(dev->bus_num, dev->addr);
-
- qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
- dev->closing = 1;
- for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
- if (is_isoc(dev, USB_TOKEN_IN, i)) {
- usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
- }
- if (is_isoc(dev, USB_TOKEN_OUT, i)) {
- usb_host_stop_n_free_iso(dev, USB_TOKEN_OUT, i);
- }
- }
- async_complete(dev);
- dev->closing = 0;
- if (dev->dev.attached) {
- usb_device_detach(&dev->dev);
- }
- usb_host_do_reset(dev);
- close(dev->fd);
- dev->fd = -1;
- return 0;
-}
-
-static void usb_host_exit_notifier(struct Notifier *n, void *data)
-{
- USBHostDevice *s = container_of(n, USBHostDevice, exit);
-
- usb_host_release_port(s);
- if (s->fd != -1) {
- usb_host_do_reset(s);
- }
-}
-
-/*
- * This is *NOT* about restoring state. We have absolutely no idea
- * what state the host device is in at the moment and whenever it is
- * still present in the first place. Attemping to contine where we
- * left off is impossible.
- *
- * What we are going to to to here is emulate a surprise removal of
- * the usb device passed through, then kick host scan so the device
- * will get re-attached (and re-initialized by the guest) in case it
- * is still present.
- *
- * As the device removal will change the state of other devices (usb
- * host controller, most likely interrupt controller too) we have to
- * wait with it until *all* vmstate is loaded. Thus post_load just
- * kicks a bottom half which then does the actual work.
- */
-static void usb_host_post_load_bh(void *opaque)
-{
- USBHostDevice *dev = opaque;
-
- if (dev->fd != -1) {
- usb_host_close(dev);
- }
- if (dev->dev.attached) {
- usb_device_detach(&dev->dev);
- }
- usb_host_auto_check(NULL);
-}
-
-static int usb_host_post_load(void *opaque, int version_id)
-{
- USBHostDevice *dev = opaque;
-
- qemu_bh_schedule(dev->bh);
- return 0;
-}
-
-static int usb_host_initfn(USBDevice *dev)
-{
- USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
-
- dev->flags |= (1 << USB_DEV_FLAG_IS_HOST);
- dev->auto_attach = 0;
- s->fd = -1;
- s->hub_fd = -1;
-
- QTAILQ_INSERT_TAIL(&hostdevs, s, next);
- s->exit.notify = usb_host_exit_notifier;
- qemu_add_exit_notifier(&s->exit);
- s->bh = qemu_bh_new(usb_host_post_load_bh, s);
- usb_host_auto_check(NULL);
-
- if (s->match.bus_num != 0 && s->match.port != NULL) {
- usb_host_claim_port(s);
- }
- add_boot_device_path(s->bootindex, &dev->qdev, NULL);
- return 0;
-}
-
-static const VMStateDescription vmstate_usb_host = {
- .name = DEVNAME,
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = usb_host_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_USB_DEVICE(dev, USBHostDevice),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property usb_host_dev_properties[] = {
- DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
- DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
- DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
- DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
- DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
- DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
- DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex, -1),
- DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
- USB_HOST_OPT_PIPELINE, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void usb_host_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
-
- uc->init = usb_host_initfn;
- uc->product_desc = "USB Host Device";
- uc->cancel_packet = usb_host_async_cancel;
- uc->handle_data = usb_host_handle_data;
- uc->handle_control = usb_host_handle_control;
- uc->handle_reset = usb_host_handle_reset;
- uc->handle_destroy = usb_host_handle_destroy;
- dc->vmsd = &vmstate_usb_host;
- dc->props = usb_host_dev_properties;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo usb_host_dev_info = {
- .name = DEVNAME,
- .parent = TYPE_USB_DEVICE,
- .instance_size = sizeof(USBHostDevice),
- .class_init = usb_host_class_initfn,
-};
-
-static void usb_host_register_types(void)
-{
- type_register_static(&usb_host_dev_info);
-}
-
-type_init(usb_host_register_types)
-
-/*
- * Read sys file-system device file
- *
- * @line address of buffer to put file contents in
- * @line_size size of line
- * @device_file path to device file (printf format string)
- * @device_name device being opened (inserted into device_file)
- *
- * @return 0 failed, 1 succeeded ('line' contains data)
- */
-static int usb_host_read_file(char *line, size_t line_size,
- const char *device_file, const char *device_name)
-{
- FILE *f;
- int ret = 0;
- char filename[PATH_MAX];
-
- snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name,
- device_file);
- f = fopen(filename, "r");
- if (f) {
- ret = fgets(line, line_size, f) != NULL;
- fclose(f);
- }
-
- return ret;
-}
-
-/*
- * Use /sys/bus/usb/devices/ directory to determine host's USB
- * devices.
- *
- * This code is based on Robert Schiele's original patches posted to
- * the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
- */
-static int usb_host_scan(void *opaque, USBScanFunc *func)
-{
- DIR *dir = NULL;
- char line[1024];
- int bus_num, addr, speed, class_id, product_id, vendor_id;
- int ret = 0;
- char port[MAX_PORTLEN];
- char product_name[512];
- struct dirent *de;
-
- dir = opendir("/sys/bus/usb/devices");
- if (!dir) {
- perror("husb: opendir /sys/bus/usb/devices");
- fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n");
- goto the_end;
- }
-
- while ((de = readdir(dir))) {
- if (de->d_name[0] != '.' && !strchr(de->d_name, ':')) {
- if (sscanf(de->d_name, "%d-%7[0-9.]", &bus_num, port) < 2) {
- continue;
- }
-
- if (!usb_host_read_file(line, sizeof(line), "devnum", de->d_name)) {
- goto the_end;
- }
- if (sscanf(line, "%d", &addr) != 1) {
- goto the_end;
- }
- if (!usb_host_read_file(line, sizeof(line), "bDeviceClass",
- de->d_name)) {
- goto the_end;
- }
- if (sscanf(line, "%x", &class_id) != 1) {
- goto the_end;
- }
-
- if (!usb_host_read_file(line, sizeof(line), "idVendor",
- de->d_name)) {
- goto the_end;
- }
- if (sscanf(line, "%x", &vendor_id) != 1) {
- goto the_end;
- }
- if (!usb_host_read_file(line, sizeof(line), "idProduct",
- de->d_name)) {
- goto the_end;
- }
- if (sscanf(line, "%x", &product_id) != 1) {
- goto the_end;
- }
- if (!usb_host_read_file(line, sizeof(line), "product",
- de->d_name)) {
- *product_name = 0;
- } else {
- if (strlen(line) > 0) {
- line[strlen(line) - 1] = '\0';
- }
- pstrcpy(product_name, sizeof(product_name), line);
- }
-
- if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
- goto the_end;
- }
- if (!strcmp(line, "5000\n")) {
- speed = USB_SPEED_SUPER;
- } else if (!strcmp(line, "480\n")) {
- speed = USB_SPEED_HIGH;
- } else if (!strcmp(line, "1.5\n")) {
- speed = USB_SPEED_LOW;
- } else {
- speed = USB_SPEED_FULL;
- }
-
- ret = func(opaque, bus_num, addr, port, class_id, vendor_id,
- product_id, product_name, speed);
- if (ret) {
- goto the_end;
- }
- }
- }
- the_end:
- if (dir) {
- closedir(dir);
- }
- return ret;
-}
-
-static QEMUTimer *usb_auto_timer;
-static VMChangeStateEntry *usb_vmstate;
-
-static int usb_host_auto_scan(void *opaque, int bus_num,
- int addr, const char *port,
- int class_id, int vendor_id, int product_id,
- const char *product_name, int speed)
-{
- struct USBAutoFilter *f;
- struct USBHostDevice *s;
-
- /* Ignore hubs */
- if (class_id == 9)
- return 0;
-
- QTAILQ_FOREACH(s, &hostdevs, next) {
- f = &s->match;
-
- if (f->bus_num > 0 && f->bus_num != bus_num) {
- continue;
- }
- if (f->addr > 0 && f->addr != addr) {
- continue;
- }
- if (f->port != NULL && strcmp(f->port, port) != 0) {
- continue;
- }
-
- if (f->vendor_id > 0 && f->vendor_id != vendor_id) {
- continue;
- }
-
- if (f->product_id > 0 && f->product_id != product_id) {
- continue;
- }
- /* We got a match */
- s->seen++;
- if (s->errcount >= 3) {
- return 0;
- }
-
- /* Already attached ? */
- if (s->fd != -1) {
- return 0;
- }
- DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
-
- if (usb_host_open(s, bus_num, addr, port, product_name, speed) < 0) {
- s->errcount++;
- }
- break;
- }
-
- return 0;
-}
-
-static void usb_host_vm_state(void *unused, int running, RunState state)
-{
- if (running) {
- usb_host_auto_check(unused);
- }
-}
-
-static void usb_host_auto_check(void *unused)
-{
- struct USBHostDevice *s;
- int unconnected = 0;
-
- if (runstate_is_running()) {
- usb_host_scan(NULL, usb_host_auto_scan);
-
- QTAILQ_FOREACH(s, &hostdevs, next) {
- if (s->fd == -1) {
- unconnected++;
- }
- if (s->seen == 0) {
- s->errcount = 0;
- }
- s->seen = 0;
- }
-
- if (unconnected == 0) {
- /* nothing to watch */
- if (usb_auto_timer) {
- timer_del(usb_auto_timer);
- trace_usb_host_auto_scan_disabled();
- }
- return;
- }
- }
-
- if (!usb_vmstate) {
- usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL);
- }
- if (!usb_auto_timer) {
- usb_auto_timer = timer_new_ms(QEMU_CLOCK_REALTIME, usb_host_auto_check, NULL);
- if (!usb_auto_timer) {
- return;
- }
- trace_usb_host_auto_scan_enabled();
- }
- timer_mod(usb_auto_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 2000);
-}
-
-#ifndef CONFIG_USB_LIBUSB
-
-/**********************/
-/* USB host device info */
-
-struct usb_class_info {
- int class;
- const char *class_name;
-};
-
-static const struct usb_class_info usb_class_info[] = {
- { USB_CLASS_AUDIO, "Audio"},
- { USB_CLASS_COMM, "Communication"},
- { USB_CLASS_HID, "HID"},
- { USB_CLASS_HUB, "Hub" },
- { USB_CLASS_PHYSICAL, "Physical" },
- { USB_CLASS_PRINTER, "Printer" },
- { USB_CLASS_MASS_STORAGE, "Storage" },
- { USB_CLASS_CDC_DATA, "Data" },
- { USB_CLASS_APP_SPEC, "Application Specific" },
- { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
- { USB_CLASS_STILL_IMAGE, "Still Image" },
- { USB_CLASS_CSCID, "Smart Card" },
- { USB_CLASS_CONTENT_SEC, "Content Security" },
- { -1, NULL }
-};
-
-static const char *usb_class_str(uint8_t class)
-{
- const struct usb_class_info *p;
- for(p = usb_class_info; p->class != -1; p++) {
- if (p->class == class) {
- break;
- }
- }
- return p->class_name;
-}
-
-static void usb_info_device(Monitor *mon, int bus_num,
- int addr, const char *port,
- int class_id, int vendor_id, int product_id,
- const char *product_name,
- int speed)
-{
- const char *class_str, *speed_str;
-
- switch(speed) {
- case USB_SPEED_LOW:
- speed_str = "1.5";
- break;
- case USB_SPEED_FULL:
- speed_str = "12";
- break;
- case USB_SPEED_HIGH:
- speed_str = "480";
- break;
- case USB_SPEED_SUPER:
- speed_str = "5000";
- break;
- default:
- speed_str = "?";
- break;
- }
-
- monitor_printf(mon, " Bus %d, Addr %d, Port %s, Speed %s Mb/s\n",
- bus_num, addr, port, speed_str);
- class_str = usb_class_str(class_id);
- if (class_str) {
- monitor_printf(mon, " %s:", class_str);
- } else {
- monitor_printf(mon, " Class %02x:", class_id);
- }
- monitor_printf(mon, " USB device %04x:%04x", vendor_id, product_id);
- if (product_name[0] != '\0') {
- monitor_printf(mon, ", %s", product_name);
- }
- monitor_printf(mon, "\n");
-}
-
-static int usb_host_info_device(void *opaque, int bus_num, int addr,
- const char *path, int class_id,
- int vendor_id, int product_id,
- const char *product_name,
- int speed)
-{
- Monitor *mon = opaque;
-
- usb_info_device(mon, bus_num, addr, path, class_id, vendor_id, product_id,
- product_name, speed);
- return 0;
-}
-
-static void dec2str(int val, char *str, size_t size)
-{
- if (val == 0) {
- snprintf(str, size, "*");
- } else {
- snprintf(str, size, "%d", val);
- }
-}
-
-static void hex2str(int val, char *str, size_t size)
-{
- if (val == 0) {
- snprintf(str, size, "*");
- } else {
- snprintf(str, size, "%04x", val);
- }
-}
-
-void usb_host_info(Monitor *mon, const QDict *qdict)
-{
- struct USBAutoFilter *f;
- struct USBHostDevice *s;
-
- usb_host_scan(mon, usb_host_info_device);
-
- if (QTAILQ_EMPTY(&hostdevs)) {
- return;
- }
-
- monitor_printf(mon, " Auto filters:\n");
- QTAILQ_FOREACH(s, &hostdevs, next) {
- char bus[10], addr[10], vid[10], pid[10];
- f = &s->match;
- dec2str(f->bus_num, bus, sizeof(bus));
- dec2str(f->addr, addr, sizeof(addr));
- hex2str(f->vendor_id, vid, sizeof(vid));
- hex2str(f->product_id, pid, sizeof(pid));
- monitor_printf(mon, " Bus %s, Addr %s, Port %s, ID %s:%s\n",
- bus, addr, f->port ? f->port : "*", vid, pid);
- }
-}
-
-#endif
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index 6eb7ab676f..56de92ede2 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -85,7 +85,7 @@ typedef struct Q35PCIHost {
#define MCH_HOST_BRIDGE_CONFIG_DATA 0xcfc
/* D0:F0 configuration space */
-#define MCH_HOST_BRIDGE_REVISION_DEFUALT 0x0
+#define MCH_HOST_BRIDGE_REVISION_DEFAULT 0x0
#define MCH_HOST_BRIDGE_PCIEXBAR 0x60 /* 64bit register */
#define MCH_HOST_BRIDGE_PCIEXBAR_SIZE 8 /* 64bit register */
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index 3ddaf6aad5..4c0002beca 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -53,6 +53,7 @@
/* Vendors and devices. Sort key: vendor first, device next. */
#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
+#define PCI_DEVICE_ID_LSI_53C810 0x0001
#define PCI_DEVICE_ID_LSI_53C895A 0x0012
#define PCI_DEVICE_ID_LSI_SAS1078 0x0060
diff --git a/include/hw/s390x/ebcdic.h b/include/hw/s390x/ebcdic.h
new file mode 100644
index 0000000000..1d6fde9c12
--- /dev/null
+++ b/include/hw/s390x/ebcdic.h
@@ -0,0 +1,104 @@
+/*
+ * EBCDIC/ASCII conversion Support
+ *
+ * Copyright (c) 2011 Alexander Graf
+ * Copyright IBM, Corp. 2013
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef EBCDIC_H_
+#define EBCDIC_H_
+
+/* EBCDIC handling */
+static const uint8_t ebcdic2ascii[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
+};
+
+static const uint8_t ascii2ebcdic[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
+ }
+}
+
+static inline void ascii_put(uint8_t *p, const char *ebcdic, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ p[i] = ebcdic2ascii[(uint8_t)ebcdic[i]];
+ }
+}
+
+#endif /* EBCDIC_H_ */
diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h
index 791ab2a6de..7ce7079f9f 100644
--- a/include/hw/s390x/event-facility.h
+++ b/include/hw/s390x/event-facility.h
@@ -19,12 +19,18 @@
#include "qemu/thread.h"
/* SCLP event types */
+#define SCLP_EVENT_OPRTNS_COMMAND 0x01
+#define SCLP_EVENT_MESSAGE 0x02
+#define SCLP_EVENT_PMSGCMD 0x09
#define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a
#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d
/* SCLP event masks */
#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008
#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040
+#define SCLP_EVENT_MASK_OP_CMD 0x80000000
+#define SCLP_EVENT_MASK_MSG 0x40000000
+#define SCLP_EVENT_MASK_PMSGCMD 0x00800000
#define SCLP_UNCONDITIONAL_READ 0x00
#define SCLP_SELECTIVE_READ 0x01
@@ -43,8 +49,8 @@ typedef struct WriteEventMask {
uint16_t mask_length;
uint32_t cp_receive_mask;
uint32_t cp_send_mask;
- uint32_t send_mask;
uint32_t receive_mask;
+ uint32_t send_mask;
} QEMU_PACKED WriteEventMask;
typedef struct EventBufferHeader {
@@ -54,6 +60,80 @@ typedef struct EventBufferHeader {
uint16_t _reserved;
} QEMU_PACKED EventBufferHeader;
+typedef struct MdbHeader {
+ uint16_t length;
+ uint16_t type;
+ uint32_t tag;
+ uint32_t revision_code;
+} QEMU_PACKED MdbHeader;
+
+typedef struct MTO {
+ uint16_t line_type_flags;
+ uint8_t alarm_control;
+ uint8_t _reserved[3];
+ char message[];
+} QEMU_PACKED MTO;
+
+typedef struct GO {
+ uint32_t domid;
+ uint8_t hhmmss_time[8];
+ uint8_t th_time[3];
+ uint8_t _reserved_0;
+ uint8_t dddyyyy_date[7];
+ uint8_t _reserved_1;
+ uint16_t general_msg_flags;
+ uint8_t _reserved_2[10];
+ uint8_t originating_system_name[8];
+ uint8_t job_guest_name[8];
+} QEMU_PACKED GO;
+
+#define MESSAGE_TEXT 0x0004
+
+typedef struct MDBO {
+ uint16_t length;
+ uint16_t type;
+ union {
+ GO go;
+ MTO mto;
+ };
+} QEMU_PACKED MDBO;
+
+typedef struct MDB {
+ MdbHeader header;
+ MDBO mdbo[0];
+} QEMU_PACKED MDB;
+
+typedef struct SclpMsg {
+ EventBufferHeader header;
+ MDB mdb;
+} QEMU_PACKED SclpMsg;
+
+#define GDS_ID_MDSMU 0x1310
+#define GDS_ID_CPMSU 0x1212
+#define GDS_ID_TEXTCMD 0x1320
+
+typedef struct GdsVector {
+ uint16_t length;
+ uint16_t gds_id;
+} QEMU_PACKED GdsVector;
+
+#define GDS_KEY_SELFDEFTEXTMSG 0x31
+#define GDS_KEY_TEXTMSG 0x30
+
+typedef struct GdsSubvector {
+ uint8_t length;
+ uint8_t key;
+} QEMU_PACKED GdsSubvector;
+
+/* MDS Message Unit */
+typedef struct MDMSU {
+ GdsVector mdmsu;
+ GdsVector cpmsu;
+ GdsVector text_command;
+ GdsSubvector self_def_text_message;
+ GdsSubvector text_message;
+} QEMU_PACKED MDMSU;
+
typedef struct WriteEventData {
SCCBHeader h;
EventBufferHeader ebh;
@@ -68,7 +148,6 @@ typedef struct ReadEventData {
typedef struct SCLPEvent {
DeviceState qdev;
bool event_pending;
- uint32_t event_type;
char *name;
} SCLPEvent;
@@ -88,9 +167,8 @@ typedef struct SCLPEventClass {
int (*write_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr);
- /* returns the supported event type */
- int (*event_type)(void);
-
+ /* can we handle this event type? */
+ bool (*can_handle_event)(uint8_t type);
} SCLPEventClass;
#endif
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index b87cf490b1..41885da1a0 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -123,6 +123,7 @@ typedef struct VirtIOBlock {
BlockConf *conf;
VirtIOBlkConf blk;
unsigned short sector_mask;
+ bool original_wce;
VMChangeStateEntry *change;
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
Notifier migration_state_notifier;
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index e4934dd61b..b58903bef5 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -115,6 +115,10 @@ static inline int64_t qemu_clock_get_us(QEMUClockType type)
* Determines whether a clock's default timer list
* has timers attached
*
+ * Note that this function should not be used when other threads also access
+ * the timer list. The return value may be outdated by the time it is acted
+ * upon.
+ *
* Returns: true if the clock's default timer list
* has timers attached
*/
@@ -271,6 +275,10 @@ void timerlist_free(QEMUTimerList *timer_list);
*
* Determine whether a timer list has active timers
*
+ * Note that this function should not be used when other threads also access
+ * the timer list. The return value may be outdated by the time it is acted
+ * upon.
+ *
* Returns: true if the timer list has timers.
*/
bool timerlist_has_timers(QEMUTimerList *timer_list);
@@ -512,6 +520,9 @@ void timer_free(QEMUTimer *ts);
* @ts: the timer
*
* Delete a timer from the active list.
+ *
+ * This function is thread-safe but the timer and its timer list must not be
+ * freed while this function is running.
*/
void timer_del(QEMUTimer *ts);
@@ -521,6 +532,9 @@ void timer_del(QEMUTimer *ts);
* @expire_time: the expiry time in nanoseconds
*
* Modify a timer to expire at @expire_time
+ *
+ * This function is thread-safe but the timer and its timer list must not be
+ * freed while this function is running.
*/
void timer_mod_ns(QEMUTimer *ts, int64_t expire_time);
@@ -531,6 +545,9 @@ void timer_mod_ns(QEMUTimer *ts, int64_t expire_time);
*
* Modify a timer to expiry at @expire_time, taking into
* account the scale associated with the timer.
+ *
+ * This function is thread-safe but the timer and its timer list must not be
+ * freed while this function is running.
*/
void timer_mod(QEMUTimer *ts, int64_t expire_timer);
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 9bbe3db146..3b25f27a7c 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -46,6 +46,7 @@ extern bool kvm_halt_in_kernel_allowed;
extern bool kvm_irqfds_allowed;
extern bool kvm_msi_via_irqfd_allowed;
extern bool kvm_gsi_routing_allowed;
+extern bool kvm_gsi_direct_mapping;
extern bool kvm_readonly_mem_allowed;
#if defined CONFIG_KVM || !defined NEED_CPU_H
@@ -108,6 +109,13 @@ extern bool kvm_readonly_mem_allowed;
#define kvm_gsi_routing_enabled() (kvm_gsi_routing_allowed)
/**
+ * kvm_gsi_direct_mapping:
+ *
+ * Returns: true if GSI direct mapping is enabled.
+ */
+#define kvm_gsi_direct_mapping() (kvm_gsi_direct_mapping)
+
+/**
* kvm_readonly_mem_enabled:
*
* Returns: true if KVM readonly memory is enabled (ie the kernel
@@ -123,6 +131,7 @@ extern bool kvm_readonly_mem_allowed;
#define kvm_irqfds_enabled() (false)
#define kvm_msi_via_irqfd_enabled() (false)
#define kvm_gsi_routing_allowed() (false)
+#define kvm_gsi_direct_mapping() (false)
#define kvm_readonly_mem_enabled() (false)
#endif
@@ -265,16 +274,6 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
uint32_t index, int reg);
-void kvm_cpu_synchronize_state(CPUState *cpu);
-
-/* generic hooks - to be moved/refactored once there are more users */
-
-static inline void cpu_synchronize_state(CPUState *cpu)
-{
- if (kvm_enabled()) {
- kvm_cpu_synchronize_state(cpu);
- }
-}
#if !defined(CONFIG_USER_ONLY)
int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
@@ -283,9 +282,19 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
#endif /* NEED_CPU_H */
+void kvm_cpu_synchronize_state(CPUState *cpu);
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
void kvm_cpu_synchronize_post_init(CPUState *cpu);
+/* generic hooks - to be moved/refactored once there are more users */
+
+static inline void cpu_synchronize_state(CPUState *cpu)
+{
+ if (kvm_enabled()) {
+ kvm_cpu_synchronize_state(cpu);
+ }
+}
+
static inline void cpu_synchronize_post_reset(CPUState *cpu)
{
if (kvm_enabled()) {
diff --git a/kvm-all.c b/kvm-all.c
index b87215c10f..4478969ed2 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -111,6 +111,7 @@ bool kvm_halt_in_kernel_allowed;
bool kvm_irqfds_allowed;
bool kvm_msi_via_irqfd_allowed;
bool kvm_gsi_routing_allowed;
+bool kvm_gsi_direct_mapping;
bool kvm_allowed;
bool kvm_readonly_mem_allowed;
@@ -1069,6 +1070,10 @@ void kvm_irqchip_release_virq(KVMState *s, int virq)
struct kvm_irq_routing_entry *e;
int i;
+ if (kvm_gsi_direct_mapping()) {
+ return;
+ }
+
for (i = 0; i < s->irq_routes->nr; i++) {
e = &s->irq_routes->entries[i];
if (e->gsi == virq) {
@@ -1190,6 +1195,10 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
struct kvm_irq_routing_entry kroute = {};
int virq;
+ if (kvm_gsi_direct_mapping()) {
+ return msg.data & 0xffff;
+ }
+
if (!kvm_gsi_routing_enabled()) {
return -ENOSYS;
}
@@ -1216,6 +1225,10 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg)
{
struct kvm_irq_routing_entry kroute = {};
+ if (kvm_gsi_direct_mapping()) {
+ return 0;
+ }
+
if (!kvm_irqchip_in_kernel()) {
return -ENOSYS;
}
@@ -1322,24 +1335,20 @@ static int kvm_irqchip_create(KVMState *s)
return 0;
}
-static int kvm_max_vcpus(KVMState *s)
+/* Find number of supported CPUs using the recommended
+ * procedure from the kernel API documentation to cope with
+ * older kernels that may be missing capabilities.
+ */
+static int kvm_recommended_vcpus(KVMState *s)
{
- int ret;
-
- /* Find number of supported CPUs using the recommended
- * procedure from the kernel API documentation to cope with
- * older kernels that may be missing capabilities.
- */
- ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS);
- if (ret) {
- return ret;
- }
- ret = kvm_check_extension(s, KVM_CAP_NR_VCPUS);
- if (ret) {
- return ret;
- }
+ int ret = kvm_check_extension(s, KVM_CAP_NR_VCPUS);
+ return (ret) ? ret : 4;
+}
- return 4;
+static int kvm_max_vcpus(KVMState *s)
+{
+ int ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS);
+ return (ret) ? ret : kvm_recommended_vcpus(s);
}
int kvm_init(void)
@@ -1347,11 +1356,19 @@ int kvm_init(void)
static const char upgrade_note[] =
"Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
"(see http://sourceforge.net/projects/kvm).\n";
+ struct {
+ const char *name;
+ int num;
+ } num_cpus[] = {
+ { "SMP", smp_cpus },
+ { "hotpluggable", max_cpus },
+ { NULL, }
+ }, *nc = num_cpus;
+ int soft_vcpus_limit, hard_vcpus_limit;
KVMState *s;
const KVMCapabilityInfo *missing_cap;
int ret;
int i;
- int max_vcpus;
s = g_malloc0(sizeof(KVMState));
@@ -1392,19 +1409,26 @@ int kvm_init(void)
goto err;
}
- max_vcpus = kvm_max_vcpus(s);
- if (smp_cpus > max_vcpus) {
- ret = -EINVAL;
- fprintf(stderr, "Number of SMP cpus requested (%d) exceeds max cpus "
- "supported by KVM (%d)\n", smp_cpus, max_vcpus);
- goto err;
- }
+ /* check the vcpu limits */
+ soft_vcpus_limit = kvm_recommended_vcpus(s);
+ hard_vcpus_limit = kvm_max_vcpus(s);
- if (max_cpus > max_vcpus) {
- ret = -EINVAL;
- fprintf(stderr, "Number of hotpluggable cpus requested (%d) exceeds max cpus "
- "supported by KVM (%d)\n", max_cpus, max_vcpus);
- goto err;
+ while (nc->name) {
+ if (nc->num > soft_vcpus_limit) {
+ fprintf(stderr,
+ "Warning: Number of %s cpus requested (%d) exceeds "
+ "the recommended cpus supported by KVM (%d)\n",
+ nc->name, nc->num, soft_vcpus_limit);
+
+ if (nc->num > hard_vcpus_limit) {
+ ret = -EINVAL;
+ fprintf(stderr, "Number of %s cpus requested (%d) exceeds "
+ "the maximum cpus supported by KVM (%d)\n",
+ nc->name, nc->num, hard_vcpus_limit);
+ goto err;
+ }
+ }
+ nc++;
}
s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0);
diff --git a/kvm-stub.c b/kvm-stub.c
index 548f471c17..e979f76d07 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -25,6 +25,7 @@ bool kvm_async_interrupts_allowed;
bool kvm_irqfds_allowed;
bool kvm_msi_via_irqfd_allowed;
bool kvm_gsi_routing_allowed;
+bool kvm_gsi_direct_mapping;
bool kvm_allowed;
bool kvm_readonly_mem_allowed;
diff --git a/libcacard/Makefile b/libcacard/Makefile
index 47827a0eb8..4d15da49b8 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -4,7 +4,8 @@ TOOLS += vscclient$(EXESUF)
# objects linked into a shared library, built with libtool with -fPIC if required
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-y += util/osdep.o util/cutils.o util/qemu-timer-common.o
+libcacard-obj-y += util/error.o util/qemu-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))
diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
index 5180d2945a..a3cb7762b5 100644
--- a/libcacard/vscclient.c
+++ b/libcacard/vscclient.c
@@ -645,7 +645,6 @@ main(
GIOChannel *channel_stdin;
char *qemu_host;
char *qemu_port;
- VSCMsgHeader mhHeader;
VCardEmulOptions *command_line_options = NULL;
@@ -754,7 +753,7 @@ main(
.magic = VSCARD_MAGIC,
.capabilities = {0}
};
- send_msg(VSC_Init, mhHeader.reader_id, &init, sizeof(init));
+ send_msg(VSC_Init, 0, &init, sizeof(init));
g_main_loop_run(loop);
g_main_loop_unref(loop);
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
new file mode 100644
index 0000000000..5031f42639
--- /dev/null
+++ b/linux-headers/asm-arm64/kvm.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/uapi/asm/kvm.h:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM_KVM_H__
+#define __ARM_KVM_H__
+
+#define KVM_SPSR_EL1 0
+#define KVM_SPSR_SVC KVM_SPSR_EL1
+#define KVM_SPSR_ABT 1
+#define KVM_SPSR_UND 2
+#define KVM_SPSR_IRQ 3
+#define KVM_SPSR_FIQ 4
+#define KVM_NR_SPSR 5
+
+#ifndef __ASSEMBLY__
+#include <asm/types.h>
+#include <asm/ptrace.h>
+
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_IRQ_LINE
+
+#define KVM_REG_SIZE(id) \
+ (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
+
+struct kvm_regs {
+ struct user_pt_regs regs; /* sp = sp_el0 */
+
+ __u64 sp_el1;
+ __u64 elr_el1;
+
+ __u64 spsr[KVM_NR_SPSR];
+
+ struct user_fpsimd_state fp_regs;
+};
+
+/* Supported Processor Types */
+#define KVM_ARM_TARGET_AEM_V8 0
+#define KVM_ARM_TARGET_FOUNDATION_V8 1
+#define KVM_ARM_TARGET_CORTEX_A57 2
+
+#define KVM_ARM_NUM_TARGETS 3
+
+/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
+#define KVM_ARM_DEVICE_TYPE_SHIFT 0
+#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_ID_SHIFT 16
+#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT)
+
+/* Supported device IDs */
+#define KVM_ARM_DEVICE_VGIC_V2 0
+
+/* Supported VGIC address types */
+#define KVM_VGIC_V2_ADDR_TYPE_DIST 0
+#define KVM_VGIC_V2_ADDR_TYPE_CPU 1
+
+#define KVM_VGIC_V2_DIST_SIZE 0x1000
+#define KVM_VGIC_V2_CPU_SIZE 0x2000
+
+#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
+#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */
+
+struct kvm_vcpu_init {
+ __u32 target;
+ __u32 features[7];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+struct kvm_guest_debug_arch {
+};
+
+struct kvm_debug_exit_arch {
+};
+
+struct kvm_sync_regs {
+};
+
+struct kvm_arch_memory_slot {
+};
+
+/* If you need to interpret the index values, here is the key: */
+#define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
+#define KVM_REG_ARM_COPROC_SHIFT 16
+
+/* Normal registers are mapped as coprocessor 16. */
+#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / sizeof(__u32))
+
+/* Some registers need more space to represent values. */
+#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00
+#define KVM_REG_ARM_DEMUX_ID_SHIFT 8
+#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT)
+#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF
+#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0
+
+/* AArch64 system registers */
+#define KVM_REG_ARM64_SYSREG (0x0013 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM64_SYSREG_OP0_MASK 0x000000000000c000
+#define KVM_REG_ARM64_SYSREG_OP0_SHIFT 14
+#define KVM_REG_ARM64_SYSREG_OP1_MASK 0x0000000000003800
+#define KVM_REG_ARM64_SYSREG_OP1_SHIFT 11
+#define KVM_REG_ARM64_SYSREG_CRN_MASK 0x0000000000000780
+#define KVM_REG_ARM64_SYSREG_CRN_SHIFT 7
+#define KVM_REG_ARM64_SYSREG_CRM_MASK 0x0000000000000078
+#define KVM_REG_ARM64_SYSREG_CRM_SHIFT 3
+#define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007
+#define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0
+
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_TYPE_SHIFT 24
+#define KVM_ARM_IRQ_TYPE_MASK 0xff
+#define KVM_ARM_IRQ_VCPU_SHIFT 16
+#define KVM_ARM_IRQ_VCPU_MASK 0xff
+#define KVM_ARM_IRQ_NUM_SHIFT 0
+#define KVM_ARM_IRQ_NUM_MASK 0xffff
+
+/* irq_type field */
+#define KVM_ARM_IRQ_TYPE_CPU 0
+#define KVM_ARM_IRQ_TYPE_SPI 1
+#define KVM_ARM_IRQ_TYPE_PPI 2
+
+/* out-of-kernel GIC cpu interrupt injection irq_number field */
+#define KVM_ARM_IRQ_CPU_IRQ 0
+#define KVM_ARM_IRQ_CPU_FIQ 1
+
+/* Highest supported SPI, from VGIC_NR_IRQS */
+#define KVM_ARM_IRQ_GIC_MAX 127
+
+/* PSCI interface */
+#define KVM_PSCI_FN_BASE 0x95c1ba5e
+#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
+
+#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0)
+#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1)
+#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
+#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
+
+#define KVM_PSCI_RET_SUCCESS 0
+#define KVM_PSCI_RET_NI ((unsigned long)-1)
+#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
+#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
+
+#endif
+
+#endif /* __ARM_KVM_H__ */
diff --git a/linux-headers/asm-arm64/kvm_para.h b/linux-headers/asm-arm64/kvm_para.h
new file mode 100644
index 0000000000..14fab8f0b9
--- /dev/null
+++ b/linux-headers/asm-arm64/kvm_para.h
@@ -0,0 +1 @@
+#include <asm-generic/kvm_para.h>
diff --git a/linux-headers/asm-mips/kvm.h b/linux-headers/asm-mips/kvm.h
index 3f424f5217..f09ff5ae20 100644
--- a/linux-headers/asm-mips/kvm.h
+++ b/linux-headers/asm-mips/kvm.h
@@ -58,56 +58,53 @@ struct kvm_fpu {
* bits[2..0] - Register 'sel' index.
* bits[7..3] - Register 'rd' index.
* bits[15..8] - Must be zero.
- * bits[63..16] - 1 -> CP0 registers.
+ * bits[31..16] - 1 -> CP0 registers.
+ * bits[51..32] - Must be zero.
+ * bits[63..52] - As per linux/kvm.h
*
* Other sets registers may be added in the future. Each set would
- * have its own identifier in bits[63..16].
- *
- * The addr field of struct kvm_one_reg must point to an aligned
- * 64-bit wide location. For registers that are narrower than
- * 64-bits, the value is stored in the low order bits of the location,
- * and sign extended to 64-bits.
+ * have its own identifier in bits[31..16].
*
* The registers defined in struct kvm_regs are also accessible, the
* id values for these are below.
*/
-#define KVM_REG_MIPS_R0 0
-#define KVM_REG_MIPS_R1 1
-#define KVM_REG_MIPS_R2 2
-#define KVM_REG_MIPS_R3 3
-#define KVM_REG_MIPS_R4 4
-#define KVM_REG_MIPS_R5 5
-#define KVM_REG_MIPS_R6 6
-#define KVM_REG_MIPS_R7 7
-#define KVM_REG_MIPS_R8 8
-#define KVM_REG_MIPS_R9 9
-#define KVM_REG_MIPS_R10 10
-#define KVM_REG_MIPS_R11 11
-#define KVM_REG_MIPS_R12 12
-#define KVM_REG_MIPS_R13 13
-#define KVM_REG_MIPS_R14 14
-#define KVM_REG_MIPS_R15 15
-#define KVM_REG_MIPS_R16 16
-#define KVM_REG_MIPS_R17 17
-#define KVM_REG_MIPS_R18 18
-#define KVM_REG_MIPS_R19 19
-#define KVM_REG_MIPS_R20 20
-#define KVM_REG_MIPS_R21 21
-#define KVM_REG_MIPS_R22 22
-#define KVM_REG_MIPS_R23 23
-#define KVM_REG_MIPS_R24 24
-#define KVM_REG_MIPS_R25 25
-#define KVM_REG_MIPS_R26 26
-#define KVM_REG_MIPS_R27 27
-#define KVM_REG_MIPS_R28 28
-#define KVM_REG_MIPS_R29 29
-#define KVM_REG_MIPS_R30 30
-#define KVM_REG_MIPS_R31 31
+#define KVM_REG_MIPS_R0 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 0)
+#define KVM_REG_MIPS_R1 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 1)
+#define KVM_REG_MIPS_R2 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 2)
+#define KVM_REG_MIPS_R3 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 3)
+#define KVM_REG_MIPS_R4 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 4)
+#define KVM_REG_MIPS_R5 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 5)
+#define KVM_REG_MIPS_R6 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 6)
+#define KVM_REG_MIPS_R7 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 7)
+#define KVM_REG_MIPS_R8 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 8)
+#define KVM_REG_MIPS_R9 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 9)
+#define KVM_REG_MIPS_R10 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 10)
+#define KVM_REG_MIPS_R11 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 11)
+#define KVM_REG_MIPS_R12 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 12)
+#define KVM_REG_MIPS_R13 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 13)
+#define KVM_REG_MIPS_R14 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 14)
+#define KVM_REG_MIPS_R15 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 15)
+#define KVM_REG_MIPS_R16 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 16)
+#define KVM_REG_MIPS_R17 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 17)
+#define KVM_REG_MIPS_R18 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 18)
+#define KVM_REG_MIPS_R19 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 19)
+#define KVM_REG_MIPS_R20 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 20)
+#define KVM_REG_MIPS_R21 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 21)
+#define KVM_REG_MIPS_R22 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 22)
+#define KVM_REG_MIPS_R23 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 23)
+#define KVM_REG_MIPS_R24 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 24)
+#define KVM_REG_MIPS_R25 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 25)
+#define KVM_REG_MIPS_R26 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 26)
+#define KVM_REG_MIPS_R27 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 27)
+#define KVM_REG_MIPS_R28 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 28)
+#define KVM_REG_MIPS_R29 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 29)
+#define KVM_REG_MIPS_R30 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 30)
+#define KVM_REG_MIPS_R31 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 31)
-#define KVM_REG_MIPS_HI 32
-#define KVM_REG_MIPS_LO 33
-#define KVM_REG_MIPS_PC 34
+#define KVM_REG_MIPS_HI (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 32)
+#define KVM_REG_MIPS_LO (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 33)
+#define KVM_REG_MIPS_PC (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 34)
/*
* KVM MIPS specific structures and definitions
diff --git a/linux-headers/asm-x86/kvm_para.h b/linux-headers/asm-x86/kvm_para.h
index a1c3d72acd..e41c5c1a28 100644
--- a/linux-headers/asm-x86/kvm_para.h
+++ b/linux-headers/asm-x86/kvm_para.h
@@ -23,6 +23,7 @@
#define KVM_FEATURE_ASYNC_PF 4
#define KVM_FEATURE_STEAL_TIME 5
#define KVM_FEATURE_PV_EOI 6
+#define KVM_FEATURE_PV_UNHALT 7
/* The last 8 bits are used to indicate how to interpret the flags field
* in pvclock structure. If no bits are set, all flags are ignored.
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index c614070662..13e890c53b 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -666,6 +666,8 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_IRQ_MPIC 90
#define KVM_CAP_PPC_RTAS 91
#define KVM_CAP_IRQ_XICS 92
+#define KVM_CAP_ARM_EL1_32BIT 93
+#define KVM_CAP_SPAPR_MULTITCE 94
#ifdef KVM_CAP_IRQ_ROUTING
@@ -783,6 +785,8 @@ struct kvm_dirty_tlb {
#define KVM_REG_IA64 0x3000000000000000ULL
#define KVM_REG_ARM 0x4000000000000000ULL
#define KVM_REG_S390 0x5000000000000000ULL
+#define KVM_REG_ARM64 0x6000000000000000ULL
+#define KVM_REG_MIPS 0x7000000000000000ULL
#define KVM_REG_SIZE_SHIFT 52
#define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h
index 7bdcf93c1d..2dff7838b4 100644
--- a/linux-headers/linux/kvm_para.h
+++ b/linux-headers/linux/kvm_para.h
@@ -19,6 +19,7 @@
#define KVM_HC_MMU_OP 2
#define KVM_HC_FEATURES 3
#define KVM_HC_PPC_MAP_MAGIC_PAGE 4
+#define KVM_HC_KICK_CPU 5
/*
* hypercalls use architecture specific
diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index 7ec1864765..17c58e0ede 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -22,6 +22,7 @@
/* Extensions */
#define VFIO_TYPE1_IOMMU 1
+#define VFIO_SPAPR_TCE_IOMMU 2
/*
* The IOCTL interface is designed for extensibility by embedding the
@@ -323,6 +324,44 @@ enum {
VFIO_PCI_NUM_IRQS
};
+/**
+ * VFIO_DEVICE_GET_PCI_HOT_RESET_INFO - _IORW(VFIO_TYPE, VFIO_BASE + 12,
+ * struct vfio_pci_hot_reset_info)
+ *
+ * Return: 0 on success, -errno on failure:
+ * -enospc = insufficient buffer, -enodev = unsupported for device.
+ */
+struct vfio_pci_dependent_device {
+ __u32 group_id;
+ __u16 segment;
+ __u8 bus;
+ __u8 devfn; /* Use PCI_SLOT/PCI_FUNC */
+};
+
+struct vfio_pci_hot_reset_info {
+ __u32 argsz;
+ __u32 flags;
+ __u32 count;
+ struct vfio_pci_dependent_device devices[];
+};
+
+#define VFIO_DEVICE_GET_PCI_HOT_RESET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
+
+/**
+ * VFIO_DEVICE_PCI_HOT_RESET - _IOW(VFIO_TYPE, VFIO_BASE + 13,
+ * struct vfio_pci_hot_reset)
+ *
+ * Return: 0 on success, -errno on failure.
+ */
+struct vfio_pci_hot_reset {
+ __u32 argsz;
+ __u32 flags;
+ __u32 count;
+ __s32 group_fds[];
+};
+
+#define VFIO_DEVICE_PCI_HOT_RESET _IO(VFIO_TYPE, VFIO_BASE + 13)
+
/* -------- API for Type1 VFIO IOMMU -------- */
/**
@@ -361,10 +400,14 @@ struct vfio_iommu_type1_dma_map {
#define VFIO_IOMMU_MAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 13)
/**
- * VFIO_IOMMU_UNMAP_DMA - _IOW(VFIO_TYPE, VFIO_BASE + 14, struct vfio_dma_unmap)
+ * VFIO_IOMMU_UNMAP_DMA - _IOWR(VFIO_TYPE, VFIO_BASE + 14,
+ * struct vfio_dma_unmap)
*
* Unmap IO virtual addresses using the provided struct vfio_dma_unmap.
- * Caller sets argsz.
+ * Caller sets argsz. The actual unmapped size is returned in the size
+ * field. No guarantee is made to the user that arbitrary unmaps of iova
+ * or size different from those used in the original mapping call will
+ * succeed.
*/
struct vfio_iommu_type1_dma_unmap {
__u32 argsz;
@@ -375,4 +418,37 @@ struct vfio_iommu_type1_dma_unmap {
#define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
+/*
+ * IOCTLs to enable/disable IOMMU container usage.
+ * No parameters are supported.
+ */
+#define VFIO_IOMMU_ENABLE _IO(VFIO_TYPE, VFIO_BASE + 15)
+#define VFIO_IOMMU_DISABLE _IO(VFIO_TYPE, VFIO_BASE + 16)
+
+/* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */
+
+/*
+ * The SPAPR TCE info struct provides the information about the PCI bus
+ * address ranges available for DMA, these values are programmed into
+ * the hardware so the guest has to know that information.
+ *
+ * The DMA 32 bit window start is an absolute PCI bus address.
+ * The IOVA address passed via map/unmap ioctls are absolute PCI bus
+ * addresses too so the window works as a filter rather than an offset
+ * for IOVA addresses.
+ *
+ * A flag will need to be added if other page sizes are supported,
+ * so as defined here, it is always 4k.
+ */
+struct vfio_iommu_spapr_tce_info {
+ __u32 argsz;
+ __u32 flags; /* reserved for future use */
+ __u32 dma32_window_start; /* 32 bit window start (bytes) */
+ __u32 dma32_window_size; /* 32 bit window size (bytes) */
+};
+
+#define VFIO_IOMMU_SPAPR_TCE_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
+
+/* ***************************************************************** */
+
#endif /* VFIO_H */
diff --git a/linux-headers/linux/virtio_config.h b/linux-headers/linux/virtio_config.h
index 4f51d8f3af..75dc20ba6f 100644
--- a/linux-headers/linux/virtio_config.h
+++ b/linux-headers/linux/virtio_config.h
@@ -51,4 +51,7 @@
* suppressed them? */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
+/* Can the device handle any descriptor layout? */
+#define VIRTIO_F_ANY_LAYOUT 27
+
#endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h
index ac2b6e2c65..d52d76e08e 100644
--- a/linux-user/alpha/syscall_nr.h
+++ b/linux-user/alpha/syscall_nr.h
@@ -20,7 +20,7 @@
#define TARGET_NR_lseek 19
#define TARGET_NR_getxpid 20
#define TARGET_NR_osf_mount 21
-#define TARGET_NR_umount 22
+#define TARGET_NR_umount2 22
#define TARGET_NR_setuid 23
#define TARGET_NR_getxuid 24
#define TARGET_NR_exec_with_loader 25 /* not implemented */
@@ -255,7 +255,7 @@
#define TARGET_NR_sysinfo 318
#define TARGET_NR__sysctl 319
/* 320 was sys_idle. */
-#define TARGET_NR_oldumount 321
+#define TARGET_NR_umount 321
#define TARGET_NR_swapon 322
#define TARGET_NR_times 323
#define TARGET_NR_personality 324
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 439c2a9e32..7381012d3d 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -20,6 +20,7 @@
IOCTL(TIOCSCTTY, 0, TYPE_INT)
IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
+ IOCTL(TIOCGSID, IOC_W, MK_PTR(TYPE_INT))
IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_INT))
IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 5cd6d91554..a1fe5ed9ae 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -131,7 +131,7 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
return sp;
}
-int loader_exec(const char * filename, char ** argv, char ** envp,
+int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
struct target_pt_regs * regs, struct image_info *infop,
struct linux_binprm *bprm)
{
@@ -140,11 +140,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
memset(bprm->page, 0, sizeof(bprm->page));
- retval = open(filename, O_RDONLY);
- if (retval < 0) {
- return -errno;
- }
- bprm->fd = retval;
+ bprm->fd = fdexec;
bprm->filename = (char *)filename;
bprm->argc = count(argv);
bprm->argv = argv;
diff --git a/linux-user/main.c b/linux-user/main.c
index 01e3cd4cc1..1561950bf5 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1861,7 +1861,7 @@ static const uint8_t mips_syscall_args[] = {
MIPS_SYS(sys_lseek , 3)
MIPS_SYS(sys_getpid , 0) /* 4020 */
MIPS_SYS(sys_mount , 5)
- MIPS_SYS(sys_oldumount , 1)
+ MIPS_SYS(sys_umount , 1)
MIPS_SYS(sys_setuid , 1)
MIPS_SYS(sys_getuid , 0)
MIPS_SYS(sys_stime , 1) /* 4025 */
@@ -1891,7 +1891,7 @@ static const uint8_t mips_syscall_args[] = {
MIPS_SYS(sys_geteuid , 0)
MIPS_SYS(sys_getegid , 0) /* 4050 */
MIPS_SYS(sys_acct , 0)
- MIPS_SYS(sys_umount , 2)
+ MIPS_SYS(sys_umount2 , 2)
MIPS_SYS(sys_ni_syscall , 0)
MIPS_SYS(sys_ioctl , 3)
MIPS_SYS(sys_fcntl , 3) /* 4055 */
@@ -2400,12 +2400,31 @@ done_syscall:
if (env->hflags & MIPS_HFLAG_M16) {
if (env->insn_flags & ASE_MICROMIPS) {
/* microMIPS mode */
- abi_ulong instr[2];
-
- ret = get_user_u16(instr[0], env->active_tc.PC) ||
- get_user_u16(instr[1], env->active_tc.PC + 2);
+ ret = get_user_u16(trap_instr, env->active_tc.PC);
+ if (ret != 0) {
+ goto error;
+ }
- trap_instr = (instr[0] << 16) | instr[1];
+ if ((trap_instr >> 10) == 0x11) {
+ /* 16-bit instruction */
+ code = trap_instr & 0xf;
+ } else {
+ /* 32-bit instruction */
+ abi_ulong instr_lo;
+
+ ret = get_user_u16(instr_lo,
+ env->active_tc.PC + 2);
+ if (ret != 0) {
+ goto error;
+ }
+ trap_instr = (trap_instr << 16) | instr_lo;
+ code = ((trap_instr >> 6) & ((1 << 20) - 1));
+ /* Unfortunately, microMIPS also suffers from
+ the old assembler bug... */
+ if (code >= (1 << 10)) {
+ code >>= 10;
+ }
+ }
} else {
/* MIPS16e mode */
ret = get_user_u16(trap_instr, env->active_tc.PC);
@@ -2413,26 +2432,21 @@ done_syscall:
goto error;
}
code = (trap_instr >> 6) & 0x3f;
- if (do_break(env, &info, code) != 0) {
- goto error;
- }
- break;
}
} else {
ret = get_user_ual(trap_instr, env->active_tc.PC);
- }
-
- if (ret != 0) {
- goto error;
- }
+ if (ret != 0) {
+ goto error;
+ }
- /* As described in the original Linux kernel code, the
- * below checks on 'code' are to work around an old
- * assembly bug.
- */
- code = ((trap_instr >> 6) & ((1 << 20) - 1));
- if (code >= (1 << 10)) {
- code >>= 10;
+ /* As described in the original Linux kernel code, the
+ * below checks on 'code' are to work around an old
+ * assembly bug.
+ */
+ code = ((trap_instr >> 6) & ((1 << 20) - 1));
+ if (code >= (1 << 10)) {
+ code >>= 10;
+ }
}
if (do_break(env, &info, code) != 0) {
@@ -3618,6 +3632,26 @@ static int parse_args(int argc, char **argv)
return optind;
}
+static int get_execfd(char **envp)
+{
+ typedef struct {
+ long a_type;
+ long a_val;
+ } auxv_t;
+ auxv_t *auxv;
+
+ while (*envp++ != NULL) {
+ ;
+ }
+
+ for (auxv = (auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
+ if (auxv->a_type == AT_EXECFD) {
+ return auxv->a_val;
+ }
+ }
+ return -1;
+}
+
int main(int argc, char **argv, char **envp)
{
struct target_pt_regs regs1, *regs = &regs1;
@@ -3632,6 +3666,7 @@ int main(int argc, char **argv, char **envp)
int target_argc;
int i;
int ret;
+ int execfd;
module_call_init(MODULE_INIT_QOM);
@@ -3809,7 +3844,16 @@ int main(int argc, char **argv, char **envp)
env->opaque = ts;
task_settid(ts);
- ret = loader_exec(filename, target_argv, target_environ, regs,
+ execfd = get_execfd(envp);
+ if (execfd < 0) {
+ execfd = open(filename, O_RDONLY);
+ }
+ if (execfd < 0) {
+ printf("Error while loading %s: %s\n", filename, strerror(-execfd));
+ _exit(1);
+ }
+
+ ret = loader_exec(execfd, filename, target_argv, target_environ, regs,
info, &bprm);
if (ret != 0) {
printf("Error while loading %s: %s\n", filename, strerror(-ret));
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 6ffe5a2dec..da64e877c7 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -174,7 +174,7 @@ struct linux_binprm {
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp,
abi_ulong stringp, int push_ptr);
-int loader_exec(const char * filename, char ** argv, char ** envp,
+int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
struct target_pt_regs * regs, struct image_info *infop,
struct linux_binprm *);
@@ -380,9 +380,9 @@ abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
/* Functions for accessing guest memory. The tget and tput functions
- read/write single values, byteswapping as necessary. The lock_user
+ read/write single values, byteswapping as necessary. The lock_user function
gets a pointer to a contiguous area of guest memory, but does not perform
- and byteswapping. lock_user may return either a pointer to the guest
+ any byteswapping. lock_user may return either a pointer to the guest
memory, or a temporary buffer. */
/* Lock an area of guest memory into the host. If copy is true then the
@@ -438,7 +438,7 @@ static inline void *lock_user_string(abi_ulong guest_addr)
return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
}
-/* Helper macros for locking/ulocking a target struct. */
+/* Helper macros for locking/unlocking a target struct. */
#define lock_user_struct(type, host_ptr, guest_addr, copy) \
(host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy))
#define unlock_user_struct(host_ptr, guest_addr, copy) \
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 08f115d843..cf5841af60 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -612,9 +612,6 @@
#ifdef TARGET_NR_oldstat
{ TARGET_NR_oldstat, "oldstat" , NULL, NULL, NULL },
#endif
-#ifdef TARGET_NR_oldumount
-{ TARGET_NR_oldumount, "oldumount" , NULL, NULL, NULL },
-#endif
#ifdef TARGET_NR_olduname
{ TARGET_NR_olduname, "olduname" , NULL, NULL, NULL },
#endif
@@ -1524,3 +1521,9 @@
#ifdef TARGET_NR_pipe2
{ TARGET_NR_pipe2, "pipe2", NULL, NULL, NULL },
#endif
+#ifdef TARGET_NR_atomic_cmpxchg_32
+{ TARGET_NR_atomic_cmpxchg_32, "atomic_cmpxchg_32", NULL, NULL, NULL },
+#endif
+#ifdef TARGET_NR_atomic_barrier
+{ TARGET_NR_atomic_barrier, "atomic_barrier", NULL, NULL, NULL },
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c62d8754f0..4a14a43037 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -106,6 +106,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <linux/dm-ioctl.h>
#include <linux/reboot.h>
#include <linux/route.h>
+#include <linux/filter.h>
#include "linux_loop.h"
#include "cpu-uname.h"
@@ -1149,11 +1150,15 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
break;
}
- cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+ if (tswap32(target_cmsg->cmsg_level) == TARGET_SOL_SOCKET) {
+ cmsg->cmsg_level = SOL_SOCKET;
+ } else {
+ cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
+ }
cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
cmsg->cmsg_len = CMSG_LEN(len);
- if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(data, target_data, len);
} else {
@@ -1204,11 +1209,15 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
break;
}
- target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+ if (cmsg->cmsg_level == SOL_SOCKET) {
+ target_cmsg->cmsg_level = tswap32(TARGET_SOL_SOCKET);
+ } else {
+ target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
+ }
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
- if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+ if ((cmsg->cmsg_level == SOL_SOCKET) &&
(cmsg->cmsg_type == SCM_RIGHTS)) {
int *fd = (int *)data;
int *target_fd = (int *)target_data;
@@ -1216,7 +1225,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
for (i = 0; i < numfds; i++)
target_fd[i] = tswap32(fd[i]);
- } else if ((cmsg->cmsg_level == TARGET_SOL_SOCKET) &&
+ } else if ((cmsg->cmsg_level == SOL_SOCKET) &&
(cmsg->cmsg_type == SO_TIMESTAMP) &&
(len == sizeof(struct timeval))) {
/* copy struct timeval to target */
@@ -1314,6 +1323,26 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
goto unimplemented;
}
break;
+ case SOL_IPV6:
+ switch (optname) {
+ case IPV6_MTU_DISCOVER:
+ case IPV6_MTU:
+ case IPV6_V6ONLY:
+ case IPV6_RECVPKTINFO:
+ val = 0;
+ if (optlen < sizeof(uint32_t)) {
+ return -TARGET_EINVAL;
+ }
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, level, optname,
+ &val, sizeof(val)));
+ break;
+ default:
+ goto unimplemented;
+ }
+ break;
case SOL_RAW:
switch (optname) {
case ICMP_FILTER:
@@ -1357,6 +1386,49 @@ set_timeout:
case TARGET_SO_SNDTIMEO:
optname = SO_SNDTIMEO;
goto set_timeout;
+ case TARGET_SO_ATTACH_FILTER:
+ {
+ struct target_sock_fprog *tfprog;
+ struct target_sock_filter *tfilter;
+ struct sock_fprog fprog;
+ struct sock_filter *filter;
+ int i;
+
+ if (optlen != sizeof(*tfprog)) {
+ return -TARGET_EINVAL;
+ }
+ if (!lock_user_struct(VERIFY_READ, tfprog, optval_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+ if (!lock_user_struct(VERIFY_READ, tfilter,
+ tswapal(tfprog->filter), 0)) {
+ unlock_user_struct(tfprog, optval_addr, 1);
+ return -TARGET_EFAULT;
+ }
+
+ fprog.len = tswap16(tfprog->len);
+ filter = malloc(fprog.len * sizeof(*filter));
+ if (filter == NULL) {
+ unlock_user_struct(tfilter, tfprog->filter, 1);
+ unlock_user_struct(tfprog, optval_addr, 1);
+ return -TARGET_ENOMEM;
+ }
+ for (i = 0; i < fprog.len; i++) {
+ filter[i].code = tswap16(tfilter[i].code);
+ filter[i].jt = tfilter[i].jt;
+ filter[i].jf = tfilter[i].jf;
+ filter[i].k = tswap32(tfilter[i].k);
+ }
+ fprog.filter = filter;
+
+ ret = get_errno(setsockopt(sockfd, SOL_SOCKET,
+ SO_ATTACH_FILTER, &fprog, sizeof(fprog)));
+ free(filter);
+
+ unlock_user_struct(tfilter, tfprog->filter, 1);
+ unlock_user_struct(tfprog, optval_addr, 1);
+ return ret;
+ }
/* Options with 'int' argument. */
case TARGET_SO_DEBUG:
optname = SO_DEBUG;
@@ -1701,7 +1773,7 @@ static void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
free(vec);
}
-static inline void target_to_host_sock_type(int *type)
+static inline int target_to_host_sock_type(int *type)
{
int host_type = 0;
int target_type = *type;
@@ -1718,22 +1790,56 @@ static inline void target_to_host_sock_type(int *type)
break;
}
if (target_type & TARGET_SOCK_CLOEXEC) {
+#if defined(SOCK_CLOEXEC)
host_type |= SOCK_CLOEXEC;
+#else
+ return -TARGET_EINVAL;
+#endif
}
if (target_type & TARGET_SOCK_NONBLOCK) {
+#if defined(SOCK_NONBLOCK)
host_type |= SOCK_NONBLOCK;
+#elif !defined(O_NONBLOCK)
+ return -TARGET_EINVAL;
+#endif
}
*type = host_type;
+ return 0;
+}
+
+/* Try to emulate socket type flags after socket creation. */
+static int sock_flags_fixup(int fd, int target_type)
+{
+#if !defined(SOCK_NONBLOCK) && defined(O_NONBLOCK)
+ if (target_type & TARGET_SOCK_NONBLOCK) {
+ int flags = fcntl(fd, F_GETFL);
+ if (fcntl(fd, F_SETFL, O_NONBLOCK | flags) == -1) {
+ close(fd);
+ return -TARGET_EINVAL;
+ }
+ }
+#endif
+ return fd;
}
/* do_socket() Must return target values and target errnos. */
static abi_long do_socket(int domain, int type, int protocol)
{
- target_to_host_sock_type(&type);
+ int target_type = type;
+ int ret;
+
+ ret = target_to_host_sock_type(&type);
+ if (ret) {
+ return ret;
+ }
if (domain == PF_NETLINK)
return -EAFNOSUPPORT; /* do not NETLINK socket connections possible */
- return get_errno(socket(domain, type, protocol));
+ ret = get_errno(socket(domain, type, protocol));
+ if (ret >= 0) {
+ ret = sock_flags_fixup(ret, target_type);
+ }
+ return ret;
}
/* do_bind() Must return target values and target errnos. */
@@ -5071,22 +5177,70 @@ static int is_proc_myself(const char *filename, const char *entry)
return 0;
}
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+static int is_proc(const char *filename, const char *entry)
+{
+ return strcmp(filename, entry) == 0;
+}
+
+static int open_net_route(void *cpu_env, int fd)
+{
+ FILE *fp;
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read;
+
+ fp = fopen("/proc/net/route", "r");
+ if (fp == NULL) {
+ return -EACCES;
+ }
+
+ /* read header */
+
+ read = getline(&line, &len, fp);
+ dprintf(fd, "%s", line);
+
+ /* read routes */
+
+ while ((read = getline(&line, &len, fp)) != -1) {
+ char iface[16];
+ uint32_t dest, gw, mask;
+ unsigned int flags, refcnt, use, metric, mtu, window, irtt;
+ sscanf(line, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
+ iface, &dest, &gw, &flags, &refcnt, &use, &metric,
+ &mask, &mtu, &window, &irtt);
+ dprintf(fd, "%s\t%08x\t%08x\t%04x\t%d\t%d\t%d\t%08x\t%d\t%u\t%u\n",
+ iface, tswap32(dest), tswap32(gw), flags, refcnt, use,
+ metric, tswap32(mask), mtu, window, irtt);
+ }
+
+ free(line);
+ fclose(fp);
+
+ return 0;
+}
+#endif
+
static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
{
struct fake_open {
const char *filename;
int (*fill)(void *cpu_env, int fd);
+ int (*cmp)(const char *s1, const char *s2);
};
const struct fake_open *fake_open;
static const struct fake_open fakes[] = {
- { "maps", open_self_maps },
- { "stat", open_self_stat },
- { "auxv", open_self_auxv },
- { NULL, NULL }
+ { "maps", open_self_maps, is_proc_myself },
+ { "stat", open_self_stat, is_proc_myself },
+ { "auxv", open_self_auxv, is_proc_myself },
+#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+ { "/proc/net/route", open_net_route, is_proc },
+#endif
+ { NULL, NULL, NULL }
};
for (fake_open = fakes; fake_open->filename; fake_open++) {
- if (is_proc_myself(pathname, fake_open->filename)) {
+ if (fake_open->cmp(pathname, fake_open->filename)) {
break;
}
}
@@ -5697,7 +5851,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
}
break;
-#ifdef TARGET_NR_umount2 /* not on alpha */
+#ifdef TARGET_NR_umount2
case TARGET_NR_umount2:
if (!(p = lock_user_string(arg1)))
goto efault;
@@ -9013,6 +9167,34 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
}
#endif
+#ifdef TARGET_NR_atomic_cmpxchg_32
+ case TARGET_NR_atomic_cmpxchg_32:
+ {
+ /* should use start_exclusive from main.c */
+ abi_ulong mem_value;
+ if (get_user_u32(mem_value, arg6)) {
+ target_siginfo_t info;
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = arg6;
+ queue_signal((CPUArchState *)cpu_env, info.si_signo, &info);
+ ret = 0xdeadbeef;
+
+ }
+ if (mem_value == arg2)
+ put_user_u32(arg1, arg6);
+ ret = mem_value;
+ break;
+ }
+#endif
+#ifdef TARGET_NR_atomic_barrier
+ case TARGET_NR_atomic_barrier:
+ {
+ /* Like the kernel implementation and the qemu arm barrier, no-op this? */
+ break;
+ }
+#endif
default:
unimplemented:
gemu_log("qemu: Unsupported syscall: %d\n", num);
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 2ebe3560d7..5f53a28d1b 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -119,6 +119,18 @@ struct target_sockaddr {
uint8_t sa_data[14];
};
+struct target_sock_filter {
+ abi_ushort code;
+ uint8_t jt;
+ uint8_t jf;
+ abi_uint k;
+};
+
+struct target_sock_fprog {
+ abi_ushort len;
+ abi_ulong filter;
+};
+
struct target_in_addr {
uint32_t s_addr; /* big endian */
};
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 05fc7c2fae..6727f0ca39 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 49f2d291fc..4d6e48fcbe 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -123,6 +123,7 @@ static void vring_init(struct vring *vr, unsigned int num, void *p,
/* We're running with interrupts off anyways, so don't bother */
vr->used->flags = VRING_USED_F_NO_NOTIFY;
vr->used->idx = 0;
+ vr->used_idx = 0;
debug_print_addr("init vr", vr);
}
@@ -150,8 +151,6 @@ static void vring_send_buf(struct vring *vr, void *p, int len, int flags)
if (!(flags & VRING_DESC_F_NEXT)) {
vr->avail->idx++;
}
-
- vr->used->idx = vr->next_idx;
}
static u64 get_clock(void)
@@ -180,7 +179,8 @@ static int vring_wait_reply(struct vring *vr, int timeout)
struct subchannel_id schid = vr->schid;
int r = 0;
- while (vr->used->idx == vr->next_idx) {
+ /* Wait until the used index has moved. */
+ while (vr->used->idx == vr->used_idx) {
vring_notify(schid);
if (timeout && (get_second() >= target_second)) {
r = 1;
@@ -189,6 +189,7 @@ static int vring_wait_reply(struct vring *vr, int timeout)
yield();
}
+ vr->used_idx = vr->used->idx;
vr->next_idx = 0;
vr->desc[0].len = 0;
vr->desc[0].flags = 0;
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 86fdd579b4..772a63f152 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -115,6 +115,7 @@ struct vring_used {
struct vring {
unsigned int num;
int next_idx;
+ int used_idx;
struct vring_desc *desc;
struct vring_avail *avail;
struct vring_used *used;
diff --git a/qemu-timer.c b/qemu-timer.c
index 95ff47fef3..6b62e88669 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -66,6 +66,7 @@ QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
struct QEMUTimerList {
QEMUClock *clock;
+ QemuMutex active_timers_lock;
QEMUTimer *active_timers;
QLIST_ENTRY(QEMUTimerList) list;
QEMUTimerListNotifyCB *notify_cb;
@@ -101,6 +102,7 @@ QEMUTimerList *timerlist_new(QEMUClockType type,
timer_list->clock = clock;
timer_list->notify_cb = cb;
timer_list->notify_opaque = opaque;
+ qemu_mutex_init(&timer_list->active_timers_lock);
QLIST_INSERT_HEAD(&clock->timerlists, timer_list, list);
return timer_list;
}
@@ -111,6 +113,7 @@ void timerlist_free(QEMUTimerList *timer_list)
if (timer_list->clock) {
QLIST_REMOVE(timer_list, list);
}
+ qemu_mutex_destroy(&timer_list->active_timers_lock);
g_free(timer_list);
}
@@ -163,9 +166,17 @@ bool qemu_clock_has_timers(QEMUClockType type)
bool timerlist_expired(QEMUTimerList *timer_list)
{
- return (timer_list->active_timers &&
- timer_list->active_timers->expire_time <
- qemu_clock_get_ns(timer_list->clock->type));
+ int64_t expire_time;
+
+ qemu_mutex_lock(&timer_list->active_timers_lock);
+ if (!timer_list->active_timers) {
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
+ return false;
+ }
+ expire_time = timer_list->active_timers->expire_time;
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
+
+ return expire_time < qemu_clock_get_ns(timer_list->clock->type);
}
bool qemu_clock_expired(QEMUClockType type)
@@ -182,13 +193,25 @@ bool qemu_clock_expired(QEMUClockType type)
int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
{
int64_t delta;
+ int64_t expire_time;
- if (!timer_list->clock->enabled || !timer_list->active_timers) {
+ if (!timer_list->clock->enabled) {
return -1;
}
- delta = timer_list->active_timers->expire_time -
- qemu_clock_get_ns(timer_list->clock->type);
+ /* The active timers list may be modified before the caller uses our return
+ * value but ->notify_cb() is called when the deadline changes. Therefore
+ * the caller should notice the change and there is no race condition.
+ */
+ qemu_mutex_lock(&timer_list->active_timers_lock);
+ if (!timer_list->active_timers) {
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
+ return -1;
+ }
+ expire_time = timer_list->active_timers->expire_time;
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
+
+ delta = expire_time - qemu_clock_get_ns(timer_list->clock->type);
if (delta <= 0) {
return 0;
@@ -289,6 +312,7 @@ void timer_init(QEMUTimer *ts,
ts->cb = cb;
ts->opaque = opaque;
ts->scale = scale;
+ ts->expire_time = -1;
}
void timer_free(QEMUTimer *ts)
@@ -296,14 +320,12 @@ void timer_free(QEMUTimer *ts)
g_free(ts);
}
-/* stop a timer, but do not dealloc it */
-void timer_del(QEMUTimer *ts)
+static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts)
{
QEMUTimer **pt, *t;
- /* NOTE: this code must be signal safe because
- timer_expired() can be called from a signal. */
- pt = &ts->timer_list->active_timers;
+ ts->expire_time = -1;
+ pt = &timer_list->active_timers;
for(;;) {
t = *pt;
if (!t)
@@ -316,18 +338,28 @@ void timer_del(QEMUTimer *ts)
}
}
+/* stop a timer, but do not dealloc it */
+void timer_del(QEMUTimer *ts)
+{
+ QEMUTimerList *timer_list = ts->timer_list;
+
+ qemu_mutex_lock(&timer_list->active_timers_lock);
+ timer_del_locked(timer_list, ts);
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
+}
+
/* modify the current timer so that it will be fired when current_time
>= expire_time. The corresponding callback will be called. */
void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
{
+ QEMUTimerList *timer_list = ts->timer_list;
QEMUTimer **pt, *t;
- timer_del(ts);
+ qemu_mutex_lock(&timer_list->active_timers_lock);
+ timer_del_locked(timer_list, ts);
/* add the timer in the sorted list */
- /* NOTE: this code must be signal safe because
- timer_expired() can be called from a signal. */
- pt = &ts->timer_list->active_timers;
+ pt = &timer_list->active_timers;
for(;;) {
t = *pt;
if (!timer_expired_ns(t, expire_time)) {
@@ -335,15 +367,16 @@ void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
}
pt = &t->next;
}
- ts->expire_time = expire_time;
+ ts->expire_time = MAX(expire_time, 0);
ts->next = *pt;
*pt = ts;
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
/* Rearm if necessary */
- if (pt == &ts->timer_list->active_timers) {
+ if (pt == &timer_list->active_timers) {
/* Interrupt execution to force deadline recalculation. */
- qemu_clock_warp(ts->timer_list->clock->type);
- timerlist_notify(ts->timer_list);
+ qemu_clock_warp(timer_list->clock->type);
+ timerlist_notify(timer_list);
}
}
@@ -354,13 +387,7 @@ void timer_mod(QEMUTimer *ts, int64_t expire_time)
bool timer_pending(QEMUTimer *ts)
{
- QEMUTimer *t;
- for (t = ts->timer_list->active_timers; t != NULL; t = t->next) {
- if (t == ts) {
- return true;
- }
- }
- return false;
+ return ts->expire_time >= 0;
}
bool timer_expired(QEMUTimer *timer_head, int64_t current_time)
@@ -373,23 +400,32 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
QEMUTimer *ts;
int64_t current_time;
bool progress = false;
-
+ QEMUTimerCB *cb;
+ void *opaque;
+
if (!timer_list->clock->enabled) {
return progress;
}
current_time = qemu_clock_get_ns(timer_list->clock->type);
for(;;) {
+ qemu_mutex_lock(&timer_list->active_timers_lock);
ts = timer_list->active_timers;
if (!timer_expired_ns(ts, current_time)) {
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
break;
}
+
/* remove timer from the list before calling the callback */
timer_list->active_timers = ts->next;
ts->next = NULL;
+ ts->expire_time = -1;
+ cb = ts->cb;
+ opaque = ts->opaque;
+ qemu_mutex_unlock(&timer_list->active_timers_lock);
/* run the callback (the timer list can be modified) */
- ts->cb(ts->opaque);
+ cb(opaque);
progress = true;
}
return progress;
diff --git a/qom/cpu.c b/qom/cpu.c
index fa7ec6b199..818fb26dd4 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -162,6 +162,7 @@ void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
CPUClass *cc = CPU_GET_CLASS(cpu);
if (cc->dump_state) {
+ cpu_synchronize_state(cpu);
cc->dump_state(cpu, f, cpu_fprintf, flags);
}
}
diff --git a/QMP/qemu-ga-client b/scripts/qmp/qemu-ga-client
index b5f7e7c5ff..b5f7e7c5ff 100755
--- a/QMP/qemu-ga-client
+++ b/scripts/qmp/qemu-ga-client
diff --git a/QMP/qmp b/scripts/qmp/qmp
index 1db3c7ffeb..1db3c7ffeb 100755
--- a/QMP/qmp
+++ b/scripts/qmp/qmp
diff --git a/QMP/qmp-shell b/scripts/qmp/qmp-shell
index 73cb3b6cef..d6b420f18a 100755
--- a/QMP/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -91,7 +91,7 @@ class QMPShell(qmp.QEMUMonitorProtocol):
"""
Build a QMP input object from a user provided command-line in the
following format:
-
+
< command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
"""
cmdargs = cmdline.split()
diff --git a/QMP/qmp.py b/scripts/qmp/qmp.py
index 074f09a063..5c9717594f 100644
--- a/QMP/qmp.py
+++ b/scripts/qmp/qmp.py
@@ -1,5 +1,5 @@
# QEMU Monitor Protocol Python class
-#
+#
# Copyright (C) 2009, 2010 Red Hat Inc.
#
# Authors:
diff --git a/QMP/qom-fuse b/scripts/qmp/qom-fuse
index 5c6754aa63..5c6754aa63 100755
--- a/QMP/qom-fuse
+++ b/scripts/qmp/qom-fuse
diff --git a/QMP/qom-get b/scripts/qmp/qom-get
index 0172c69441..0172c69441 100755
--- a/QMP/qom-get
+++ b/scripts/qmp/qom-get
diff --git a/QMP/qom-list b/scripts/qmp/qom-list
index 1e7cc6cb2d..1e7cc6cb2d 100755
--- a/QMP/qom-list
+++ b/scripts/qmp/qom-list
diff --git a/QMP/qom-set b/scripts/qmp/qom-set
index 54ecfecc53..54ecfecc53 100755
--- a/QMP/qom-set
+++ b/scripts/qmp/qom-set
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index c4447c2b6e..f4fab155bd 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -70,6 +70,9 @@ typedef struct X86CPU {
bool hyperv_relaxed_timing;
int hyperv_spinlock_attempts;
+ /* if true the CPUID code directly forward host cache leaves to the guest */
+ bool cache_info_passthrough;
+
/* Features that were filtered out because of missing host capabilities */
uint32_t filtered_features[FEATURE_WORDS];
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index c36345e426..b6828022bc 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -235,7 +235,7 @@ static const char *ext4_feature_name[] = {
static const char *kvm_feature_name[] = {
"kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock",
- "kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", NULL,
+ "kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", "kvm_pv_unhalt",
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
@@ -486,6 +486,7 @@ typedef struct x86_def_t {
int stepping;
FeatureWordArray features;
char model_id[48];
+ bool cache_info_passthrough;
} x86_def_t;
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -1139,6 +1140,7 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
assert(kvm_enabled());
x86_cpu_def->name = "host";
+ x86_cpu_def->cache_info_passthrough = true;
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
@@ -1888,6 +1890,7 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp)
env->features[FEAT_C000_0001_EDX] = def->features[FEAT_C000_0001_EDX];
env->features[FEAT_7_0_EBX] = def->features[FEAT_7_0_EBX];
env->cpuid_xlevel2 = def->xlevel2;
+ cpu->cache_info_passthrough = def->cache_info_passthrough;
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp);
}
@@ -2062,6 +2065,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 2:
/* cache info: needed for Pentium Pro compatibility */
+ if (cpu->cache_info_passthrough) {
+ host_cpuid(index, 0, eax, ebx, ecx, edx);
+ break;
+ }
*eax = 1; /* Number of CPUID[EAX=2] calls required */
*ebx = 0;
*ecx = 0;
@@ -2071,6 +2078,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 4:
/* cache info: needed for Core compatibility */
+ if (cpu->cache_info_passthrough) {
+ host_cpuid(index, count, eax, ebx, ecx, edx);
+ break;
+ }
if (cs->nr_cores > 1) {
*eax = (cs->nr_cores - 1) << 26;
} else {
@@ -2228,6 +2239,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 0x80000005:
/* cache info (L1 cache) */
+ if (cpu->cache_info_passthrough) {
+ host_cpuid(index, 0, eax, ebx, ecx, edx);
+ break;
+ }
*eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | \
(L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES);
*ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \
@@ -2239,6 +2254,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 0x80000006:
/* cache info (L2 cache) */
+ if (cpu->cache_info_passthrough) {
+ host_cpuid(index, 0, eax, ebx, ecx, edx);
+ break;
+ }
*eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | \
(L2_DTLB_2M_ENTRIES << 16) | \
(AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | \
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 8bf85ec5f0..7c196ffc42 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -147,7 +147,9 @@ cpu_x86_dump_seg_cache(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, " [%c%c", (sc->flags & DESC_C_MASK) ? 'C' : '-',
(sc->flags & DESC_R_MASK) ? 'R' : '-');
} else {
- cpu_fprintf(f, (sc->flags & DESC_B_MASK) ? "DS " : "DS16");
+ cpu_fprintf(f,
+ (sc->flags & DESC_B_MASK || env->hflags & HF_LMA_MASK)
+ ? "DS " : "DS16");
cpu_fprintf(f, " [%c%c", (sc->flags & DESC_E_MASK) ? 'E' : '-',
(sc->flags & DESC_W_MASK) ? 'W' : '-');
}
@@ -188,8 +190,6 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
char cc_op_name[32];
static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
- cpu_synchronize_state(cs);
-
eflags = cpu_compute_eflags(env);
#ifdef TARGET_X86_64
if (env->hflags & HF_CS64_MASK) {
diff --git a/target-i386/machine.c b/target-i386/machine.c
index dc81cde535..e568da2ba4 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -330,9 +330,9 @@ static bool pv_eoi_msr_needed(void *opaque)
static bool steal_time_msr_needed(void *opaque)
{
- CPUX86State *cpu = opaque;
+ X86CPU *cpu = opaque;
- return cpu->steal_time_msr != 0;
+ return cpu->env.steal_time_msr != 0;
}
static const VMStateDescription vmstate_steal_time_msr = {
@@ -341,7 +341,7 @@ static const VMStateDescription vmstate_steal_time_msr = {
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
- VMSTATE_UINT64(steal_time_msr, CPUX86State),
+ VMSTATE_UINT64(env.steal_time_msr, X86CPU),
VMSTATE_END_OF_LIST()
}
};
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 2da7bc740f..9c59f69ee1 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -9536,8 +9536,6 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
CPUPPCState *env = &cpu->env;
int i;
- cpu_synchronize_state(cs);
-
cpu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR "
TARGET_FMT_lx " XER " TARGET_FMT_lx "\n",
env->nip, env->lr, env->ctr, cpu_read_xer(env));
diff --git a/target-s390x/arch_dump.c b/target-s390x/arch_dump.c
index 9d36116242..5cbb53ca2e 100644
--- a/target-s390x/arch_dump.c
+++ b/target-s390x/arch_dump.c
@@ -151,6 +151,7 @@ static int s390x_write_all_elf64_notes(const char *note_name,
int ret = -1;
for (nf = note_func; nf->note_contents_func; nf++) {
+ memset(&note, 0, sizeof(note));
note.hdr.n_namesz = cpu_to_be32(sizeof(note.name));
note.hdr.n_descsz = cpu_to_be32(nf->contents_size);
strncpy(note.name, note_name, sizeof(note.name));
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 8be5648806..a2c077bdcd 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -148,6 +148,7 @@ typedef struct CPUS390XState {
} CPUS390XState;
#include "cpu-qom.h"
+#include <sysemu/kvm.h>
/* distinguish between 24 bit and 31 bit addressing */
#define HIGH_ORDER_BIT 0x80000000
@@ -692,6 +693,14 @@ static inline const char *cc_name(int cc_op)
return cc_names[cc_op];
}
+static inline void setcc(S390CPU *cpu, uint64_t cc)
+{
+ CPUS390XState *env = &cpu->env;
+
+ env->psw.mask &= ~(3ull << 44);
+ env->psw.mask |= (cc & 3) << 44;
+}
+
typedef struct LowCore
{
/* prefix area: defined by architecture */
@@ -1058,8 +1067,6 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
uintptr_t retaddr);
-#include <sysemu/kvm.h>
-
#ifdef CONFIG_KVM
void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id,
uint16_t subchannel_nr, uint32_t io_int_parm,
diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c
index 85fd285736..8d6363df4e 100644
--- a/target-s390x/ioinst.c
+++ b/target-s390x/ioinst.c
@@ -36,7 +36,7 @@ int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
return 0;
}
-int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -44,8 +44,8 @@ int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1)
int cc;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
+ return;
}
trace_ioinst_sch_id("xsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
@@ -66,11 +66,10 @@ int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1)
cc = 1;
break;
}
-
- return cc;
+ setcc(cpu, cc);
}
-int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -78,8 +77,8 @@ int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1)
int cc;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
+ return;
}
trace_ioinst_sch_id("csch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
@@ -91,10 +90,10 @@ int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1)
} else {
cc = 0;
}
- return cc;
+ setcc(cpu, cc);
}
-int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -102,8 +101,8 @@ int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1)
int cc;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
+ return;
}
trace_ioinst_sch_id("hsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
@@ -124,8 +123,7 @@ int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1)
cc = 1;
break;
}
-
- return cc;
+ setcc(cpu, cc);
}
static int ioinst_schib_valid(SCHIB *schib)
@@ -141,7 +139,7 @@ static int ioinst_schib_valid(SCHIB *schib)
return 1;
}
-int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
+void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -150,22 +148,21 @@ int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
int ret = -ENODEV;
int cc;
hwaddr len = sizeof(*schib);
+ CPUS390XState *env = &cpu->env;
addr = decode_basedisp_s(env, ipb);
if (addr & 3) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
schib = s390_cpu_physical_memory_map(env, addr, &len, 0);
if (!schib || len != sizeof(*schib)) {
program_interrupt(env, PGM_ADDRESSING, 2);
- cc = -EIO;
goto out;
}
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
!ioinst_schib_valid(schib)) {
program_interrupt(env, PGM_OPERAND, 2);
- cc = -EIO;
goto out;
}
trace_ioinst_sch_id("msch", cssid, ssid, schid);
@@ -187,9 +184,10 @@ int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
cc = 1;
break;
}
+ setcc(cpu, cc);
+
out:
s390_cpu_physical_memory_unmap(env, schib, len, 0);
- return cc;
}
static void copy_orb_from_guest(ORB *dest, const ORB *src)
@@ -213,7 +211,7 @@ static int ioinst_orb_valid(ORB *orb)
return 1;
}
-int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
+void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -222,23 +220,22 @@ int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
int ret = -ENODEV;
int cc;
hwaddr len = sizeof(*orig_orb);
+ CPUS390XState *env = &cpu->env;
addr = decode_basedisp_s(env, ipb);
if (addr & 3) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
orig_orb = s390_cpu_physical_memory_map(env, addr, &len, 0);
if (!orig_orb || len != sizeof(*orig_orb)) {
program_interrupt(env, PGM_ADDRESSING, 2);
- cc = -EIO;
goto out;
}
copy_orb_from_guest(&orb, orig_orb);
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
!ioinst_orb_valid(&orb)) {
program_interrupt(env, PGM_OPERAND, 2);
- cc = -EIO;
goto out;
}
trace_ioinst_sch_id("ssch", cssid, ssid, schid);
@@ -260,38 +257,39 @@ int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
cc = 1;
break;
}
+ setcc(cpu, cc);
out:
s390_cpu_physical_memory_unmap(env, orig_orb, len, 0);
- return cc;
}
-int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb)
+void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb)
{
CRW *crw;
uint64_t addr;
int cc;
hwaddr len = sizeof(*crw);
+ CPUS390XState *env = &cpu->env;
addr = decode_basedisp_s(env, ipb);
if (addr & 3) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
crw = s390_cpu_physical_memory_map(env, addr, &len, 1);
if (!crw || len != sizeof(*crw)) {
program_interrupt(env, PGM_ADDRESSING, 2);
- cc = -EIO;
goto out;
}
cc = css_do_stcrw(crw);
/* 0 - crw stored, 1 - zeroes stored */
+ setcc(cpu, cc);
+
out:
s390_cpu_physical_memory_unmap(env, crw, len, 1);
- return cc;
}
-int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
+void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -299,22 +297,21 @@ int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
int cc;
SCHIB *schib;
hwaddr len = sizeof(*schib);
+ CPUS390XState *env = &cpu->env;
addr = decode_basedisp_s(env, ipb);
if (addr & 3) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
schib = s390_cpu_physical_memory_map(env, addr, &len, 1);
if (!schib || len != sizeof(*schib)) {
program_interrupt(env, PGM_ADDRESSING, 2);
- cc = -EIO;
goto out;
}
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
program_interrupt(env, PGM_OPERAND, 2);
- cc = -EIO;
goto out;
}
trace_ioinst_sch_id("stsch", cssid, ssid, schid);
@@ -336,9 +333,10 @@ int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
cc = 0;
}
}
+ setcc(cpu, cc);
+
out:
s390_cpu_physical_memory_unmap(env, schib, len, 1);
- return cc;
}
int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
@@ -575,7 +573,7 @@ static void ioinst_handle_chsc_unimplemented(ChscResp *res)
res->param = 0;
}
-int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
+void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb)
{
ChscReq *req;
ChscResp *res;
@@ -584,7 +582,7 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
uint16_t len;
uint16_t command;
hwaddr map_size = TARGET_PAGE_SIZE;
- int ret = 0;
+ CPUS390XState *env = &cpu->env;
trace_ioinst("chsc");
reg = (ipb >> 20) & 0x00f;
@@ -592,19 +590,17 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
/* Page boundary? */
if (addr & 0xfff) {
program_interrupt(env, PGM_SPECIFICATION, 2);
- return -EIO;
+ return;
}
req = s390_cpu_physical_memory_map(env, addr, &map_size, 1);
if (!req || map_size != TARGET_PAGE_SIZE) {
program_interrupt(env, PGM_ADDRESSING, 2);
- ret = -EIO;
goto out;
}
len = be16_to_cpu(req->len);
/* Length field valid? */
if ((len < 16) || (len > 4088) || (len & 7)) {
program_interrupt(env, PGM_OPERAND, 2);
- ret = -EIO;
goto out;
}
memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
@@ -628,7 +624,6 @@ int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
out:
s390_cpu_physical_memory_unmap(env, req, map_size, 1);
- return ret;
}
int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb)
@@ -666,18 +661,19 @@ out:
#define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
#define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
-int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2,
- uint32_t ipb)
+void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
+ uint32_t ipb)
{
uint8_t mbk;
int update;
int dct;
+ CPUS390XState *env = &cpu->env;
trace_ioinst("schm");
if (SCHM_REG1_RES(reg1)) {
program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ return;
}
mbk = SCHM_REG1_MBK(reg1);
@@ -686,15 +682,13 @@ int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2,
if (update && (reg2 & 0x000000000000001f)) {
program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ return;
}
css_do_schm(mbk, update, dct, update ? reg2 : 0);
-
- return 0;
}
-int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1)
{
int cssid, ssid, schid, m;
SubchDev *sch;
@@ -702,8 +696,8 @@ int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1)
int cc;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
+ return;
}
trace_ioinst_sch_id("rsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
@@ -724,24 +718,23 @@ int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1)
cc = 1;
break;
}
-
- return cc;
-
+ setcc(cpu, cc);
}
#define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
#define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
#define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
-int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1)
{
int cc;
uint8_t cssid;
uint8_t chpid;
int ret;
+ CPUS390XState *env = &cpu->env;
if (RCHP_REG1_RES(reg1)) {
program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ return;
}
cssid = RCHP_REG1_CSSID(reg1);
@@ -764,19 +757,16 @@ int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1)
default:
/* Invalid channel subsystem. */
program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ return;
}
-
- return cc;
+ setcc(cpu, cc);
}
#define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
-int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1)
+void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1)
{
/* We do not provide address limit checking, so let's suppress it. */
if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
- program_interrupt(env, PGM_OPERAND, 2);
- return -EIO;
+ program_interrupt(&cpu->env, PGM_OPERAND, 2);
}
- return 0;
}
diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h
index 7bed2910dc..613da49b3b 100644
--- a/target-s390x/ioinst.h
+++ b/target-s390x/ioinst.h
@@ -214,20 +214,20 @@ typedef struct IOIntCode {
int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
int *schid);
-int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb);
-int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb);
-int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb);
-int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb);
+void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb);
+void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb);
+void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb);
+void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb);
int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb);
-int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb);
+void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb);
int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb);
-int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2,
- uint32_t ipb);
-int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1);
-int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1);
+void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
+ uint32_t ipb);
+void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1);
+void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1);
#endif
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 4923e0a717..a444f6999b 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -418,18 +418,6 @@ static void enter_pgmcheck(S390CPU *cpu, uint16_t code)
kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code);
}
-static inline void setcc(S390CPU *cpu, uint64_t cc)
-{
- CPUS390XState *env = &cpu->env;
- CPUState *cs = CPU(cpu);
-
- cs->kvm_run->psw_mask &= ~(3ull << 44);
- cs->kvm_run->psw_mask |= (cc & 3) << 44;
-
- env->psw.mask &= ~(3ul << 44);
- env->psw.mask |= (cc & 3) << 44;
-}
-
static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
uint16_t ipbh0)
{
@@ -439,6 +427,10 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
int r = 0;
cpu_synchronize_state(CPU(cpu));
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ enter_pgmcheck(cpu, PGM_PRIVILEGED);
+ return 0;
+ }
sccb = env->regs[ipbh0 & 0xf];
code = env->regs[(ipbh0 & 0xf0) >> 4];
@@ -454,8 +446,6 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run,
uint8_t ipa0, uint8_t ipa1, uint8_t ipb)
{
- int r = 0;
- int no_cc = 0;
CPUS390XState *env = &cpu->env;
CPUState *cs = CPU(cpu);
@@ -469,69 +459,61 @@ static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run,
switch (ipa1) {
case PRIV_XSCH:
- r = ioinst_handle_xsch(env, env->regs[1]);
+ ioinst_handle_xsch(cpu, env->regs[1]);
break;
case PRIV_CSCH:
- r = ioinst_handle_csch(env, env->regs[1]);
+ ioinst_handle_csch(cpu, env->regs[1]);
break;
case PRIV_HSCH:
- r = ioinst_handle_hsch(env, env->regs[1]);
+ ioinst_handle_hsch(cpu, env->regs[1]);
break;
case PRIV_MSCH:
- r = ioinst_handle_msch(env, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
case PRIV_SSCH:
- r = ioinst_handle_ssch(env, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
case PRIV_STCRW:
- r = ioinst_handle_stcrw(env, run->s390_sieic.ipb);
+ ioinst_handle_stcrw(cpu, run->s390_sieic.ipb);
break;
case PRIV_STSCH:
- r = ioinst_handle_stsch(env, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb);
break;
case PRIV_TSCH:
/* We should only get tsch via KVM_EXIT_S390_TSCH. */
fprintf(stderr, "Spurious tsch intercept\n");
break;
case PRIV_CHSC:
- r = ioinst_handle_chsc(env, run->s390_sieic.ipb);
+ ioinst_handle_chsc(cpu, run->s390_sieic.ipb);
break;
case PRIV_TPI:
/* This should have been handled by kvm already. */
fprintf(stderr, "Spurious tpi intercept\n");
break;
case PRIV_SCHM:
- no_cc = 1;
- r = ioinst_handle_schm(env, env->regs[1], env->regs[2],
- run->s390_sieic.ipb);
+ ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
+ run->s390_sieic.ipb);
break;
case PRIV_RSCH:
- r = ioinst_handle_rsch(env, env->regs[1]);
+ ioinst_handle_rsch(cpu, env->regs[1]);
break;
case PRIV_RCHP:
- r = ioinst_handle_rchp(env, env->regs[1]);
+ ioinst_handle_rchp(cpu, env->regs[1]);
break;
case PRIV_STCPS:
/* We do not provide this instruction, it is suppressed. */
- no_cc = 1;
- r = 0;
break;
case PRIV_SAL:
- no_cc = 1;
- r = ioinst_handle_sal(env, env->regs[1]);
+ ioinst_handle_sal(cpu, env->regs[1]);
break;
case PRIV_SIGA:
/* Not provided, set CC = 3 for subchannel not operational */
- r = 3;
+ setcc(cpu, 3);
break;
default:
return -1;
}
- if (r >= 0 && !no_cc) {
- setcc(cpu, r);
- }
-
return 0;
}
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 1690907169..10d04252d5 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -33,6 +33,7 @@
#include "exec/softmmu_exec.h"
#include "sysemu/cpus.h"
#include "sysemu/sysemu.h"
+#include "hw/s390x/ebcdic.h"
#endif
/* #define DEBUG_HELPER */
@@ -72,86 +73,6 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp)
#ifndef CONFIG_USER_ONLY
-/* EBCDIC handling */
-static const uint8_t ebcdic2ascii[] = {
- 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
- 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
- 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
- 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
- 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
- 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
- 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
- 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
- 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
- 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
- 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
- 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
- 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
- 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
- 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
- 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
- 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
- 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
- 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
- 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
- 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
- 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
- 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
- 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
-};
-
-static const uint8_t ascii2ebcdic[] = {
- 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
- 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
- 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
- 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
- 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
- 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
- 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
- 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
- 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
- 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
- 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
- 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
- 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
-};
-
-static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
- }
-}
-
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
{
qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
@@ -192,6 +113,29 @@ static void cpu_reset_all(void)
}
}
+static void cpu_full_reset_all(void)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ cpu_reset(cpu);
+ }
+}
+
+static int modified_clear_reset(S390CPU *cpu)
+{
+ S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
+
+ pause_all_vcpus();
+ cpu_synchronize_all_states();
+ cpu_full_reset_all();
+ io_subsystem_reset();
+ scc->load_normal(CPU(cpu));
+ cpu_synchronize_all_post_reset();
+ resume_all_vcpus();
+ return 0;
+}
+
static int load_normal_reset(S390CPU *cpu)
{
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
@@ -225,6 +169,9 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
}
switch (subcode) {
+ case 0:
+ modified_clear_reset(s390_env_get_cpu(env));
+ break;
case 1:
load_normal_reset(s390_env_get_cpu(env));
break;
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 2edf858733..1ff2922bbe 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -153,7 +153,7 @@ typedef enum {
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
{
uintptr_t p;
- for (p = start & -8; p < (stop + 7) & -8; p += 8) {
+ for (p = start & -8; p < ((stop + 7) & -8); p += 8) {
__asm__ __volatile__("flush\t%0" : : "r" (p));
}
}
diff --git a/tci.c b/tci.c
index 18c888e54d..6d64891557 100644
--- a/tci.c
+++ b/tci.c
@@ -1085,7 +1085,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
tmp8 = helper_ldb_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
tmp8 = *(uint8_t *)(host_addr + GUEST_BASE);
#endif
tci_write_reg8(t0, tmp8);
@@ -1097,7 +1096,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
tmp8 = helper_ldb_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
tmp8 = *(uint8_t *)(host_addr + GUEST_BASE);
#endif
tci_write_reg8s(t0, tmp8);
@@ -1109,7 +1107,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
tmp16 = helper_ldw_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
tmp16 = tswap16(*(uint16_t *)(host_addr + GUEST_BASE));
#endif
tci_write_reg16(t0, tmp16);
@@ -1121,7 +1118,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
tmp16 = helper_ldw_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
tmp16 = tswap16(*(uint16_t *)(host_addr + GUEST_BASE));
#endif
tci_write_reg16s(t0, tmp16);
@@ -1134,7 +1130,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
tmp32 = helper_ldl_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
tmp32 = tswap32(*(uint32_t *)(host_addr + GUEST_BASE));
#endif
tci_write_reg32(t0, tmp32);
@@ -1146,7 +1141,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
tmp32 = helper_ldl_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
tmp32 = tswap32(*(uint32_t *)(host_addr + GUEST_BASE));
#endif
tci_write_reg32s(t0, tmp32);
@@ -1159,7 +1153,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
tmp32 = helper_ldl_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
tmp32 = tswap32(*(uint32_t *)(host_addr + GUEST_BASE));
#endif
tci_write_reg32(t0, tmp32);
@@ -1174,7 +1167,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
tmp64 = helper_ldq_mmu(env, taddr, tci_read_i(&tb_ptr));
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
tmp64 = tswap64(*(uint64_t *)(host_addr + GUEST_BASE));
#endif
tci_write_reg(t0, tmp64);
@@ -1190,7 +1182,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
helper_stb_mmu(env, taddr, t0, t2);
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
*(uint8_t *)(host_addr + GUEST_BASE) = t0;
#endif
break;
@@ -1202,7 +1193,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
helper_stw_mmu(env, taddr, t0, t2);
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
*(uint16_t *)(host_addr + GUEST_BASE) = tswap16(t0);
#endif
break;
@@ -1214,7 +1204,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
helper_stl_mmu(env, taddr, t0, t2);
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
*(uint32_t *)(host_addr + GUEST_BASE) = tswap32(t0);
#endif
break;
@@ -1226,7 +1215,6 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr)
helper_stq_mmu(env, taddr, tmp64, t2);
#else
host_addr = (tcg_target_ulong)taddr;
- assert(taddr == host_addr);
*(uint64_t *)(host_addr + GUEST_BASE) = tswap64(tmp64);
#endif
break;
diff --git a/tests/.gitignore b/tests/.gitignore
index d11cc22373..ae5280ef68 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -5,6 +5,7 @@ check-qjson
check-qlist
check-qstring
test-aio
+test-throttle
test-cutils
test-hbitmap
test-iov
diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c
index 39be046ec7..15a885e882 100644
--- a/tests/test-coroutine.c
+++ b/tests/test-coroutine.c
@@ -182,17 +182,17 @@ static void perf_nesting(void)
unsigned int i, maxcycles, maxnesting;
double duration;
- maxcycles = 100000000;
+ maxcycles = 10000;
maxnesting = 1000;
Coroutine *root;
- NestData nd = {
- .n_enter = 0,
- .n_return = 0,
- .max = maxnesting,
- };
g_test_timer_start();
for (i = 0; i < maxcycles; i++) {
+ NestData nd = {
+ .n_enter = 0,
+ .n_return = 0,
+ .max = maxnesting,
+ };
root = qemu_coroutine_create(nest);
qemu_coroutine_enter(root, &nd);
}
@@ -202,6 +202,38 @@ static void perf_nesting(void)
maxcycles, maxnesting, duration);
}
+/*
+ * Yield benchmark
+ */
+
+static void coroutine_fn yield_loop(void *opaque)
+{
+ unsigned int *counter = opaque;
+
+ while ((*counter) > 0) {
+ (*counter)--;
+ qemu_coroutine_yield();
+ }
+}
+
+static void perf_yield(void)
+{
+ unsigned int i, maxcycles;
+ double duration;
+
+ maxcycles = 100000000;
+ i = maxcycles;
+ Coroutine *coroutine = qemu_coroutine_create(yield_loop);
+
+ g_test_timer_start();
+ while (i > 0) {
+ qemu_coroutine_enter(coroutine, &i);
+ }
+ duration = g_test_timer_elapsed();
+
+ g_test_message("Yield %u iterations: %f s\n",
+ maxcycles, duration);
+}
int main(int argc, char **argv)
{
@@ -214,6 +246,7 @@ int main(int argc, char **argv)
if (g_test_perf()) {
g_test_add_func("/perf/lifecycle", perf_lifecycle);
g_test_add_func("/perf/nesting", perf_nesting);
+ g_test_add_func("/perf/yield", perf_yield);
}
return g_test_run();
}
diff --git a/trace-events b/trace-events
index d4dba24551..8695e9e5b7 100644
--- a/trace-events
+++ b/trace-events
@@ -1109,7 +1109,6 @@ qemu_spice_wakeup(uint32_t qid) "%d"
qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "lr %d -> %d, tb -> %d -> %d"
# hw/display/qxl-render.c
-qxl_render_blit_guest_primary_initialized(void) ""
qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]"
qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d"
qxl_render_update_area_done(void *cookie) "%p"
@@ -1122,7 +1121,7 @@ spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "q
spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
-# hw/ppc/xics.c
+# hw/intc/xics.c
xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=%#x"
xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR %#"PRIx32"->%#"PRIx32
xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR %#"PRIx32" new XIRR %#"PRIx32
@@ -1167,9 +1166,9 @@ virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *dev
migrate_set_state(int new_state) "new state %d"
# kvm-all.c
-kvm_ioctl(int type, void *arg) "type %d, arg %p"
-kvm_vm_ioctl(int type, void *arg) "type %d, arg %p"
-kvm_vcpu_ioctl(int cpu_index, int type, void *arg) "cpu_index %d, type %d, arg %p"
+kvm_ioctl(int type, void *arg) "type 0x%x, arg %p"
+kvm_vm_ioctl(int type, void *arg) "type 0x%x, arg %p"
+kvm_vcpu_ioctl(int cpu_index, int type, void *arg) "cpu_index %d, type 0x%x, arg %p"
kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d"
# memory.c
diff --git a/translate-all.c b/translate-all.c
index 2c923c644b..e7aff928b6 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1679,8 +1679,9 @@ static int dump_region(void *priv, abi_ulong start,
/* dump memory mappings */
void page_dump(FILE *f)
{
- (void) fprintf(f, "%-8s %-8s %-8s %s\n",
- "start", "end", "size", "prot");
+ const int length = sizeof(abi_ulong) * 2;
+ (void) fprintf(f, "%-*s %-*s %-*s %s\n",
+ length, "start", length, "end", length, "size", "prot");
walk_memory_regions(f, dump_region);
}
diff --git a/util/iov.c b/util/iov.c
index f705586808..bb46c04e4d 100644
--- a/util/iov.c
+++ b/util/iov.c
@@ -181,13 +181,11 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
assert(iov[niov].iov_len > tail);
orig_len = iov[niov].iov_len;
iov[niov++].iov_len = tail;
- }
-
- ret = do_send_recv(sockfd, iov, niov, do_send);
-
- /* Undo the changes above before checking for errors */
- if (tail) {
+ ret = do_send_recv(sockfd, iov, niov, do_send);
+ /* Undo the changes above before checking for errors */
iov[niov-1].iov_len = orig_len;
+ } else {
+ ret = do_send_recv(sockfd, iov, niov, do_send);
}
if (offset) {
iov[0].iov_base -= offset;
diff --git a/util/osdep.c b/util/osdep.c
index 685c8ae889..62072b4be3 100644
--- a/util/osdep.c
+++ b/util/osdep.c
@@ -207,6 +207,13 @@ int qemu_open(const char *name, int flags, ...)
}
#endif
+#ifdef O_DIRECT
+ if (ret == -1 && errno == EINVAL && (flags & O_DIRECT)) {
+ error_report("file system may not support O_DIRECT");
+ errno = EINVAL; /* in case it was clobbered */
+ }
+#endif /* O_DIRECT */
+
return ret;
}