aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS21
-rw-r--r--accel/kvm/kvm-all.c2
-rwxr-xr-xconfigure27
-rw-r--r--cpus-common.c4
-rw-r--r--cpus.c186
-rw-r--r--default-configs/arm-softmmu.mak4
-rw-r--r--disas/m68k.c1
-rw-r--r--docs/usb2.txt4
-rw-r--r--dump.c2
-rw-r--r--fpu/softfloat.c573
-rw-r--r--hmp-commands-info.hx22
-rw-r--r--hmp-commands.hx15
-rw-r--r--hmp.c24
-rw-r--r--hmp.h1
-rw-r--r--hw/acpi/piix4.c2
-rw-r--r--hw/arm/boot.c11
-rw-r--r--hw/arm/fsl-imx6ul.c4
-rw-r--r--hw/arm/fsl-imx7.c4
-rw-r--r--hw/arm/highbank.c6
-rw-r--r--hw/arm/iotkit.c114
-rw-r--r--hw/arm/mps2-tz.c142
-rw-r--r--hw/arm/mps2.c17
-rw-r--r--hw/arm/pxa2xx.c2
-rw-r--r--hw/arm/vexpress.c64
-rw-r--r--hw/audio/cs4231a.c1
-rw-r--r--hw/audio/es1370.c235
-rw-r--r--hw/audio/gusemu_hal.c1
-rw-r--r--hw/audio/sb16.c11
-rw-r--r--hw/cpu/a15mpcore.c31
-rw-r--r--hw/display/bcm2835_fb.c218
-rw-r--r--hw/display/cg3.c1
-rw-r--r--hw/display/cirrus_vga.c3
-rw-r--r--hw/i2c/pm_smbus.c254
-rw-r--r--hw/i2c/smbus.c37
-rw-r--r--hw/i2c/smbus_ich9.c26
-rw-r--r--hw/i386/pc.c16
-rw-r--r--hw/intc/apic.c42
-rw-r--r--hw/intc/arm_gic.c2
-rw-r--r--hw/ipmi/isa_ipmi_bt.c68
-rw-r--r--hw/isa/vt82c686.c2
-rw-r--r--hw/mem/pc-dimm.c61
-rw-r--r--hw/misc/Makefile.objs3
-rw-r--r--hw/misc/bcm2835_property.c123
-rw-r--r--hw/misc/iotkit-secctl.c73
-rw-r--r--hw/misc/iotkit-sysctl.c261
-rw-r--r--hw/misc/iotkit-sysinfo.c128
-rw-r--r--hw/misc/mps2-fpgaio.c146
-rw-r--r--hw/misc/pvpanic.c11
-rw-r--r--hw/misc/trace-events16
-rw-r--r--hw/misc/tz-msc.c308
-rw-r--r--hw/misc/vmcoreinfo.c6
-rw-r--r--hw/ppc/prep.c3
-rw-r--r--hw/ppc/spapr.c30
-rw-r--r--hw/scsi/lsi53c895a.c4
-rw-r--r--hw/scsi/megasas.c2
-rw-r--r--hw/scsi/mptsas.c1
-rw-r--r--hw/scsi/vhost-scsi-common.c3
-rw-r--r--hw/scsi/vhost-scsi.c3
-rw-r--r--hw/scsi/vhost-user-scsi.c28
-rw-r--r--hw/ssi/pl022.c57
-rw-r--r--hw/timer/Makefile.objs1
-rw-r--r--hw/timer/cmsdk-apb-dualtimer.c515
-rw-r--r--hw/timer/mc146818rtc.c20
-rw-r--r--hw/timer/sh_timer.c1
-rw-r--r--hw/timer/trace-events5
-rw-r--r--hw/usb/dev-mtp.c93
-rw-r--r--hw/usb/hcd-ohci.c3
-rw-r--r--include/chardev/char-fe.h10
-rw-r--r--include/fpu/softfloat.h131
-rw-r--r--include/hw/arm/iotkit.h25
-rw-r--r--include/hw/display/bcm2835_fb.h59
-rw-r--r--include/hw/i2c/pm_smbus.h24
-rw-r--r--include/hw/i2c/smbus.h17
-rw-r--r--include/hw/mem/pc-dimm.h5
-rw-r--r--include/hw/misc/iotkit-secctl.h14
-rw-r--r--include/hw/misc/iotkit-sysctl.h49
-rw-r--r--include/hw/misc/iotkit-sysinfo.h37
-rw-r--r--include/hw/misc/mps2-fpgaio.h10
-rw-r--r--include/hw/misc/pvpanic.h11
-rw-r--r--include/hw/misc/tz-msc.h79
-rw-r--r--include/hw/misc/vmcoreinfo.h12
-rw-r--r--include/hw/nvram/fw_cfg.h18
-rw-r--r--include/hw/nvram/fw_cfg_keys.h45
-rw-r--r--include/hw/ssi/pl022.h51
-rw-r--r--include/hw/timer/cmsdk-apb-dualtimer.h72
-rw-r--r--include/hw/virtio/vhost-scsi-common.h1
-rw-r--r--include/hw/virtio/vhost-user-scsi.h1
-rw-r--r--include/qemu/main-loop.h4
-rw-r--r--include/qemu/qht.h1
-rw-r--r--include/qemu/qsp.h29
-rw-r--r--include/qemu/rcu_queue.h135
-rw-r--r--include/qemu/seqlock.h22
-rw-r--r--include/qemu/thread-posix.h4
-rw-r--r--include/qemu/thread-win32.h5
-rw-r--r--include/qemu/thread.h66
-rw-r--r--include/qom/cpu.h11
-rw-r--r--include/standard-headers/linux/qemu_fw_cfg.h97
-rw-r--r--job.c2
-rw-r--r--linux-user/main.c2
-rw-r--r--linux-user/syscall.c1611
-rw-r--r--monitor.c11
-rw-r--r--pc-bios/optionrom/linuxboot_dma.c4
-rw-r--r--pc-bios/optionrom/optionrom.h15
-rw-r--r--qemu-options.hx10
-rwxr-xr-xscripts/checkpatch.pl7
-rwxr-xr-xscripts/qemu-guest-agent/fsfreeze-hook2
-rwxr-xr-xscripts/update-linux-headers.sh4
-rw-r--r--scsi/qemu-pr-helper.c4
-rw-r--r--stubs/iothread-lock.c2
-rw-r--r--target/arm/arm-semi.c2
-rw-r--r--target/arm/cpu.h16
-rw-r--r--target/arm/helper.c339
-rw-r--r--target/arm/iwmmxt_helper.c234
-rw-r--r--target/arm/translate.c122
-rw-r--r--target/i386/cpu.c9
-rw-r--r--target/i386/cpu.h7
-rw-r--r--target/i386/kvm.c8
-rw-r--r--target/i386/seg_helper.c196
-rw-r--r--target/i386/translate.c2
-rw-r--r--target/s390x/cpu_models.c2
-rw-r--r--tests/Makefile.include115
-rw-r--r--tests/atomic_add-bench.c6
-rw-r--r--tests/boot-order-test.c2
-rw-r--r--tests/cpu-plug-test.c6
-rw-r--r--tests/device-introspect-test.c55
-rw-r--r--tests/fw_cfg-test.c2
-rw-r--r--tests/libqos/malloc-pc.c2
-rw-r--r--tests/libqtest.c52
-rw-r--r--tests/libqtest.h4
-rwxr-xr-xtests/qemu-iotests/22995
-rw-r--r--tests/qemu-iotests/229.out23
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/qom-test.c2
-rw-r--r--tests/test-char.c4
-rw-r--r--tests/test-hmp.c2
-rw-r--r--tests/test-rcu-list.c92
-rw-r--r--tests/test-rcu-simpleq.c2
-rw-r--r--tests/test-rcu-tailq.c2
-rw-r--r--tests/test-x86-cpuid-compat.c6
-rw-r--r--tests/vhost-user-test.c4
-rw-r--r--tests/virtio-ccw-test.c110
-rwxr-xr-xtests/vm/basevm.py2
-rw-r--r--util/Makefile.objs1
-rw-r--r--util/module.c22
-rw-r--r--util/oslib-win32.c15
-rw-r--r--util/qemu-thread-win32.c4
-rw-r--r--util/qht.c47
-rw-r--r--util/qsp.c828
-rw-r--r--vl.c7
149 files changed, 6802 insertions, 2472 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 6902a568f4..53a8b931bb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -451,10 +451,14 @@ F: hw/gpio/pl061.c
F: hw/input/pl050.c
F: hw/intc/pl190.c
F: hw/sd/pl181.c
+F: hw/ssi/pl022.c
+F: include/hw/ssi/pl022.h
F: hw/timer/pl031.c
F: include/hw/arm/primecell.h
F: hw/timer/cmsdk-apb-timer.c
F: include/hw/timer/cmsdk-apb-timer.h
+F: hw/timer/cmsdk-apb-dualtimer.c
+F: include/hw/timer/cmsdk-apb-dualtimer.h
F: hw/char/cmsdk-apb-uart.c
F: include/hw/char/cmsdk-apb-uart.h
F: hw/watchdog/cmsdk-apb-watchdog.c
@@ -463,6 +467,8 @@ F: hw/misc/tz-ppc.c
F: include/hw/misc/tz-ppc.h
F: hw/misc/tz-mpc.c
F: include/hw/misc/tz-mpc.h
+F: hw/misc/tz-msc.c
+F: include/hw/misc/tz-msc.h
ARM cores
M: Peter Maydell <peter.maydell@linaro.org>
@@ -537,6 +543,10 @@ F: hw/misc/mps2-*.c
F: include/hw/misc/mps2-*.h
F: hw/arm/iotkit.c
F: include/hw/arm/iotkit.h
+F: hw/misc/iotkit-sysctl.c
+F: include/hw/misc/iotkit-sysctl.h
+F: hw/misc/iotkit-sysinfo.c
+F: include/hw/misc/iotkit-sysinfo.h
Musicpal
M: Jan Kiszka <jan.kiszka@web.de>
@@ -1696,7 +1706,6 @@ F: qom/
X: qom/cpu.c
F: tests/check-qom-interface.c
F: tests/check-qom-proplist.c
-F: tests/qom-test.c
QMP
M: Markus Armbruster <armbru@redhat.com>
@@ -1708,6 +1717,16 @@ F: scripts/qmp/
F: tests/qmp-test.c
T: git git://repo.or.cz/qemu/armbru.git qapi-next
+qtest
+M: Paolo Bonzini <pbonzini@redhat.com>
+M: Thomas Huth <thuth@redhat.com>
+M: Laurent Vivier <lvivier@redhat.com>
+S: Maintained
+F: qtest.c
+F: tests/libqtest.*
+F: tests/libqos/
+F: tests/*-test.c
+
Register API
M: Alistair Francis <alistair@alistair23.me>
S: Maintained
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 38f468d8e2..de12f78eb8 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -1639,10 +1639,8 @@ static int kvm_init(MachineState *ms)
s->irq_set_ioctl = KVM_IRQ_LINE_STATUS;
}
-#ifdef KVM_CAP_READONLY_MEM
kvm_readonly_mem_allowed =
(kvm_check_extension(s, KVM_CAP_READONLY_MEM) > 0);
-#endif
kvm_eventfds_allowed =
(kvm_check_extension(s, KVM_CAP_IOEVENTFD) > 0);
diff --git a/configure b/configure
index e7bddc04b0..2ff272de79 100755
--- a/configure
+++ b/configure
@@ -3612,6 +3612,7 @@ fi
# libmpathpersist probe
if test "$mpath" != "no" ; then
+ # probe for the new API
cat > $TMPC <<EOF
#include <libudev.h>
#include <mpath_persist.h>
@@ -3633,8 +3634,26 @@ int main(void) {
EOF
if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
mpathpersist=yes
+ mpathpersist_new_api=yes
else
- mpathpersist=no
+ # probe for the old API
+ cat > $TMPC <<EOF
+#include <libudev.h>
+#include <mpath_persist.h>
+unsigned mpath_mx_alloc_len = 1024;
+int logsink;
+int main(void) {
+ struct udev *udev = udev_new();
+ mpath_lib_init(udev);
+ return 0;
+}
+EOF
+ if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
+ mpathpersist=yes
+ mpathpersist_new_api=no
+ else
+ mpathpersist=no
+ fi
fi
else
mpathpersist=no
@@ -6409,9 +6428,6 @@ if test "$bluez" = "yes" ; then
echo "CONFIG_BLUEZ=y" >> $config_host_mak
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
fi
-if test "$glib_subprocess" = "yes" ; then
- echo "CONFIG_HAS_GLIB_SUBPROCESS_TESTS=y" >> $config_host_mak
-fi
if test "$gtk" = "yes" ; then
echo "CONFIG_GTK=m" >> $config_host_mak
echo "CONFIG_GTKABI=$gtkabi" >> $config_host_mak
@@ -6495,6 +6511,9 @@ if test "$virtfs" = "yes" ; then
fi
if test "$mpath" = "yes" ; then
echo "CONFIG_MPATH=y" >> $config_host_mak
+ if test "$mpathpersist_new_api" = "yes"; then
+ echo "CONFIG_MPATH_NEW_API=y" >> $config_host_mak
+ fi
fi
if test "$vhost_scsi" = "yes" ; then
echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
diff --git a/cpus-common.c b/cpus-common.c
index 59f751ecf9..98dd8c6ff1 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -84,7 +84,7 @@ void cpu_list_add(CPUState *cpu)
} else {
assert(!cpu_index_auto_assigned);
}
- QTAILQ_INSERT_TAIL(&cpus, cpu, node);
+ QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node);
qemu_mutex_unlock(&qemu_cpu_list_lock);
finish_safe_work(cpu);
@@ -101,7 +101,7 @@ void cpu_list_remove(CPUState *cpu)
assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
- QTAILQ_REMOVE(&cpus, cpu, node);
+ QTAILQ_REMOVE_RCU(&cpus, cpu, node);
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
qemu_mutex_unlock(&qemu_cpu_list_lock);
}
diff --git a/cpus.c b/cpus.c
index b5844b7103..8ee6e5db93 100644
--- a/cpus.c
+++ b/cpus.c
@@ -121,8 +121,6 @@ static bool all_cpu_threads_idle(void)
/* Protected by TimersState seqlock */
static bool icount_sleep = true;
-/* Conversion factor from emulated instructions to virtual clock ticks. */
-static int icount_time_shift;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
#define MAX_ICOUNT_SHIFT 10
@@ -131,20 +129,27 @@ typedef struct TimersState {
int64_t cpu_ticks_prev;
int64_t cpu_ticks_offset;
- /* cpu_clock_offset can be read out of BQL, so protect it with
- * this lock.
+ /* Protect fields that can be respectively read outside the
+ * BQL, and written from multiple threads.
*/
QemuSeqLock vm_clock_seqlock;
- int64_t cpu_clock_offset;
- int32_t cpu_ticks_enabled;
- int64_t dummy;
+ QemuSpin vm_clock_lock;
+
+ int16_t cpu_ticks_enabled;
+
+ /* Conversion factor from emulated instructions to virtual clock ticks. */
+ int16_t icount_time_shift;
/* Compensate for varying guest execution speed. */
int64_t qemu_icount_bias;
+
+ int64_t vm_clock_warp_start;
+ int64_t cpu_clock_offset;
+
/* Only written by TCG thread */
int64_t qemu_icount;
+
/* for adjusting icount */
- int64_t vm_clock_warp_start;
QEMUTimer *icount_rt_timer;
QEMUTimer *icount_vm_timer;
QEMUTimer *icount_warp_timer;
@@ -245,16 +250,19 @@ void cpu_update_icount(CPUState *cpu)
int64_t executed = cpu_get_icount_executed(cpu);
cpu->icount_budget -= executed;
-#ifdef CONFIG_ATOMIC64
+#ifndef CONFIG_ATOMIC64
+ seqlock_write_lock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
+#endif
atomic_set__nocheck(&timers_state.qemu_icount,
- atomic_read__nocheck(&timers_state.qemu_icount) +
- executed);
-#else /* FIXME: we need 64bit atomics to do this safely */
- timers_state.qemu_icount += executed;
+ timers_state.qemu_icount + executed);
+#ifndef CONFIG_ATOMIC64
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
#endif
}
-int64_t cpu_get_icount_raw(void)
+static int64_t cpu_get_icount_raw_locked(void)
{
CPUState *cpu = current_cpu;
@@ -266,20 +274,30 @@ int64_t cpu_get_icount_raw(void)
/* Take into account what has run */
cpu_update_icount(cpu);
}
-#ifdef CONFIG_ATOMIC64
+ /* The read is protected by the seqlock, so __nocheck is okay. */
return atomic_read__nocheck(&timers_state.qemu_icount);
-#else /* FIXME: we need 64bit atomics to do this safely */
- return timers_state.qemu_icount;
-#endif
}
-/* Return the virtual CPU time, based on the instruction counter. */
static int64_t cpu_get_icount_locked(void)
{
- int64_t icount = cpu_get_icount_raw();
- return timers_state.qemu_icount_bias + cpu_icount_to_ns(icount);
+ int64_t icount = cpu_get_icount_raw_locked();
+ return atomic_read__nocheck(&timers_state.qemu_icount_bias) + cpu_icount_to_ns(icount);
}
+int64_t cpu_get_icount_raw(void)
+{
+ int64_t icount;
+ unsigned start;
+
+ do {
+ start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
+ icount = cpu_get_icount_raw_locked();
+ } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
+
+ return icount;
+}
+
+/* Return the virtual CPU time, based on the instruction counter. */
int64_t cpu_get_icount(void)
{
int64_t icount;
@@ -295,14 +313,29 @@ int64_t cpu_get_icount(void)
int64_t cpu_icount_to_ns(int64_t icount)
{
- return icount << icount_time_shift;
+ return icount << atomic_read(&timers_state.icount_time_shift);
+}
+
+static int64_t cpu_get_ticks_locked(void)
+{
+ int64_t ticks = timers_state.cpu_ticks_offset;
+ if (timers_state.cpu_ticks_enabled) {
+ ticks += cpu_get_host_ticks();
+ }
+
+ if (timers_state.cpu_ticks_prev > ticks) {
+ /* Non increasing ticks may happen if the host uses software suspend. */
+ timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
+ ticks = timers_state.cpu_ticks_prev;
+ }
+
+ timers_state.cpu_ticks_prev = ticks;
+ return ticks;
}
/* return the time elapsed in VM between vm_start and vm_stop. Unless
* icount is active, cpu_get_ticks() uses units of the host CPU cycle
* counter.
- *
- * Caller must hold the BQL
*/
int64_t cpu_get_ticks(void)
{
@@ -312,19 +345,9 @@ int64_t cpu_get_ticks(void)
return cpu_get_icount();
}
- ticks = timers_state.cpu_ticks_offset;
- if (timers_state.cpu_ticks_enabled) {
- ticks += cpu_get_host_ticks();
- }
-
- if (timers_state.cpu_ticks_prev > ticks) {
- /* Note: non increasing ticks may happen if the host uses
- software suspend */
- timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
- ticks = timers_state.cpu_ticks_prev;
- }
-
- timers_state.cpu_ticks_prev = ticks;
+ qemu_spin_lock(&timers_state.vm_clock_lock);
+ ticks = cpu_get_ticks_locked();
+ qemu_spin_unlock(&timers_state.vm_clock_lock);
return ticks;
}
@@ -361,14 +384,15 @@ int64_t cpu_get_clock(void)
*/
void cpu_enable_ticks(void)
{
- /* Here, the really thing protected by seqlock is cpu_clock_offset. */
- seqlock_write_begin(&timers_state.vm_clock_seqlock);
+ seqlock_write_lock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
if (!timers_state.cpu_ticks_enabled) {
timers_state.cpu_ticks_offset -= cpu_get_host_ticks();
timers_state.cpu_clock_offset -= get_clock();
timers_state.cpu_ticks_enabled = 1;
}
- seqlock_write_end(&timers_state.vm_clock_seqlock);
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
}
/* disable cpu_get_ticks() : the clock is stopped. You must not call
@@ -377,14 +401,15 @@ void cpu_enable_ticks(void)
*/
void cpu_disable_ticks(void)
{
- /* Here, the really thing protected by seqlock is cpu_clock_offset. */
- seqlock_write_begin(&timers_state.vm_clock_seqlock);
+ seqlock_write_lock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
if (timers_state.cpu_ticks_enabled) {
timers_state.cpu_ticks_offset += cpu_get_host_ticks();
timers_state.cpu_clock_offset = cpu_get_clock_locked();
timers_state.cpu_ticks_enabled = 0;
}
- seqlock_write_end(&timers_state.vm_clock_seqlock);
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
}
/* Correlation between real and virtual time is always going to be
@@ -407,7 +432,8 @@ static void icount_adjust(void)
return;
}
- seqlock_write_begin(&timers_state.vm_clock_seqlock);
+ seqlock_write_lock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
cur_time = cpu_get_clock_locked();
cur_icount = cpu_get_icount_locked();
@@ -415,20 +441,24 @@ static void icount_adjust(void)
/* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */
if (delta > 0
&& last_delta + ICOUNT_WOBBLE < delta * 2
- && icount_time_shift > 0) {
+ && timers_state.icount_time_shift > 0) {
/* The guest is getting too far ahead. Slow time down. */
- icount_time_shift--;
+ atomic_set(&timers_state.icount_time_shift,
+ timers_state.icount_time_shift - 1);
}
if (delta < 0
&& last_delta - ICOUNT_WOBBLE > delta * 2
- && icount_time_shift < MAX_ICOUNT_SHIFT) {
+ && timers_state.icount_time_shift < MAX_ICOUNT_SHIFT) {
/* The guest is getting too far behind. Speed time up. */
- icount_time_shift++;
+ atomic_set(&timers_state.icount_time_shift,
+ timers_state.icount_time_shift + 1);
}
last_delta = delta;
- timers_state.qemu_icount_bias = cur_icount
- - (timers_state.qemu_icount << icount_time_shift);
- seqlock_write_end(&timers_state.vm_clock_seqlock);
+ atomic_set__nocheck(&timers_state.qemu_icount_bias,
+ cur_icount - (timers_state.qemu_icount
+ << timers_state.icount_time_shift));
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
}
static void icount_adjust_rt(void *opaque)
@@ -448,7 +478,8 @@ static void icount_adjust_vm(void *opaque)
static int64_t qemu_icount_round(int64_t count)
{
- return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
+ int shift = atomic_read(&timers_state.icount_time_shift);
+ return (count + (1 << shift) - 1) >> shift;
}
static void icount_warp_rt(void)
@@ -468,7 +499,8 @@ static void icount_warp_rt(void)
return;
}
- seqlock_write_begin(&timers_state.vm_clock_seqlock);
+ seqlock_write_lock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
if (runstate_is_running()) {
int64_t clock = REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT,
cpu_get_clock_locked());
@@ -484,10 +516,12 @@ static void icount_warp_rt(void)
int64_t delta = clock - cur_icount;
warp_delta = MIN(warp_delta, delta);
}
- timers_state.qemu_icount_bias += warp_delta;
+ atomic_set__nocheck(&timers_state.qemu_icount_bias,
+ timers_state.qemu_icount_bias + warp_delta);
}
timers_state.vm_clock_warp_start = -1;
- seqlock_write_end(&timers_state.vm_clock_seqlock);
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) {
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
@@ -512,9 +546,12 @@ void qtest_clock_warp(int64_t dest)
int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
- seqlock_write_begin(&timers_state.vm_clock_seqlock);
- timers_state.qemu_icount_bias += warp;
- seqlock_write_end(&timers_state.vm_clock_seqlock);
+ seqlock_write_lock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
+ atomic_set__nocheck(&timers_state.qemu_icount_bias,
+ timers_state.qemu_icount_bias + warp);
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]);
@@ -581,9 +618,12 @@ void qemu_start_warp_timer(void)
* It is useful when we want a deterministic execution time,
* isolated from host latencies.
*/
- seqlock_write_begin(&timers_state.vm_clock_seqlock);
- timers_state.qemu_icount_bias += deadline;
- seqlock_write_end(&timers_state.vm_clock_seqlock);
+ seqlock_write_lock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
+ atomic_set__nocheck(&timers_state.qemu_icount_bias,
+ timers_state.qemu_icount_bias + deadline);
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
} else {
/*
@@ -594,12 +634,14 @@ void qemu_start_warp_timer(void)
* you will not be sending network packets continuously instead of
* every 100ms.
*/
- seqlock_write_begin(&timers_state.vm_clock_seqlock);
+ seqlock_write_lock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
if (timers_state.vm_clock_warp_start == -1
|| timers_state.vm_clock_warp_start > clock) {
timers_state.vm_clock_warp_start = clock;
}
- seqlock_write_end(&timers_state.vm_clock_seqlock);
+ seqlock_write_unlock(&timers_state.vm_clock_seqlock,
+ &timers_state.vm_clock_lock);
timer_mod_anticipate(timers_state.icount_warp_timer,
clock + deadline);
}
@@ -700,7 +742,7 @@ static const VMStateDescription vmstate_timers = {
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT64(cpu_ticks_offset, TimersState),
- VMSTATE_INT64(dummy, TimersState),
+ VMSTATE_UNUSED(8),
VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
VMSTATE_END_OF_LIST()
},
@@ -812,7 +854,7 @@ void configure_icount(QemuOpts *opts, Error **errp)
}
if (strcmp(option, "auto") != 0) {
errno = 0;
- icount_time_shift = strtol(option, &rem_str, 0);
+ timers_state.icount_time_shift = strtol(option, &rem_str, 0);
if (errno != 0 || *rem_str != '\0' || !strlen(option)) {
error_setg(errp, "icount: Invalid shift value");
}
@@ -828,7 +870,7 @@ void configure_icount(QemuOpts *opts, Error **errp)
/* 125MIPS seems a reasonable initial guess at the guest speed.
It will be corrected fairly quickly anyway. */
- icount_time_shift = 3;
+ timers_state.icount_time_shift = 3;
/* Have both realtime and virtual time triggers for speed adjustment.
The realtime trigger catches emulated time passing too slowly,
@@ -1491,7 +1533,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg)
atomic_mb_set(&cpu->exit_request, 0);
}
- qemu_tcg_rr_wait_io_event(cpu ? cpu : QTAILQ_FIRST(&cpus));
+ qemu_tcg_rr_wait_io_event(cpu ? cpu : first_cpu);
deal_with_unplugged_cpus();
}
@@ -1762,10 +1804,16 @@ bool qemu_mutex_iothread_locked(void)
return iothread_locked;
}
-void qemu_mutex_lock_iothread(void)
+/*
+ * The BQL is taken from so many places that it is worth profiling the
+ * callers directly, instead of funneling them all through a single function.
+ */
+void qemu_mutex_lock_iothread_impl(const char *file, int line)
{
+ QemuMutexLockFunc bql_lock = atomic_read(&qemu_bql_mutex_lock_func);
+
g_assert(!qemu_mutex_iothread_locked());
- qemu_mutex_lock(&qemu_global_mutex);
+ bql_lock(&qemu_global_mutex, file, line);
iothread_locked = true;
}
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index a92bc34fb2..0483d548d9 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -103,6 +103,7 @@ CONFIG_STM32F2XX_SPI=y
CONFIG_STM32F205_SOC=y
CONFIG_CMSDK_APB_TIMER=y
+CONFIG_CMSDK_APB_DUALTIMER=y
CONFIG_CMSDK_APB_UART=y
CONFIG_CMSDK_APB_WATCHDOG=y
@@ -110,9 +111,12 @@ CONFIG_MPS2_FPGAIO=y
CONFIG_MPS2_SCC=y
CONFIG_TZ_MPC=y
+CONFIG_TZ_MSC=y
CONFIG_TZ_PPC=y
CONFIG_IOTKIT=y
CONFIG_IOTKIT_SECCTL=y
+CONFIG_IOTKIT_SYSCTL=y
+CONFIG_IOTKIT_SYSINFO=y
CONFIG_VERSATILE=y
CONFIG_VERSATILE_PCI=y
diff --git a/disas/m68k.c b/disas/m68k.c
index a687df437c..0dc8aa1a3c 100644
--- a/disas/m68k.c
+++ b/disas/m68k.c
@@ -1623,6 +1623,7 @@ print_insn_arg (const char *d,
case 'X':
place = '8';
+ /* fall through */
case 'Y':
case 'Z':
case 'W':
diff --git a/docs/usb2.txt b/docs/usb2.txt
index f63c8d9465..172614d3a7 100644
--- a/docs/usb2.txt
+++ b/docs/usb2.txt
@@ -94,8 +94,8 @@ physical port addressing
First you can (for all USB devices) specify the physical port where
the device will show up in the guest. This can be done using the
-"port" property. UHCI has two root ports (1,2). EHCI has four root
-ports (1-4), the emulated (1.1) USB hub has eight ports.
+"port" property. UHCI has two root ports (1,2). EHCI has six root
+ports (1-6), the emulated (1.1) USB hub has eight ports.
Plugging a tablet into UHCI port 1 works like this:
diff --git a/dump.c b/dump.c
index 04467b353e..500b554523 100644
--- a/dump.c
+++ b/dump.c
@@ -1742,7 +1742,7 @@ static void dump_init(DumpState *s, int fd, bool has_format,
warn_report("guest note is not present");
} else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) {
warn_report("guest note size is invalid: %" PRIu32, size);
- } else if (format != VMCOREINFO_FORMAT_ELF) {
+ } else if (format != FW_CFG_VMCOREINFO_FORMAT_ELF) {
warn_report("guest note format is unsupported: %" PRIu16, format);
} else {
s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 7d63cffdeb..59ca356d0e 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -1293,19 +1293,23 @@ float32 float64_to_float32(float64 a, float_status *s)
* Arithmetic.
*/
-static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
+static FloatParts round_to_int(FloatParts a, int rmode,
+ int scale, float_status *s)
{
- if (is_nan(a.cls)) {
+ switch (a.cls) {
+ case float_class_qnan:
+ case float_class_snan:
return return_nan(a, s);
- }
- switch (a.cls) {
case float_class_zero:
case float_class_inf:
- case float_class_qnan:
/* already "integral" */
break;
+
case float_class_normal:
+ scale = MIN(MAX(scale, -0x10000), 0x10000);
+ a.exp += scale;
+
if (a.exp >= DECOMPOSED_BINARY_POINT) {
/* already integral */
break;
@@ -1314,7 +1318,7 @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
bool one;
/* all fractional */
s->float_exception_flags |= float_flag_inexact;
- switch (rounding_mode) {
+ switch (rmode) {
case float_round_nearest_even:
one = a.exp == -1 && a.frac > DECOMPOSED_IMPLICIT_BIT;
break;
@@ -1347,7 +1351,7 @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
uint64_t rnd_mask = rnd_even_mask >> 1;
uint64_t inc;
- switch (rounding_mode) {
+ switch (rmode) {
case float_round_nearest_even:
inc = ((a.frac & rnd_even_mask) != frac_lsbm1 ? frac_lsbm1 : 0);
break;
@@ -1387,28 +1391,28 @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
float16 float16_round_to_int(float16 a, float_status *s)
{
FloatParts pa = float16_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
return float16_round_pack_canonical(pr, s);
}
float32 float32_round_to_int(float32 a, float_status *s)
{
FloatParts pa = float32_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
return float32_round_pack_canonical(pr, s);
}
float64 float64_round_to_int(float64 a, float_status *s)
{
FloatParts pa = float64_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
return float64_round_pack_canonical(pr, s);
}
float64 float64_trunc_to_int(float64 a, float_status *s)
{
FloatParts pa = float64_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, float_round_to_zero, s);
+ FloatParts pr = round_to_int(pa, float_round_to_zero, 0, s);
return float64_round_pack_canonical(pr, s);
}
@@ -1423,13 +1427,13 @@ float64 float64_trunc_to_int(float64 a, float_status *s)
* is returned.
*/
-static int64_t round_to_int_and_pack(FloatParts in, int rmode,
+static int64_t round_to_int_and_pack(FloatParts in, int rmode, int scale,
int64_t min, int64_t max,
float_status *s)
{
uint64_t r;
int orig_flags = get_float_exception_flags(s);
- FloatParts p = round_to_int(in, rmode, s);
+ FloatParts p = round_to_int(in, rmode, scale, s);
switch (p.cls) {
case float_class_snan:
@@ -1469,38 +1473,158 @@ static int64_t round_to_int_and_pack(FloatParts in, int rmode,
}
}
-#define FLOAT_TO_INT(fsz, isz) \
-int ## isz ## _t float ## fsz ## _to_int ## isz(float ## fsz a, \
- float_status *s) \
-{ \
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
- return round_to_int_and_pack(p, s->float_rounding_mode, \
- INT ## isz ## _MIN, INT ## isz ## _MAX,\
- s); \
-} \
- \
-int ## isz ## _t float ## fsz ## _to_int ## isz ## _round_to_zero \
- (float ## fsz a, float_status *s) \
-{ \
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
- return round_to_int_and_pack(p, float_round_to_zero, \
- INT ## isz ## _MIN, INT ## isz ## _MAX,\
- s); \
+int16_t float16_to_int16_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, INT16_MIN, INT16_MAX, s);
+}
+
+int32_t float16_to_int32_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+int64_t float16_to_int64_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+int16_t float32_to_int16_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, INT16_MIN, INT16_MAX, s);
+}
+
+int32_t float32_to_int32_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+int64_t float32_to_int64_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+int16_t float64_to_int16_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, INT16_MIN, INT16_MAX, s);
+}
+
+int32_t float64_to_int32_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+int64_t float64_to_int64_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+int16_t float16_to_int16(float16 a, float_status *s)
+{
+ return float16_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int32_t float16_to_int32(float16 a, float_status *s)
+{
+ return float16_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int64_t float16_to_int64(float16 a, float_status *s)
+{
+ return float16_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int16_t float32_to_int16(float32 a, float_status *s)
+{
+ return float32_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int32_t float32_to_int32(float32 a, float_status *s)
+{
+ return float32_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int64_t float32_to_int64(float32 a, float_status *s)
+{
+ return float32_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int16_t float64_to_int16(float64 a, float_status *s)
+{
+ return float64_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int32_t float64_to_int32(float64 a, float_status *s)
+{
+ return float64_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int64_t float64_to_int64(float64 a, float_status *s)
+{
+ return float64_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int16_t float16_to_int16_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_int16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int32_t float16_to_int32_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_int32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int64_t float16_to_int64_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_int64_scalbn(a, float_round_to_zero, 0, s);
}
-FLOAT_TO_INT(16, 16)
-FLOAT_TO_INT(16, 32)
-FLOAT_TO_INT(16, 64)
+int16_t float32_to_int16_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_int16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int32_t float32_to_int32_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_int32_scalbn(a, float_round_to_zero, 0, s);
+}
-FLOAT_TO_INT(32, 16)
-FLOAT_TO_INT(32, 32)
-FLOAT_TO_INT(32, 64)
+int64_t float32_to_int64_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_int64_scalbn(a, float_round_to_zero, 0, s);
+}
-FLOAT_TO_INT(64, 16)
-FLOAT_TO_INT(64, 32)
-FLOAT_TO_INT(64, 64)
+int16_t float64_to_int16_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_int16_scalbn(a, float_round_to_zero, 0, s);
+}
-#undef FLOAT_TO_INT
+int32_t float64_to_int32_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_int32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+int64_t float64_to_int64_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_int64_scalbn(a, float_round_to_zero, 0, s);
+}
/*
* Returns the result of converting the floating-point value `a' to
@@ -1515,11 +1639,12 @@ FLOAT_TO_INT(64, 64)
* flag.
*/
-static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
- float_status *s)
+static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, int scale,
+ uint64_t max, float_status *s)
{
int orig_flags = get_float_exception_flags(s);
- FloatParts p = round_to_int(in, rmode, s);
+ FloatParts p = round_to_int(in, rmode, scale, s);
+ uint64_t r;
switch (p.cls) {
case float_class_snan:
@@ -1532,8 +1657,6 @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
case float_class_zero:
return 0;
case float_class_normal:
- {
- uint64_t r;
if (p.sign) {
s->float_exception_flags = orig_flags | float_flag_invalid;
return 0;
@@ -1555,45 +1678,165 @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
if (r > max) {
s->float_exception_flags = orig_flags | float_flag_invalid;
return max;
- } else {
- return r;
}
- }
+ return r;
default:
g_assert_not_reached();
}
}
-#define FLOAT_TO_UINT(fsz, isz) \
-uint ## isz ## _t float ## fsz ## _to_uint ## isz(float ## fsz a, \
- float_status *s) \
-{ \
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
- return round_to_uint_and_pack(p, s->float_rounding_mode, \
- UINT ## isz ## _MAX, s); \
-} \
- \
-uint ## isz ## _t float ## fsz ## _to_uint ## isz ## _round_to_zero \
- (float ## fsz a, float_status *s) \
-{ \
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
- return round_to_uint_and_pack(p, float_round_to_zero, \
- UINT ## isz ## _MAX, s); \
+uint16_t float16_to_uint16_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, UINT16_MAX, s);
+}
+
+uint32_t float16_to_uint32_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, UINT32_MAX, s);
+}
+
+uint64_t float16_to_uint64_scalbn(float16 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
+ rmode, scale, UINT64_MAX, s);
+}
+
+uint16_t float32_to_uint16_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, UINT16_MAX, s);
+}
+
+uint32_t float32_to_uint32_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, UINT32_MAX, s);
+}
+
+uint64_t float32_to_uint64_scalbn(float32 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
+ rmode, scale, UINT64_MAX, s);
+}
+
+uint16_t float64_to_uint16_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, UINT16_MAX, s);
+}
+
+uint32_t float64_to_uint32_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, UINT32_MAX, s);
}
-FLOAT_TO_UINT(16, 16)
-FLOAT_TO_UINT(16, 32)
-FLOAT_TO_UINT(16, 64)
+uint64_t float64_to_uint64_scalbn(float64 a, int rmode, int scale,
+ float_status *s)
+{
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
+ rmode, scale, UINT64_MAX, s);
+}
+
+uint16_t float16_to_uint16(float16 a, float_status *s)
+{
+ return float16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint32_t float16_to_uint32(float16 a, float_status *s)
+{
+ return float16_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint64_t float16_to_uint64(float16 a, float_status *s)
+{
+ return float16_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint16_t float32_to_uint16(float32 a, float_status *s)
+{
+ return float32_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint32_t float32_to_uint32(float32 a, float_status *s)
+{
+ return float32_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint64_t float32_to_uint64(float32 a, float_status *s)
+{
+ return float32_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint16_t float64_to_uint16(float64 a, float_status *s)
+{
+ return float64_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+uint32_t float64_to_uint32(float64 a, float_status *s)
+{
+ return float64_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
+}
-FLOAT_TO_UINT(32, 16)
-FLOAT_TO_UINT(32, 32)
-FLOAT_TO_UINT(32, 64)
+uint64_t float64_to_uint64(float64 a, float_status *s)
+{
+ return float64_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
+}
-FLOAT_TO_UINT(64, 16)
-FLOAT_TO_UINT(64, 32)
-FLOAT_TO_UINT(64, 64)
+uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_uint16_scalbn(a, float_round_to_zero, 0, s);
+}
-#undef FLOAT_TO_UINT
+uint32_t float16_to_uint32_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_uint32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint64_t float16_to_uint64_round_to_zero(float16 a, float_status *s)
+{
+ return float16_to_uint64_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint16_t float32_to_uint16_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_uint16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint32_t float32_to_uint32_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_uint32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint64_t float32_to_uint64_round_to_zero(float32 a, float_status *s)
+{
+ return float32_to_uint64_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint16_t float64_to_uint16_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_uint16_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint32_t float64_to_uint32_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_uint32_scalbn(a, float_round_to_zero, 0, s);
+}
+
+uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *s)
+{
+ return float64_to_uint64_scalbn(a, float_round_to_zero, 0, s);
+}
/*
* Integer to float conversions
@@ -1603,81 +1846,122 @@ FLOAT_TO_UINT(64, 64)
* to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*/
-static FloatParts int_to_float(int64_t a, float_status *status)
+static FloatParts int_to_float(int64_t a, int scale, float_status *status)
{
- FloatParts r = {};
+ FloatParts r = { .sign = false };
+
if (a == 0) {
r.cls = float_class_zero;
- r.sign = false;
- } else if (a == (1ULL << 63)) {
- r.cls = float_class_normal;
- r.sign = true;
- r.frac = DECOMPOSED_IMPLICIT_BIT;
- r.exp = 63;
} else {
- uint64_t f;
+ uint64_t f = a;
+ int shift;
+
+ r.cls = float_class_normal;
if (a < 0) {
- f = -a;
+ f = -f;
r.sign = true;
- } else {
- f = a;
- r.sign = false;
}
- int shift = clz64(f) - 1;
- r.cls = float_class_normal;
- r.exp = (DECOMPOSED_BINARY_POINT - shift);
- r.frac = f << shift;
+ shift = clz64(f) - 1;
+ scale = MIN(MAX(scale, -0x10000), 0x10000);
+
+ r.exp = DECOMPOSED_BINARY_POINT - shift + scale;
+ r.frac = (shift < 0 ? DECOMPOSED_IMPLICIT_BIT : f << shift);
}
return r;
}
-float16 int64_to_float16(int64_t a, float_status *status)
+float16 int64_to_float16_scalbn(int64_t a, int scale, float_status *status)
{
- FloatParts pa = int_to_float(a, status);
+ FloatParts pa = int_to_float(a, scale, status);
return float16_round_pack_canonical(pa, status);
}
+float16 int32_to_float16_scalbn(int32_t a, int scale, float_status *status)
+{
+ return int64_to_float16_scalbn(a, scale, status);
+}
+
+float16 int16_to_float16_scalbn(int16_t a, int scale, float_status *status)
+{
+ return int64_to_float16_scalbn(a, scale, status);
+}
+
+float16 int64_to_float16(int64_t a, float_status *status)
+{
+ return int64_to_float16_scalbn(a, 0, status);
+}
+
float16 int32_to_float16(int32_t a, float_status *status)
{
- return int64_to_float16(a, status);
+ return int64_to_float16_scalbn(a, 0, status);
}
float16 int16_to_float16(int16_t a, float_status *status)
{
- return int64_to_float16(a, status);
+ return int64_to_float16_scalbn(a, 0, status);
}
-float32 int64_to_float32(int64_t a, float_status *status)
+float32 int64_to_float32_scalbn(int64_t a, int scale, float_status *status)
{
- FloatParts pa = int_to_float(a, status);
+ FloatParts pa = int_to_float(a, scale, status);
return float32_round_pack_canonical(pa, status);
}
+float32 int32_to_float32_scalbn(int32_t a, int scale, float_status *status)
+{
+ return int64_to_float32_scalbn(a, scale, status);
+}
+
+float32 int16_to_float32_scalbn(int16_t a, int scale, float_status *status)
+{
+ return int64_to_float32_scalbn(a, scale, status);
+}
+
+float32 int64_to_float32(int64_t a, float_status *status)
+{
+ return int64_to_float32_scalbn(a, 0, status);
+}
+
float32 int32_to_float32(int32_t a, float_status *status)
{
- return int64_to_float32(a, status);
+ return int64_to_float32_scalbn(a, 0, status);
}
float32 int16_to_float32(int16_t a, float_status *status)
{
- return int64_to_float32(a, status);
+ return int64_to_float32_scalbn(a, 0, status);
}
-float64 int64_to_float64(int64_t a, float_status *status)
+float64 int64_to_float64_scalbn(int64_t a, int scale, float_status *status)
{
- FloatParts pa = int_to_float(a, status);
+ FloatParts pa = int_to_float(a, scale, status);
return float64_round_pack_canonical(pa, status);
}
+float64 int32_to_float64_scalbn(int32_t a, int scale, float_status *status)
+{
+ return int64_to_float64_scalbn(a, scale, status);
+}
+
+float64 int16_to_float64_scalbn(int16_t a, int scale, float_status *status)
+{
+ return int64_to_float64_scalbn(a, scale, status);
+}
+
+float64 int64_to_float64(int64_t a, float_status *status)
+{
+ return int64_to_float64_scalbn(a, 0, status);
+}
+
float64 int32_to_float64(int32_t a, float_status *status)
{
- return int64_to_float64(a, status);
+ return int64_to_float64_scalbn(a, 0, status);
}
float64 int16_to_float64(int16_t a, float_status *status)
{
- return int64_to_float64(a, status);
+ return int64_to_float64_scalbn(a, 0, status);
}
@@ -1689,73 +1973,120 @@ float64 int16_to_float64(int16_t a, float_status *status)
* IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*/
-static FloatParts uint_to_float(uint64_t a, float_status *status)
+static FloatParts uint_to_float(uint64_t a, int scale, float_status *status)
{
- FloatParts r = { .sign = false};
+ FloatParts r = { .sign = false };
if (a == 0) {
r.cls = float_class_zero;
} else {
- int spare_bits = clz64(a) - 1;
+ scale = MIN(MAX(scale, -0x10000), 0x10000);
r.cls = float_class_normal;
- r.exp = DECOMPOSED_BINARY_POINT - spare_bits;
- if (spare_bits < 0) {
- shift64RightJamming(a, -spare_bits, &a);
+ if ((int64_t)a < 0) {
+ r.exp = DECOMPOSED_BINARY_POINT + 1 + scale;
+ shift64RightJamming(a, 1, &a);
r.frac = a;
} else {
- r.frac = a << spare_bits;
+ int shift = clz64(a) - 1;
+ r.exp = DECOMPOSED_BINARY_POINT - shift + scale;
+ r.frac = a << shift;
}
}
return r;
}
-float16 uint64_to_float16(uint64_t a, float_status *status)
+float16 uint64_to_float16_scalbn(uint64_t a, int scale, float_status *status)
{
- FloatParts pa = uint_to_float(a, status);
+ FloatParts pa = uint_to_float(a, scale, status);
return float16_round_pack_canonical(pa, status);
}
+float16 uint32_to_float16_scalbn(uint32_t a, int scale, float_status *status)
+{
+ return uint64_to_float16_scalbn(a, scale, status);
+}
+
+float16 uint16_to_float16_scalbn(uint16_t a, int scale, float_status *status)
+{
+ return uint64_to_float16_scalbn(a, scale, status);
+}
+
+float16 uint64_to_float16(uint64_t a, float_status *status)
+{
+ return uint64_to_float16_scalbn(a, 0, status);
+}
+
float16 uint32_to_float16(uint32_t a, float_status *status)
{
- return uint64_to_float16(a, status);
+ return uint64_to_float16_scalbn(a, 0, status);
}
float16 uint16_to_float16(uint16_t a, float_status *status)
{
- return uint64_to_float16(a, status);
+ return uint64_to_float16_scalbn(a, 0, status);
}
-float32 uint64_to_float32(uint64_t a, float_status *status)
+float32 uint64_to_float32_scalbn(uint64_t a, int scale, float_status *status)
{
- FloatParts pa = uint_to_float(a, status);
+ FloatParts pa = uint_to_float(a, scale, status);
return float32_round_pack_canonical(pa, status);
}
+float32 uint32_to_float32_scalbn(uint32_t a, int scale, float_status *status)
+{
+ return uint64_to_float32_scalbn(a, scale, status);
+}
+
+float32 uint16_to_float32_scalbn(uint16_t a, int scale, float_status *status)
+{
+ return uint64_to_float32_scalbn(a, scale, status);
+}
+
+float32 uint64_to_float32(uint64_t a, float_status *status)
+{
+ return uint64_to_float32_scalbn(a, 0, status);
+}
+
float32 uint32_to_float32(uint32_t a, float_status *status)
{
- return uint64_to_float32(a, status);
+ return uint64_to_float32_scalbn(a, 0, status);
}
float32 uint16_to_float32(uint16_t a, float_status *status)
{
- return uint64_to_float32(a, status);
+ return uint64_to_float32_scalbn(a, 0, status);
}
-float64 uint64_to_float64(uint64_t a, float_status *status)
+float64 uint64_to_float64_scalbn(uint64_t a, int scale, float_status *status)
{
- FloatParts pa = uint_to_float(a, status);
+ FloatParts pa = uint_to_float(a, scale, status);
return float64_round_pack_canonical(pa, status);
}
+float64 uint32_to_float64_scalbn(uint32_t a, int scale, float_status *status)
+{
+ return uint64_to_float64_scalbn(a, scale, status);
+}
+
+float64 uint16_to_float64_scalbn(uint16_t a, int scale, float_status *status)
+{
+ return uint64_to_float64_scalbn(a, scale, status);
+}
+
+float64 uint64_to_float64(uint64_t a, float_status *status)
+{
+ return uint64_to_float64_scalbn(a, 0, status);
+}
+
float64 uint32_to_float64(uint32_t a, float_status *status)
{
- return uint64_to_float64(a, status);
+ return uint64_to_float64_scalbn(a, 0, status);
}
float64 uint16_to_float64(uint16_t a, float_status *status)
{
- return uint64_to_float64(a, status);
+ return uint64_to_float64_scalbn(a, 0, status);
}
/* Float Min/Max */
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 70639f656a..cbee8b944d 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -300,6 +300,28 @@ Show dynamic compiler opcode counters
ETEXI
{
+ .name = "sync-profile",
+ .args_type = "mean:-m,no_coalesce:-n,max:i?",
+ .params = "[-m] [-n] [max]",
+ .help = "show synchronization profiling info, up to max entries "
+ "(default: 10), sorted by total wait time. (-m: sort by "
+ "mean wait time; -n: do not coalesce objects with the "
+ "same call site)",
+ .cmd = hmp_info_sync_profile,
+ },
+
+STEXI
+@item info sync-profile [-m|-n] [@var{max}]
+@findex info sync-profile
+Show synchronization profiling info, up to @var{max} entries (default: 10),
+sorted by total wait time.
+ -m: sort by mean wait time
+ -n: do not coalesce objects with the same call site
+When different objects that share the same call site are coalesced, the "Object"
+field shows---enclosed in brackets---the number of objects being coalesced.
+ETEXI
+
+ {
.name = "kvm",
.args_type = "",
.params = "",
diff --git a/hmp-commands.hx b/hmp-commands.hx
index c1fc747403..db0c681f74 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -644,6 +644,21 @@ sendkey ctrl-alt-f1
This command is useful to send keys that your graphical user interface
intercepts at low level, such as @code{ctrl-alt-f1} in X Window.
ETEXI
+ {
+ .name = "sync-profile",
+ .args_type = "op:s?",
+ .params = "[on|off|reset]",
+ .help = "enable, disable or reset synchronization profiling. "
+ "With no arguments, prints whether profiling is on or off.",
+ .cmd = hmp_sync_profile,
+ },
+
+STEXI
+@item sync-profile [on|off|reset]
+@findex sync-profile
+Enable, disable or reset synchronization profiling. With no arguments, prints
+whether profiling is on or off.
+ETEXI
{
.name = "system_reset",
diff --git a/hmp.c b/hmp.c
index 9147037951..4975fa56b0 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1070,6 +1070,30 @@ void hmp_stop(Monitor *mon, const QDict *qdict)
qmp_stop(NULL);
}
+void hmp_sync_profile(Monitor *mon, const QDict *qdict)
+{
+ const char *op = qdict_get_try_str(qdict, "op");
+
+ if (op == NULL) {
+ bool on = qsp_is_enabled();
+
+ monitor_printf(mon, "sync-profile is %s\n", on ? "on" : "off");
+ return;
+ }
+ if (!strcmp(op, "on")) {
+ qsp_enable();
+ } else if (!strcmp(op, "off")) {
+ qsp_disable();
+ } else if (!strcmp(op, "reset")) {
+ qsp_reset();
+ } else {
+ Error *err = NULL;
+
+ error_setg(&err, QERR_INVALID_PARAMETER, op);
+ hmp_handle_error(mon, &err);
+ }
+}
+
void hmp_system_reset(Monitor *mon, const QDict *qdict)
{
qmp_system_reset(NULL);
diff --git a/hmp.h b/hmp.h
index 33354f1bdd..5f1addcca2 100644
--- a/hmp.h
+++ b/hmp.h
@@ -42,6 +42,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict);
void hmp_info_iothreads(Monitor *mon, const QDict *qdict);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
+void hmp_sync_profile(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
void hmp_exit_preconfig(Monitor *mon, const QDict *qdict);
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 6404af5f33..e330f24c71 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -512,7 +512,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
pci_conf[0x90] = s->smb_io_base | 1;
pci_conf[0x91] = s->smb_io_base >> 8;
pci_conf[0xd2] = 0x09;
- pm_smbus_init(DEVICE(dev), &s->smb);
+ pm_smbus_init(DEVICE(dev), &s->smb, true);
memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
memory_region_add_subregion(pci_address_space_io(dev),
s->smb_io_base, &s->smb.io);
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index ca9467e583..20c71d7d96 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -736,6 +736,17 @@ static void do_cpu_reset(void *opaque)
}
}
+ if (!env->aarch64 && !info->secure_boot &&
+ arm_feature(env, ARM_FEATURE_EL2)) {
+ /*
+ * This is an AArch32 boot not to Secure state, and
+ * we have Hyp mode available, so boot the kernel into
+ * Hyp mode. This is not how the CPU comes out of reset,
+ * so we need to manually put it there.
+ */
+ cpsr_write(env, ARM_CPU_MODE_HYP, CPSR_M, CPSRWriteRaw);
+ }
+
if (cs == first_cpu) {
AddressSpace *as = arm_boot_address_space(cpu, info);
diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c
index 258f470623..4b56bfa8d1 100644
--- a/hw/arm/fsl-imx6ul.c
+++ b/hw/arm/fsl-imx6ul.c
@@ -207,6 +207,10 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
irq = qdev_get_gpio_in(d, ARM_CPU_IRQ);
sysbus_connect_irq(sbd, i, irq);
sysbus_connect_irq(sbd, i + smp_cpus, qdev_get_gpio_in(d, ARM_CPU_FIQ));
+ sysbus_connect_irq(sbd, i + 2 * smp_cpus,
+ qdev_get_gpio_in(d, ARM_CPU_VIRQ));
+ sysbus_connect_irq(sbd, i + 3 * smp_cpus,
+ qdev_get_gpio_in(d, ARM_CPU_VFIQ));
}
/*
diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c
index d5e26855a5..7663ad6861 100644
--- a/hw/arm/fsl-imx7.c
+++ b/hw/arm/fsl-imx7.c
@@ -209,6 +209,10 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(sbd, i, irq);
irq = qdev_get_gpio_in(d, ARM_CPU_FIQ);
sysbus_connect_irq(sbd, i + smp_cpus, irq);
+ irq = qdev_get_gpio_in(d, ARM_CPU_VIRQ);
+ sysbus_connect_irq(sbd, i + 2 * smp_cpus, irq);
+ irq = qdev_get_gpio_in(d, ARM_CPU_VFIQ);
+ sysbus_connect_irq(sbd, i + 3 * smp_cpus, irq);
}
/*
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index 6d42fce2c3..fb9efa02c3 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -243,6 +243,8 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
int n;
qemu_irq cpu_irq[4];
qemu_irq cpu_fiq[4];
+ qemu_irq cpu_virq[4];
+ qemu_irq cpu_vfiq[4];
MemoryRegion *sysram;
MemoryRegion *dram;
MemoryRegion *sysmem;
@@ -282,6 +284,8 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
object_property_set_bool(cpuobj, true, "realized", &error_fatal);
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ);
+ cpu_virq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VIRQ);
+ cpu_vfiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VFIQ);
}
sysmem = get_system_memory();
@@ -329,6 +333,8 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
for (n = 0; n < smp_cpus; n++) {
sysbus_connect_irq(busdev, n, cpu_irq[n]);
sysbus_connect_irq(busdev, n + smp_cpus, cpu_fiq[n]);
+ sysbus_connect_irq(busdev, n + 2 * smp_cpus, cpu_virq[n]);
+ sysbus_connect_irq(busdev, n + 3 * smp_cpus, cpu_vfiq[n]);
}
for (n = 0; n < 128; n++) {
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
index 8cadc8b160..8742200fb4 100644
--- a/hw/arm/iotkit.c
+++ b/hw/arm/iotkit.c
@@ -16,9 +16,11 @@
#include "hw/sysbus.h"
#include "hw/registerfields.h"
#include "hw/arm/iotkit.h"
-#include "hw/misc/unimp.h"
#include "hw/arm/arm.h"
+/* Clock frequency in HZ of the 32KHz "slow clock" */
+#define S32KCLK (32 * 1000)
+
/* Create an alias region of @size bytes starting at @base
* which mirrors the memory starting at @orig.
*/
@@ -138,8 +140,23 @@ static void iotkit_init(Object *obj)
TYPE_CMSDK_APB_TIMER);
sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1),
TYPE_CMSDK_APB_TIMER);
+ sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
+ TYPE_CMSDK_APB_TIMER);
sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
- TYPE_UNIMPLEMENTED_DEVICE);
+ TYPE_CMSDK_APB_DUALTIMER);
+ sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
+ sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG);
+ sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog,
+ sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
+ sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
+ sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
+ sysbus_init_child_obj(obj, "iotkit-sysctl", &s->sysctl,
+ sizeof(s->sysctl), TYPE_IOTKIT_SYSCTL);
+ sysbus_init_child_obj(obj, "iotkit-sysinfo", &s->sysinfo,
+ sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO);
+ object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
+ sizeof(s->nmi_orgate), TYPE_OR_IRQ,
+ &error_abort, NULL);
object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ,
&error_abort, NULL);
@@ -154,8 +171,6 @@ static void iotkit_init(Object *obj)
TYPE_SPLIT_IRQ, &error_abort, NULL);
g_free(name);
}
- sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
- TYPE_UNIMPLEMENTED_DEVICE);
}
static void iotkit_exp_irq(void *opaque, int n, int level)
@@ -390,13 +405,15 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
return;
}
- qdev_prop_set_string(DEVICE(&s->dualtimer), "name", "Dual timer");
- qdev_prop_set_uint64(DEVICE(&s->dualtimer), "size", 0x1000);
+
+ qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq);
object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0,
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 5));
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0);
object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err);
if (err) {
@@ -462,13 +479,14 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
/* Devices behind APB PPC1:
* 0x4002f000: S32K timer
*/
- qdev_prop_set_string(DEVICE(&s->s32ktimer), "name", "S32KTIMER");
- qdev_prop_set_uint64(DEVICE(&s->s32ktimer), "size", 0x1000);
+ qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK);
object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0,
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 2));
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err);
if (err) {
@@ -501,19 +519,66 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in_named(dev_apb_ppc1,
"cfg_sec_resp", 0));
- /* Using create_unimplemented_device() maps the stub into the
- * system address space rather than into our container, but the
- * overall effect to the guest is the same.
- */
- create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
+ object_property_set_bool(OBJECT(&s->sysinfo), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ /* System information registers */
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000);
+ /* System control registers */
+ object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50021000);
- create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
- create_unimplemented_device("S32KWATCHDOG", 0x5002e000, 0x1000);
+ /* This OR gate wires together outputs from the secure watchdogs to NMI */
+ object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
+
+ qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK);
+ object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0,
+ qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 0));
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 0x5002e000);
/* 0x40080000 .. 0x4008ffff : IoTKit second Base peripheral region */
- create_unimplemented_device("NS watchdog", 0x40081000, 0x1000);
- create_unimplemented_device("S watchdog", 0x50081000, 0x1000);
+ qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq);
+ object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0,
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 1));
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000);
+
+ qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq);
+ object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0,
+ qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 1));
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->swatchdog), 0, 0x50081000);
for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
@@ -602,6 +667,21 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
iotkit_forward_sec_resp_cfg(s);
+ /* Forward the MSC related signals */
+ qdev_pass_gpios(dev_secctl, dev, "mscexp_status");
+ qdev_pass_gpios(dev_secctl, dev, "mscexp_clear");
+ qdev_pass_gpios(dev_secctl, dev, "mscexp_ns");
+ qdev_connect_gpio_out_named(dev_secctl, "msc_irq", 0,
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 11));
+
+ /*
+ * Expose our container region to the board model; this corresponds
+ * to the AHB Slave Expansion ports which allow bus master devices
+ * (eg DMA controllers) in the board model to make transactions into
+ * devices in the IoTKit.
+ */
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
+
system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
}
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index dc0f34abe5..6dd02ae47e 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -45,7 +45,10 @@
#include "hw/misc/mps2-scc.h"
#include "hw/misc/mps2-fpgaio.h"
#include "hw/misc/tz-mpc.h"
+#include "hw/misc/tz-msc.h"
#include "hw/arm/iotkit.h"
+#include "hw/dma/pl080.h"
+#include "hw/ssi/pl022.h"
#include "hw/devices.h"
#include "net/net.h"
#include "hw/core/split-irq.h"
@@ -71,12 +74,13 @@ typedef struct {
MPS2FPGAIO fpgaio;
TZPPC ppc[5];
TZMPC ssram_mpc[3];
- UnimplementedDeviceState spi[5];
+ PL022State spi[5];
UnimplementedDeviceState i2c[4];
UnimplementedDeviceState i2s_audio;
UnimplementedDeviceState gpio[4];
- UnimplementedDeviceState dma[4];
UnimplementedDeviceState gfx;
+ PL080State dma[4];
+ TZMSC msc[4];
CMSDKAPBUART uart[5];
SplitIRQ sec_resp_splitter;
qemu_or_irq uart_irq_orgate;
@@ -188,7 +192,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
sccdev = DEVICE(scc);
qdev_set_parent_bus(sccdev, sysbus_get_default());
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
- qdev_prop_set_uint32(sccdev, "scc-aid", 0x02000008);
+ qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
object_property_set_bool(OBJECT(scc), true, "realized", &error_fatal);
return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0);
@@ -263,6 +267,89 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
}
+static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ PL080State *dma = opaque;
+ int i = dma - &mms->dma[0];
+ SysBusDevice *s;
+ char *mscname = g_strdup_printf("%s-msc", name);
+ TZMSC *msc = &mms->msc[i];
+ DeviceState *iotkitdev = DEVICE(&mms->iotkit);
+ MemoryRegion *msc_upstream;
+ MemoryRegion *msc_downstream;
+
+ /*
+ * Each DMA device is a PL081 whose transaction master interface
+ * is guarded by a Master Security Controller. The downstream end of
+ * the MSC connects to the IoTKit AHB Slave Expansion port, so the
+ * DMA devices can see all devices and memory that the CPU does.
+ */
+ sysbus_init_child_obj(OBJECT(mms), mscname, msc, sizeof(*msc), TYPE_TZ_MSC);
+ msc_downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(&mms->iotkit), 0);
+ object_property_set_link(OBJECT(msc), OBJECT(msc_downstream),
+ "downstream", &error_fatal);
+ object_property_set_link(OBJECT(msc), OBJECT(mms),
+ "idau", &error_fatal);
+ object_property_set_bool(OBJECT(msc), true, "realized", &error_fatal);
+
+ qdev_connect_gpio_out_named(DEVICE(msc), "irq", 0,
+ qdev_get_gpio_in_named(iotkitdev,
+ "mscexp_status", i));
+ qdev_connect_gpio_out_named(iotkitdev, "mscexp_clear", i,
+ qdev_get_gpio_in_named(DEVICE(msc),
+ "irq_clear", 0));
+ qdev_connect_gpio_out_named(iotkitdev, "mscexp_ns", i,
+ qdev_get_gpio_in_named(DEVICE(msc),
+ "cfg_nonsec", 0));
+ qdev_connect_gpio_out(DEVICE(&mms->sec_resp_splitter),
+ ARRAY_SIZE(mms->ppc) + i,
+ qdev_get_gpio_in_named(DEVICE(msc),
+ "cfg_sec_resp", 0));
+ msc_upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(msc), 0);
+
+ sysbus_init_child_obj(OBJECT(mms), name, dma, sizeof(*dma), TYPE_PL081);
+ object_property_set_link(OBJECT(dma), OBJECT(msc_upstream),
+ "downstream", &error_fatal);
+ object_property_set_bool(OBJECT(dma), true, "realized", &error_fatal);
+
+ s = SYS_BUS_DEVICE(dma);
+ /* Wire up DMACINTR, DMACINTERR, DMACINTTC */
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev,
+ "EXP_IRQ", 58 + i * 3));
+ sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev,
+ "EXP_IRQ", 56 + i * 3));
+ sysbus_connect_irq(s, 2, qdev_get_gpio_in_named(iotkitdev,
+ "EXP_IRQ", 57 + i * 3));
+
+ return sysbus_mmio_get_region(s, 0);
+}
+
+static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ /*
+ * The AN505 has five PL022 SPI controllers.
+ * One of these should have the LCD controller behind it; the others
+ * are connected only to the FPGA's "general purpose SPI connector"
+ * or "shield" expansion connectors.
+ * Note that if we do implement devices behind SPI, the chip select
+ * lines are set via the "MISC" register in the MPS2 FPGAIO device.
+ */
+ PL022State *spi = opaque;
+ int i = spi - &mms->spi[0];
+ DeviceState *iotkitdev = DEVICE(&mms->iotkit);
+ SysBusDevice *s;
+
+ sysbus_init_child_obj(OBJECT(mms), name, spi, sizeof(mms->spi[0]),
+ TYPE_PL022);
+ object_property_set_bool(OBJECT(spi), true, "realized", &error_fatal);
+ s = SYS_BUS_DEVICE(spi);
+ sysbus_connect_irq(s, 0,
+ qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 51 + i));
+ return sysbus_mmio_get_region(s, 0);
+}
+
static void mps2tz_common_init(MachineState *machine)
{
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
@@ -289,13 +376,14 @@ static void mps2tz_common_init(MachineState *machine)
&error_fatal);
/* The sec_resp_cfg output from the IoTKit must be split into multiple
- * lines, one for each of the PPCs we create here.
+ * lines, one for each of the PPCs we create here, plus one per MSC.
*/
object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
TYPE_SPLIT_IRQ);
object_property_add_child(OBJECT(machine), "sec-resp-splitter",
OBJECT(&mms->sec_resp_splitter), &error_abort);
- object_property_set_int(OBJECT(&mms->sec_resp_splitter), 5,
+ object_property_set_int(OBJECT(&mms->sec_resp_splitter),
+ ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc),
"num-lines", &error_fatal);
object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
"realized", &error_fatal);
@@ -360,11 +448,11 @@ static void mps2tz_common_init(MachineState *machine)
}, {
.name = "apb_ppcexp1",
.ports = {
- { "spi0", make_unimp_dev, &mms->spi[0], 0x40205000, 0x1000 },
- { "spi1", make_unimp_dev, &mms->spi[1], 0x40206000, 0x1000 },
- { "spi2", make_unimp_dev, &mms->spi[2], 0x40209000, 0x1000 },
- { "spi3", make_unimp_dev, &mms->spi[3], 0x4020a000, 0x1000 },
- { "spi4", make_unimp_dev, &mms->spi[4], 0x4020b000, 0x1000 },
+ { "spi0", make_spi, &mms->spi[0], 0x40205000, 0x1000 },
+ { "spi1", make_spi, &mms->spi[1], 0x40206000, 0x1000 },
+ { "spi2", make_spi, &mms->spi[2], 0x40209000, 0x1000 },
+ { "spi3", make_spi, &mms->spi[3], 0x4020a000, 0x1000 },
+ { "spi4", make_spi, &mms->spi[4], 0x4020b000, 0x1000 },
{ "uart0", make_uart, &mms->uart[0], 0x40200000, 0x1000 },
{ "uart1", make_uart, &mms->uart[1], 0x40201000, 0x1000 },
{ "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 },
@@ -396,10 +484,10 @@ static void mps2tz_common_init(MachineState *machine)
}, {
.name = "ahb_ppcexp1",
.ports = {
- { "dma0", make_unimp_dev, &mms->dma[0], 0x40110000, 0x1000 },
- { "dma1", make_unimp_dev, &mms->dma[1], 0x40111000, 0x1000 },
- { "dma2", make_unimp_dev, &mms->dma[2], 0x40112000, 0x1000 },
- { "dma3", make_unimp_dev, &mms->dma[3], 0x40113000, 0x1000 },
+ { "dma0", make_dma, &mms->dma[0], 0x40110000, 0x1000 },
+ { "dma1", make_dma, &mms->dma[1], 0x40111000, 0x1000 },
+ { "dma2", make_dma, &mms->dma[2], 0x40112000, 0x1000 },
+ { "dma3", make_dma, &mms->dma[3], 0x40113000, 0x1000 },
},
},
};
@@ -480,12 +568,32 @@ static void mps2tz_common_init(MachineState *machine)
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x400000);
}
+static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
+ int *iregion, bool *exempt, bool *ns, bool *nsc)
+{
+ /*
+ * The MPS2 TZ FPGA images have IDAUs in them which are connected to
+ * the Master Security Controllers. Thes have the same logic as
+ * is used by the IoTKit for the IDAU connected to the CPU, except
+ * that MSCs don't care about the NSC attribute.
+ */
+ int region = extract32(address, 28, 4);
+
+ *ns = !(region & 1);
+ *nsc = false;
+ /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */
+ *exempt = (address & 0xeff00000) == 0xe0000000;
+ *iregion = region;
+}
+
static void mps2tz_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
mc->init = mps2tz_common_init;
mc->max_cpus = 1;
+ iic->check = mps2_tz_idau_check;
}
static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
@@ -496,7 +604,7 @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM MPS2 with AN505 FPGA image for Cortex-M33";
mmc->fpga_type = FPGA_AN505;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
- mmc->scc_id = 0x41040000 | (505 << 4);
+ mmc->scc_id = 0x41045050;
}
static const TypeInfo mps2tz_info = {
@@ -506,6 +614,10 @@ static const TypeInfo mps2tz_info = {
.instance_size = sizeof(MPS2TZMachineState),
.class_size = sizeof(MPS2TZMachineClass),
.class_init = mps2tz_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_IDAU_INTERFACE },
+ { }
+ },
};
static const TypeInfo mps2tz_an505_info = {
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
index 0a0ae867d9..e3d698ba6c 100644
--- a/hw/arm/mps2.c
+++ b/hw/arm/mps2.c
@@ -34,6 +34,7 @@
#include "hw/misc/unimp.h"
#include "hw/char/cmsdk-apb-uart.h"
#include "hw/timer/cmsdk-apb-timer.h"
+#include "hw/timer/cmsdk-apb-dualtimer.h"
#include "hw/misc/mps2-scc.h"
#include "hw/devices.h"
#include "net/net.h"
@@ -64,6 +65,7 @@ typedef struct {
MemoryRegion blockram_m3;
MemoryRegion sram;
MPS2SCC scc;
+ CMSDKAPBDualTimer dualtimer;
} MPS2MachineState;
#define TYPE_MPS2_MACHINE "mps2"
@@ -297,11 +299,20 @@ static void mps2_common_init(MachineState *machine)
cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ);
cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ);
+ sysbus_init_child_obj(OBJECT(mms), "dualtimer", &mms->dualtimer,
+ sizeof(mms->dualtimer), TYPE_CMSDK_APB_DUALTIMER);
+ qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ);
+ object_property_set_bool(OBJECT(&mms->dualtimer), true, "realized",
+ &error_fatal);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0,
+ qdev_get_gpio_in(armv7m, 10));
+ sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000);
+
object_initialize(&mms->scc, sizeof(mms->scc), TYPE_MPS2_SCC);
sccdev = DEVICE(&mms->scc);
qdev_set_parent_bus(sccdev, sysbus_get_default());
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
- qdev_prop_set_uint32(sccdev, "scc-aid", 0x02000008);
+ qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
object_property_set_bool(OBJECT(&mms->scc), true, "realized",
&error_fatal);
@@ -336,7 +347,7 @@ static void mps2_an385_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM MPS2 with AN385 FPGA image for Cortex-M3";
mmc->fpga_type = FPGA_AN385;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
- mmc->scc_id = 0x41040000 | (385 << 4);
+ mmc->scc_id = 0x41043850;
}
static void mps2_an511_class_init(ObjectClass *oc, void *data)
@@ -347,7 +358,7 @@ static void mps2_an511_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3";
mmc->fpga_type = FPGA_AN511;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
- mmc->scc_id = 0x4104000 | (511 << 4);
+ mmc->scc_id = 0x41045110;
}
static const TypeInfo mps2_info = {
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index b67b0cefb6..f598a1c053 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -409,7 +409,7 @@ static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr,
case MDCNFG ... SA1110:
if ((addr & 3) == 0)
return s->mm_regs[addr >> 2];
-
+ /* fall through */
default:
printf("%s: Bad register " REG_FMT "\n", __func__, addr);
break;
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 5bfe2e4348..c02d18ee61 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -172,6 +172,7 @@ typedef struct {
typedef struct {
MachineState parent;
bool secure;
+ bool virt;
} VexpressMachineState;
#define TYPE_VEXPRESS_MACHINE "vexpress"
@@ -203,7 +204,7 @@ struct VEDBoardInfo {
};
static void init_cpus(const char *cpu_type, const char *privdev,
- hwaddr periphbase, qemu_irq *pic, bool secure)
+ hwaddr periphbase, qemu_irq *pic, bool secure, bool virt)
{
DeviceState *dev;
SysBusDevice *busdev;
@@ -216,6 +217,11 @@ static void init_cpus(const char *cpu_type, const char *privdev,
if (!secure) {
object_property_set_bool(cpuobj, false, "has_el3", NULL);
}
+ if (!virt) {
+ if (object_property_find(cpuobj, "has_el2", NULL)) {
+ object_property_set_bool(cpuobj, false, "has_el2", NULL);
+ }
+ }
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
object_property_set_int(cpuobj, periphbase,
@@ -251,6 +257,10 @@ static void init_cpus(const char *cpu_type, const char *privdev,
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
sysbus_connect_irq(busdev, n + smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+ sysbus_connect_irq(busdev, n + 2 * smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
+ sysbus_connect_irq(busdev, n + 3 * smp_cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
}
@@ -285,7 +295,8 @@ static void a9_daughterboard_init(const VexpressMachineState *vms,
memory_region_add_subregion(sysmem, 0x60000000, ram);
/* 0x1e000000 A9MPCore (SCU) private memory region */
- init_cpus(cpu_type, TYPE_A9MPCORE_PRIV, 0x1e000000, pic, vms->secure);
+ init_cpus(cpu_type, TYPE_A9MPCORE_PRIV, 0x1e000000, pic,
+ vms->secure, vms->virt);
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
@@ -366,7 +377,8 @@ static void a15_daughterboard_init(const VexpressMachineState *vms,
memory_region_add_subregion(sysmem, 0x80000000, ram);
/* 0x2c000000 A15MPCore private memory region (GIC) */
- init_cpus(cpu_type, TYPE_A15MPCORE_PRIV, 0x2c000000, pic, vms->secure);
+ init_cpus(cpu_type, TYPE_A15MPCORE_PRIV, 0x2c000000, pic, vms->secure,
+ vms->virt);
/* A15 daughterboard peripherals: */
@@ -701,8 +713,8 @@ static void vexpress_common_init(MachineState *machine)
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
- /* Indicate that when booting Linux we should be in secure state */
- daughterboard->bootinfo.secure_boot = true;
+ /* When booting Linux we should be in secure state if the CPU has one. */
+ daughterboard->bootinfo.secure_boot = vms->secure;
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
}
@@ -720,6 +732,20 @@ static void vexpress_set_secure(Object *obj, bool value, Error **errp)
vms->secure = value;
}
+static bool vexpress_get_virt(Object *obj, Error **errp)
+{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ return vms->virt;
+}
+
+static void vexpress_set_virt(Object *obj, bool value, Error **errp)
+{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ vms->virt = value;
+}
+
static void vexpress_instance_init(Object *obj)
{
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
@@ -734,6 +760,32 @@ static void vexpress_instance_init(Object *obj)
NULL);
}
+static void vexpress_a15_instance_init(Object *obj)
+{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ /*
+ * For the vexpress-a15, EL2 is by default enabled if EL3 is,
+ * but can also be specifically set to on or off.
+ */
+ vms->virt = true;
+ object_property_add_bool(obj, "virtualization", vexpress_get_virt,
+ vexpress_set_virt, NULL);
+ object_property_set_description(obj, "virtualization",
+ "Set on/off to enable/disable the ARM "
+ "Virtualization Extensions "
+ "(defaults to same as 'secure')",
+ NULL);
+}
+
+static void vexpress_a9_instance_init(Object *obj)
+{
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
+
+ /* The A9 doesn't have the virt extensions */
+ vms->virt = false;
+}
+
static void vexpress_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -780,12 +832,14 @@ static const TypeInfo vexpress_a9_info = {
.name = TYPE_VEXPRESS_A9_MACHINE,
.parent = TYPE_VEXPRESS_MACHINE,
.class_init = vexpress_a9_class_init,
+ .instance_init = vexpress_a9_instance_init,
};
static const TypeInfo vexpress_a15_info = {
.name = TYPE_VEXPRESS_A15_MACHINE,
.parent = TYPE_VEXPRESS_MACHINE,
.class_init = vexpress_a15_class_init,
+ .instance_init = vexpress_a15_instance_init,
};
static void vexpress_machine_init(void)
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
index aaebec1839..9089dcb47e 100644
--- a/hw/audio/cs4231a.c
+++ b/hw/audio/cs4231a.c
@@ -305,6 +305,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)
case 6:
as.endianness = 1;
+ /* fall through */
case 2:
as.fmt = AUD_FMT_S16;
s->shift = as.nchannels;
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 59cf252754..dd75c9e8f5 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -474,82 +474,7 @@ static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
return addr;
}
-static void es1370_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- ES1370State *s = opaque;
- uint32_t shift, mask;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_CONTROL:
- case ES1370_REG_CONTROL + 1:
- case ES1370_REG_CONTROL + 2:
- case ES1370_REG_CONTROL + 3:
- shift = (addr - ES1370_REG_CONTROL) << 3;
- mask = 0xff << shift;
- val = (s->ctl & ~mask) | ((val & 0xff) << shift);
- es1370_update_voices (s, val, s->sctl);
- print_ctl (val);
- break;
- case ES1370_REG_MEMPAGE:
- s->mempage = val;
- break;
- case ES1370_REG_SERIAL_CONTROL:
- case ES1370_REG_SERIAL_CONTROL + 1:
- case ES1370_REG_SERIAL_CONTROL + 2:
- case ES1370_REG_SERIAL_CONTROL + 3:
- shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3;
- mask = 0xff << shift;
- val = (s->sctl & ~mask) | ((val & 0xff) << shift);
- es1370_maybe_lower_irq (s, val);
- es1370_update_voices (s, s->ctl, val);
- print_sctl (val);
- break;
- default:
- lwarn ("writeb %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-static void es1370_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- ES1370State *s = opaque;
- addr = es1370_fixup (s, addr);
- uint32_t shift, mask;
- struct chan *d = &s->chan[0];
-
- switch (addr) {
- case ES1370_REG_CODEC:
- dolog ("ignored codec write address %#x, data %#x\n",
- (val >> 8) & 0xff, val & 0xff);
- s->codec = val;
- break;
-
- case ES1370_REG_CONTROL:
- case ES1370_REG_CONTROL + 2:
- shift = (addr != ES1370_REG_CONTROL) << 4;
- mask = 0xffff << shift;
- val = (s->ctl & ~mask) | ((val & 0xffff) << shift);
- es1370_update_voices (s, val, s->sctl);
- print_ctl (val);
- break;
-
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
- case ES1370_REG_DAC1_SCOUNT:
- d->scount = (d->scount & ~0xffff) | (val & 0xffff);
- break;
-
- default:
- lwarn ("writew %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
+static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
ES1370State *s = opaque;
struct chan *d = &s->chan[0];
@@ -572,21 +497,19 @@ static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
print_sctl (val);
break;
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
case ES1370_REG_DAC1_SCOUNT:
+ case ES1370_REG_DAC2_SCOUNT:
+ case ES1370_REG_ADC_SCOUNT:
+ d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
d->scount = (val & 0xffff) | (d->scount & ~0xffff);
ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
d - &s->chan[0], val >> 16, (val & 0xffff));
break;
- case ES1370_REG_ADC_FRAMEADR:
- d++;
- case ES1370_REG_DAC2_FRAMEADR:
- d++;
case ES1370_REG_DAC1_FRAMEADR:
+ case ES1370_REG_DAC2_FRAMEADR:
+ case ES1370_REG_ADC_FRAMEADR:
+ d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
d->frame_addr = val;
ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
break;
@@ -598,11 +521,10 @@ static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
lwarn ("writing to phantom frame address %#x\n", val);
break;
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
case ES1370_REG_DAC1_FRAMECNT:
+ case ES1370_REG_DAC2_FRAMECNT:
+ case ES1370_REG_ADC_FRAMECNT:
+ d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
d->frame_cnt = val;
d->leftover = 0;
ldebug ("chan %td frame count %d, buffer size %d\n",
@@ -615,84 +537,7 @@ static void es1370_writel(void *opaque, uint32_t addr, uint32_t val)
}
}
-static uint32_t es1370_readb(void *opaque, uint32_t addr)
-{
- ES1370State *s = opaque;
- uint32_t val;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case 0x1b: /* Legacy */
- lwarn ("Attempt to read from legacy register\n");
- val = 5;
- break;
- case ES1370_REG_MEMPAGE:
- val = s->mempage;
- break;
- case ES1370_REG_CONTROL + 0:
- case ES1370_REG_CONTROL + 1:
- case ES1370_REG_CONTROL + 2:
- case ES1370_REG_CONTROL + 3:
- val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3);
- break;
- case ES1370_REG_STATUS + 0:
- case ES1370_REG_STATUS + 1:
- case ES1370_REG_STATUS + 2:
- case ES1370_REG_STATUS + 3:
- val = s->status >> ((addr - ES1370_REG_STATUS) << 3);
- break;
- default:
- val = ~0;
- lwarn ("readb %#x -> %#x\n", addr, val);
- break;
- }
- return val;
-}
-
-static uint32_t es1370_readw(void *opaque, uint32_t addr)
-{
- ES1370State *s = opaque;
- struct chan *d = &s->chan[0];
- uint32_t val;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_ADC_SCOUNT + 2:
- d++;
- case ES1370_REG_DAC2_SCOUNT + 2:
- d++;
- case ES1370_REG_DAC1_SCOUNT + 2:
- val = d->scount >> 16;
- break;
-
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
- case ES1370_REG_DAC1_FRAMECNT:
- val = d->frame_cnt & 0xffff;
- break;
-
- case ES1370_REG_ADC_FRAMECNT + 2:
- d++;
- case ES1370_REG_DAC2_FRAMECNT + 2:
- d++;
- case ES1370_REG_DAC1_FRAMECNT + 2:
- val = d->frame_cnt >> 16;
- break;
-
- default:
- val = ~0;
- lwarn ("readw %#x -> %#x\n", addr, val);
- break;
- }
-
- return val;
-}
-
-static uint32_t es1370_readl(void *opaque, uint32_t addr)
+static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size)
{
ES1370State *s = opaque;
uint32_t val;
@@ -717,11 +562,10 @@ static uint32_t es1370_readl(void *opaque, uint32_t addr)
val = s->sctl;
break;
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
case ES1370_REG_DAC1_SCOUNT:
+ case ES1370_REG_DAC2_SCOUNT:
+ case ES1370_REG_ADC_SCOUNT:
+ d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
val = d->scount;
#ifdef DEBUG_ES1370
{
@@ -735,11 +579,10 @@ static uint32_t es1370_readl(void *opaque, uint32_t addr)
#endif
break;
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
case ES1370_REG_DAC1_FRAMECNT:
+ case ES1370_REG_DAC2_FRAMECNT:
+ case ES1370_REG_ADC_FRAMECNT:
+ d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
val = d->frame_cnt;
#ifdef DEBUG_ES1370
{
@@ -753,11 +596,10 @@ static uint32_t es1370_readl(void *opaque, uint32_t addr)
#endif
break;
- case ES1370_REG_ADC_FRAMEADR:
- d++;
- case ES1370_REG_DAC2_FRAMEADR:
- d++;
case ES1370_REG_DAC1_FRAMEADR:
+ case ES1370_REG_DAC2_FRAMEADR:
+ case ES1370_REG_ADC_FRAMEADR:
+ d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
val = d->frame_addr;
break;
@@ -908,44 +750,17 @@ static void es1370_adc_callback (void *opaque, int avail)
es1370_run_channel (s, ADC_CHANNEL, avail);
}
-static uint64_t es1370_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return es1370_readb(opaque, addr);
- case 2:
- return es1370_readw(opaque, addr);
- case 4:
- return es1370_readl(opaque, addr);
- default:
- return -1;
- }
-}
-
-static void es1370_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned size)
-{
- switch (size) {
- case 1:
- es1370_writeb(opaque, addr, val);
- break;
- case 2:
- es1370_writew(opaque, addr, val);
- break;
- case 4:
- es1370_writel(opaque, addr, val);
- break;
- }
-}
-
static const MemoryRegionOps es1370_io_ops = {
.read = es1370_read,
.write = es1370_write,
- .impl = {
+ .valid = {
.min_access_size = 1,
.max_access_size = 4,
},
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
.endianness = DEVICE_LITTLE_ENDIAN,
};
diff --git a/hw/audio/gusemu_hal.c b/hw/audio/gusemu_hal.c
index 1150fc4426..ae40ca341c 100644
--- a/hw/audio/gusemu_hal.c
+++ b/hw/audio/gusemu_hal.c
@@ -261,6 +261,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
GUSregb(IRQStatReg2x6) = 0x10;
GUS_irqrequest(state, state->gusirq, 1);
}
+ /* fall through */
case 0x20D: /* SB2xCd no IRQ */
GUSregb(SB2xCd) = (uint8_t) data;
break;
diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c
index 5a4d32364e..c5b9bf79e8 100644
--- a/hw/audio/sb16.c
+++ b/hw/audio/sb16.c
@@ -741,10 +741,15 @@ static void complete (SB16State *s)
ldebug ("set time const %d\n", s->time_const);
break;
- case 0x42: /* FT2 sets output freq with this, go figure */
- qemu_log_mask(LOG_UNIMP, "cmd 0x42 might not do what it think it"
- " should\n");
case 0x41:
+ case 0x42:
+ /*
+ * 0x41 is documented as setting the output sample rate,
+ * and 0x42 the input sample rate, but in fact SB16 hardware
+ * seems to have only a single sample rate under the hood,
+ * and FT2 sets output freq with this (go figure). Compare:
+ * http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.html#SamplingRate
+ */
s->freq = dsp_get_hilo (s);
ldebug ("set freq %d\n", s->freq);
break;
diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
index 43c1079493..5649843cd8 100644
--- a/hw/cpu/a15mpcore.c
+++ b/hw/cpu/a15mpcore.c
@@ -53,6 +53,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
int i;
Error *err = NULL;
bool has_el3;
+ bool has_el2 = false;
Object *cpuobj;
gicdev = DEVICE(&s->gic);
@@ -67,6 +68,10 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
object_property_get_bool(cpuobj, "has_el3", &error_abort);
qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
+ /* Similarly for virtualization support */
+ has_el2 = object_property_find(cpuobj, "has_el2", NULL) &&
+ object_property_get_bool(cpuobj, "has_el2", &error_abort);
+ qdev_prop_set_bit(gicdev, "has-virtualization-extensions", has_el2);
}
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
@@ -103,20 +108,40 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev,
ppibase + timer_irq[irq]));
}
+ if (has_el2) {
+ /* Connect the GIC maintenance interrupt to PPI ID 25 */
+ sysbus_connect_irq(SYS_BUS_DEVICE(gicdev), i + 4 * s->num_cpu,
+ qdev_get_gpio_in(gicdev, ppibase + 25));
+ }
}
/* Memory map (addresses are offsets from PERIPHBASE):
* 0x0000-0x0fff -- reserved
* 0x1000-0x1fff -- GIC Distributor
* 0x2000-0x3fff -- GIC CPU interface
- * 0x4000-0x4fff -- GIC virtual interface control (not modelled)
- * 0x5000-0x5fff -- GIC virtual interface control (not modelled)
- * 0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
+ * 0x4000-0x4fff -- GIC virtual interface control for this CPU
+ * 0x5000-0x51ff -- GIC virtual interface control for CPU 0
+ * 0x5200-0x53ff -- GIC virtual interface control for CPU 1
+ * 0x5400-0x55ff -- GIC virtual interface control for CPU 2
+ * 0x5600-0x57ff -- GIC virtual interface control for CPU 3
+ * 0x6000-0x7fff -- GIC virtual CPU interface
*/
memory_region_add_subregion(&s->container, 0x1000,
sysbus_mmio_get_region(busdev, 0));
memory_region_add_subregion(&s->container, 0x2000,
sysbus_mmio_get_region(busdev, 1));
+ if (has_el2) {
+ memory_region_add_subregion(&s->container, 0x4000,
+ sysbus_mmio_get_region(busdev, 2));
+ memory_region_add_subregion(&s->container, 0x6000,
+ sysbus_mmio_get_region(busdev, 3));
+ for (i = 0; i < s->num_cpu; i++) {
+ hwaddr base = 0x5000 + i * 0x200;
+ MemoryRegion *mr = sysbus_mmio_get_region(busdev,
+ 4 + s->num_cpu + i);
+ memory_region_add_subregion(&s->container, base, mr);
+ }
+ }
}
static Property a15mp_priv_properties[] = {
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index 3355f4c131..d534d00a65 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -34,6 +34,13 @@
#define DEFAULT_VCRAM_SIZE 0x4000000
#define BCM2835_FB_OFFSET 0x00100000
+/* Maximum permitted framebuffer size; experimentally determined on an rpi2 */
+#define XRES_MAX 3840
+#define YRES_MAX 2560
+/* Framebuffer size used if guest requests zero size */
+#define XRES_SMALL 592
+#define YRES_SMALL 488
+
static void fb_invalidate_display(void *opaque)
{
BCM2835FBState *s = BCM2835_FB(opaque);
@@ -52,7 +59,7 @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
int bpp = surface_bits_per_pixel(surface);
while (width--) {
- switch (s->bpp) {
+ switch (s->config.bpp) {
case 8:
/* lookup palette starting at video ram base
* TODO: cache translation, rather than doing this each time!
@@ -91,7 +98,7 @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
break;
}
- if (s->pixo == 0) {
+ if (s->config.pixo == 0) {
/* swap to BGR pixel format */
uint8_t tmp = r;
r = b;
@@ -126,6 +133,18 @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
}
}
+static bool fb_use_offsets(BCM2835FBConfig *config)
+{
+ /*
+ * Return true if we should use the viewport offsets.
+ * Experimentally, the hardware seems to do this only if the
+ * viewport size is larger than the physical screen. (It doesn't
+ * prevent the guest setting this silly viewport setting, though...)
+ */
+ return config->xres_virtual > config->xres &&
+ config->yres_virtual > config->yres;
+}
+
static void fb_update_display(void *opaque)
{
BCM2835FBState *s = opaque;
@@ -134,13 +153,19 @@ static void fb_update_display(void *opaque)
int last = 0;
int src_width = 0;
int dest_width = 0;
+ uint32_t xoff = 0, yoff = 0;
- if (s->lock || !s->xres) {
+ if (s->lock || !s->config.xres) {
return;
}
- src_width = s->xres * (s->bpp >> 3);
- dest_width = s->xres;
+ src_width = bcm2835_fb_get_pitch(&s->config);
+ if (fb_use_offsets(&s->config)) {
+ xoff = s->config.xoffset;
+ yoff = s->config.yoffset;
+ }
+
+ dest_width = s->config.xres;
switch (surface_bits_per_pixel(surface)) {
case 0:
@@ -165,89 +190,104 @@ static void fb_update_display(void *opaque)
}
if (s->invalidate) {
- framebuffer_update_memory_section(&s->fbsection, s->dma_mr, s->base,
- s->yres, src_width);
+ hwaddr base = s->config.base + xoff + yoff * src_width;
+ framebuffer_update_memory_section(&s->fbsection, s->dma_mr,
+ base,
+ s->config.yres, src_width);
}
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
+ framebuffer_update_display(surface, &s->fbsection,
+ s->config.xres, s->config.yres,
src_width, dest_width, 0, s->invalidate,
draw_line_src16, s, &first, &last);
if (first >= 0) {
- dpy_gfx_update(s->con, 0, first, s->xres, last - first + 1);
+ dpy_gfx_update(s->con, 0, first, s->config.xres,
+ last - first + 1);
}
s->invalidate = false;
}
-static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
+void bcm2835_fb_validate_config(BCM2835FBConfig *config)
{
- value &= ~0xf;
-
- s->lock = true;
-
- s->xres = ldl_le_phys(&s->dma_as, value);
- s->yres = ldl_le_phys(&s->dma_as, value + 4);
- s->xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
- s->yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
- s->bpp = ldl_le_phys(&s->dma_as, value + 20);
- s->xoffset = ldl_le_phys(&s->dma_as, value + 24);
- s->yoffset = ldl_le_phys(&s->dma_as, value + 28);
-
- s->base = s->vcram_base | (value & 0xc0000000);
- s->base += BCM2835_FB_OFFSET;
+ /*
+ * Validate the config, and clip any bogus values into range,
+ * as the hardware does. Note that fb_update_display() relies on
+ * this happening to prevent it from performing out-of-range
+ * accesses on redraw.
+ */
+ config->xres = MIN(config->xres, XRES_MAX);
+ config->xres_virtual = MIN(config->xres_virtual, XRES_MAX);
+ config->yres = MIN(config->yres, YRES_MAX);
+ config->yres_virtual = MIN(config->yres_virtual, YRES_MAX);
+
+ /*
+ * These are not minima: a 40x40 framebuffer will be accepted.
+ * They're only used as defaults if the guest asks for zero size.
+ */
+ if (config->xres == 0) {
+ config->xres = XRES_SMALL;
+ }
+ if (config->yres == 0) {
+ config->yres = YRES_SMALL;
+ }
+ if (config->xres_virtual == 0) {
+ config->xres_virtual = config->xres;
+ }
+ if (config->yres_virtual == 0) {
+ config->yres_virtual = config->yres;
+ }
- /* TODO - Manage properly virtual resolution */
+ if (fb_use_offsets(config)) {
+ /* Clip the offsets so the viewport is within the physical screen */
+ config->xoffset = MIN(config->xoffset,
+ config->xres_virtual - config->xres);
+ config->yoffset = MIN(config->yoffset,
+ config->yres_virtual - config->yres);
+ }
+}
- s->pitch = s->xres * (s->bpp >> 3);
- s->size = s->yres * s->pitch;
+void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
+{
+ s->lock = true;
- stl_le_phys(&s->dma_as, value + 16, s->pitch);
- stl_le_phys(&s->dma_as, value + 32, s->base);
- stl_le_phys(&s->dma_as, value + 36, s->size);
+ s->config = *newconfig;
s->invalidate = true;
- qemu_console_resize(s->con, s->xres, s->yres);
+ qemu_console_resize(s->con, s->config.xres, s->config.yres);
s->lock = false;
}
-void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
- uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
- uint32_t *pixo, uint32_t *alpha)
+static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
{
- s->lock = true;
+ uint32_t pitch;
+ uint32_t size;
+ BCM2835FBConfig newconf;
- /* TODO: input validation! */
- if (xres) {
- s->xres = *xres;
- }
- if (yres) {
- s->yres = *yres;
- }
- if (xoffset) {
- s->xoffset = *xoffset;
- }
- if (yoffset) {
- s->yoffset = *yoffset;
- }
- if (bpp) {
- s->bpp = *bpp;
- }
- if (pixo) {
- s->pixo = *pixo;
- }
- if (alpha) {
- s->alpha = *alpha;
- }
+ value &= ~0xf;
- /* TODO - Manage properly virtual resolution */
+ newconf.xres = ldl_le_phys(&s->dma_as, value);
+ newconf.yres = ldl_le_phys(&s->dma_as, value + 4);
+ newconf.xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
+ newconf.yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
+ newconf.bpp = ldl_le_phys(&s->dma_as, value + 20);
+ newconf.xoffset = ldl_le_phys(&s->dma_as, value + 24);
+ newconf.yoffset = ldl_le_phys(&s->dma_as, value + 28);
- s->pitch = s->xres * (s->bpp >> 3);
- s->size = s->yres * s->pitch;
+ newconf.base = s->vcram_base | (value & 0xc0000000);
+ newconf.base += BCM2835_FB_OFFSET;
- s->invalidate = true;
- qemu_console_resize(s->con, s->xres, s->yres);
- s->lock = false;
+ bcm2835_fb_validate_config(&newconf);
+
+ pitch = bcm2835_fb_get_pitch(&newconf);
+ size = bcm2835_fb_get_size(&newconf);
+
+ stl_le_phys(&s->dma_as, value + 16, pitch);
+ stl_le_phys(&s->dma_as, value + 32, newconf.base);
+ stl_le_phys(&s->dma_as, value + 36, size);
+
+ bcm2835_fb_reconfigure(s, &newconf);
}
static uint64_t bcm2835_fb_read(void *opaque, hwaddr offset, unsigned size)
@@ -312,18 +352,17 @@ static const VMStateDescription vmstate_bcm2835_fb = {
VMSTATE_BOOL(lock, BCM2835FBState),
VMSTATE_BOOL(invalidate, BCM2835FBState),
VMSTATE_BOOL(pending, BCM2835FBState),
- VMSTATE_UINT32(xres, BCM2835FBState),
- VMSTATE_UINT32(yres, BCM2835FBState),
- VMSTATE_UINT32(xres_virtual, BCM2835FBState),
- VMSTATE_UINT32(yres_virtual, BCM2835FBState),
- VMSTATE_UINT32(xoffset, BCM2835FBState),
- VMSTATE_UINT32(yoffset, BCM2835FBState),
- VMSTATE_UINT32(bpp, BCM2835FBState),
- VMSTATE_UINT32(base, BCM2835FBState),
- VMSTATE_UINT32(pitch, BCM2835FBState),
- VMSTATE_UINT32(size, BCM2835FBState),
- VMSTATE_UINT32(pixo, BCM2835FBState),
- VMSTATE_UINT32(alpha, BCM2835FBState),
+ VMSTATE_UINT32(config.xres, BCM2835FBState),
+ VMSTATE_UINT32(config.yres, BCM2835FBState),
+ VMSTATE_UINT32(config.xres_virtual, BCM2835FBState),
+ VMSTATE_UINT32(config.yres_virtual, BCM2835FBState),
+ VMSTATE_UINT32(config.xoffset, BCM2835FBState),
+ VMSTATE_UINT32(config.yoffset, BCM2835FBState),
+ VMSTATE_UINT32(config.bpp, BCM2835FBState),
+ VMSTATE_UINT32(config.base, BCM2835FBState),
+ VMSTATE_UNUSED(8), /* Was pitch and size */
+ VMSTATE_UINT32(config.pixo, BCM2835FBState),
+ VMSTATE_UINT32(config.alpha, BCM2835FBState),
VMSTATE_END_OF_LIST()
}
};
@@ -349,13 +388,7 @@ static void bcm2835_fb_reset(DeviceState *dev)
s->pending = false;
- s->xres_virtual = s->xres;
- s->yres_virtual = s->yres;
- s->xoffset = 0;
- s->yoffset = 0;
- s->base = s->vcram_base + BCM2835_FB_OFFSET;
- s->pitch = s->xres * (s->bpp >> 3);
- s->size = s->yres * s->pitch;
+ s->config = s->initial_config;
s->invalidate = true;
s->lock = false;
@@ -379,24 +412,33 @@ static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
return;
}
+ /* Fill in the parts of initial_config that are not set by QOM properties */
+ s->initial_config.xres_virtual = s->initial_config.xres;
+ s->initial_config.yres_virtual = s->initial_config.yres;
+ s->initial_config.xoffset = 0;
+ s->initial_config.yoffset = 0;
+ s->initial_config.base = s->vcram_base + BCM2835_FB_OFFSET;
+
s->dma_mr = MEMORY_REGION(obj);
address_space_init(&s->dma_as, s->dma_mr, NULL);
bcm2835_fb_reset(dev);
s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
- qemu_console_resize(s->con, s->xres, s->yres);
+ qemu_console_resize(s->con, s->config.xres, s->config.yres);
}
static Property bcm2835_fb_props[] = {
DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
DEFAULT_VCRAM_SIZE),
- DEFINE_PROP_UINT32("xres", BCM2835FBState, xres, 640),
- DEFINE_PROP_UINT32("yres", BCM2835FBState, yres, 480),
- DEFINE_PROP_UINT32("bpp", BCM2835FBState, bpp, 16),
- DEFINE_PROP_UINT32("pixo", BCM2835FBState, pixo, 1), /* 1=RGB, 0=BGR */
- DEFINE_PROP_UINT32("alpha", BCM2835FBState, alpha, 2), /* alpha ignored */
+ DEFINE_PROP_UINT32("xres", BCM2835FBState, initial_config.xres, 640),
+ DEFINE_PROP_UINT32("yres", BCM2835FBState, initial_config.yres, 480),
+ DEFINE_PROP_UINT32("bpp", BCM2835FBState, initial_config.bpp, 16),
+ DEFINE_PROP_UINT32("pixo", BCM2835FBState,
+ initial_config.pixo, 1), /* 1=RGB, 0=BGR */
+ DEFINE_PROP_UINT32("alpha", BCM2835FBState,
+ initial_config.alpha, 2), /* alpha ignored */
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 6fff4852c5..1c199ab369 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -232,6 +232,7 @@ static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
s->b[s->dac_index] = regval;
/* Index autoincrement */
s->dac_index = (s->dac_index + 1) & 0xff;
+ /* fall through */
default:
s->dac_state = 0;
break;
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 7583b18c29..04c87c8e8d 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -1426,7 +1426,8 @@ static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
s->vga.hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
break;
case 0x07: // Extended Sequencer Mode
- cirrus_update_memory_access(s);
+ cirrus_update_memory_access(s);
+ /* fall through */
case 0x08: // EEPROM Control
case 0x09: // Scratch Register 0
case 0x0a: // Scratch Register 1
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
index 0d26e0f6b5..685a2378ed 100644
--- a/hw/i2c/pm_smbus.c
+++ b/hw/i2c/pm_smbus.c
@@ -22,8 +22,6 @@
#include "hw/i2c/pm_smbus.h"
#include "hw/i2c/smbus.h"
-/* no save/load? */
-
#define SMBHSTSTS 0x00
#define SMBHSTCNT 0x02
#define SMBHSTCMD 0x03
@@ -31,20 +29,40 @@
#define SMBHSTDAT0 0x05
#define SMBHSTDAT1 0x06
#define SMBBLKDAT 0x07
+#define SMBAUXCTL 0x0d
-#define STS_HOST_BUSY (1)
-#define STS_INTR (1<<1)
-#define STS_DEV_ERR (1<<2)
-#define STS_BUS_ERR (1<<3)
-#define STS_FAILED (1<<4)
-#define STS_SMBALERT (1<<5)
-#define STS_INUSE_STS (1<<6)
-#define STS_BYTE_DONE (1<<7)
+#define STS_HOST_BUSY (1 << 0)
+#define STS_INTR (1 << 1)
+#define STS_DEV_ERR (1 << 2)
+#define STS_BUS_ERR (1 << 3)
+#define STS_FAILED (1 << 4)
+#define STS_SMBALERT (1 << 5)
+#define STS_INUSE_STS (1 << 6)
+#define STS_BYTE_DONE (1 << 7)
/* Signs of successfully transaction end :
* ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR )
*/
-//#define DEBUG
+#define CTL_INTREN (1 << 0)
+#define CTL_KILL (1 << 1)
+#define CTL_LAST_BYTE (1 << 5)
+#define CTL_START (1 << 6)
+#define CTL_PEC_EN (1 << 7)
+#define CTL_RETURN_MASK 0x1f
+
+#define PROT_QUICK 0
+#define PROT_BYTE 1
+#define PROT_BYTE_DATA 2
+#define PROT_WORD_DATA 3
+#define PROT_PROC_CALL 4
+#define PROT_BLOCK_DATA 5
+#define PROT_I2C_BLOCK_READ 6
+
+#define AUX_PEC (1 << 0)
+#define AUX_BLK (1 << 1)
+#define AUX_MASK 0x3
+
+/*#define DEBUG*/
#ifdef DEBUG
# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
@@ -62,19 +80,17 @@ static void smb_transaction(PMSMBus *s)
I2CBus *bus = s->smbus;
int ret;
- assert(s->smb_stat & STS_HOST_BUSY);
- s->smb_stat &= ~STS_HOST_BUSY;
-
SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
/* Transaction isn't exec if STS_DEV_ERR bit set */
if ((s->smb_stat & STS_DEV_ERR) != 0) {
goto error;
}
+
switch(prot) {
- case 0x0:
+ case PROT_QUICK:
ret = smbus_quick_command(bus, addr, read);
goto done;
- case 0x1:
+ case PROT_BYTE:
if (read) {
ret = smbus_receive_byte(bus, addr);
goto data8;
@@ -82,7 +98,7 @@ static void smb_transaction(PMSMBus *s)
ret = smbus_send_byte(bus, addr, cmd);
goto done;
}
- case 0x2:
+ case PROT_BYTE_DATA:
if (read) {
ret = smbus_read_byte(bus, addr, cmd);
goto data8;
@@ -91,22 +107,73 @@ static void smb_transaction(PMSMBus *s)
goto done;
}
break;
- case 0x3:
+ case PROT_WORD_DATA:
if (read) {
ret = smbus_read_word(bus, addr, cmd);
goto data16;
} else {
- ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
+ ret = smbus_write_word(bus, addr, cmd,
+ (s->smb_data1 << 8) | s->smb_data0);
goto done;
}
break;
- case 0x5:
+ case PROT_I2C_BLOCK_READ:
if (read) {
- ret = smbus_read_block(bus, addr, cmd, s->smb_data);
+ int xfersize = s->smb_data0;
+ if (xfersize > sizeof(s->smb_data)) {
+ xfersize = sizeof(s->smb_data);
+ }
+ ret = smbus_read_block(bus, addr, s->smb_data1, s->smb_data,
+ xfersize, false, true);
goto data8;
} else {
- ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
- goto done;
+ /* The manual says the behavior is undefined, just set DEV_ERR. */
+ goto error;
+ }
+ break;
+ case PROT_BLOCK_DATA:
+ if (read) {
+ ret = smbus_read_block(bus, addr, cmd, s->smb_data,
+ sizeof(s->smb_data), !s->i2c_enable,
+ !s->i2c_enable);
+ if (ret < 0) {
+ goto error;
+ }
+ s->smb_index = 0;
+ s->op_done = false;
+ if (s->smb_auxctl & AUX_BLK) {
+ s->smb_stat |= STS_INTR;
+ } else {
+ s->smb_blkdata = s->smb_data[0];
+ s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
+ }
+ s->smb_data0 = ret;
+ goto out;
+ } else {
+ if (s->smb_auxctl & AUX_BLK) {
+ if (s->smb_index != s->smb_data0) {
+ s->smb_index = 0;
+ goto error;
+ }
+ /* Data is already all written to the queue, just do
+ the operation. */
+ s->smb_index = 0;
+ ret = smbus_write_block(bus, addr, cmd, s->smb_data,
+ s->smb_data0, !s->i2c_enable);
+ if (ret < 0) {
+ goto error;
+ }
+ s->op_done = true;
+ s->smb_stat |= STS_INTR;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ } else {
+ s->op_done = false;
+ s->smb_stat |= STS_HOST_BUSY | STS_BYTE_DONE;
+ s->smb_data[0] = s->smb_blkdata;
+ s->smb_index = 0;
+ ret = 0;
+ }
+ goto out;
}
break;
default:
@@ -128,20 +195,35 @@ done:
if (ret < 0) {
goto error;
}
- s->smb_stat |= STS_BYTE_DONE | STS_INTR;
+ s->smb_stat |= STS_INTR;
+out:
return;
error:
s->smb_stat |= STS_DEV_ERR;
return;
-
}
static void smb_transaction_start(PMSMBus *s)
{
- /* Do not execute immediately the command ; it will be
- * executed when guest will read SMB_STAT register */
- s->smb_stat |= STS_HOST_BUSY;
+ if (s->smb_ctl & CTL_INTREN) {
+ smb_transaction(s);
+ } else {
+ /* Do not execute immediately the command; it will be
+ * executed when guest will read SMB_STAT register. This
+ * is to work around a bug in AMIBIOS (that is working
+ * around another bug in some specific hardware) where
+ * it waits for STS_HOST_BUSY to be set before waiting
+ * checking for status. If STS_HOST_BUSY doesn't get
+ * set, it gets stuck. */
+ s->smb_stat |= STS_HOST_BUSY;
+ }
+}
+
+static bool
+smb_irq_value(PMSMBus *s)
+{
+ return ((s->smb_stat & ~STS_HOST_BUSY) != 0) && (s->smb_ctl & CTL_INTREN);
}
static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
@@ -153,13 +235,61 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
" val=0x%02" PRIx64 "\n", addr, val);
switch(addr) {
case SMBHSTSTS:
- s->smb_stat = (~(val & 0xff)) & s->smb_stat;
- s->smb_index = 0;
+ s->smb_stat &= ~(val & ~STS_HOST_BUSY);
+ if (!s->op_done && !(s->smb_auxctl & AUX_BLK)) {
+ uint8_t read = s->smb_addr & 0x01;
+
+ s->smb_index++;
+ if (!read && s->smb_index == s->smb_data0) {
+ uint8_t prot = (s->smb_ctl >> 2) & 0x07;
+ uint8_t cmd = s->smb_cmd;
+ uint8_t addr = s->smb_addr >> 1;
+ int ret;
+
+ if (prot == PROT_I2C_BLOCK_READ) {
+ s->smb_stat |= STS_DEV_ERR;
+ goto out;
+ }
+
+ ret = smbus_write_block(s->smbus, addr, cmd, s->smb_data,
+ s->smb_data0, !s->i2c_enable);
+ if (ret < 0) {
+ s->smb_stat |= STS_DEV_ERR;
+ goto out;
+ }
+ s->op_done = true;
+ s->smb_stat |= STS_INTR;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ } else if (!read) {
+ s->smb_data[s->smb_index] = s->smb_blkdata;
+ s->smb_stat |= STS_BYTE_DONE;
+ } else if (s->smb_ctl & CTL_LAST_BYTE) {
+ s->op_done = true;
+ s->smb_blkdata = s->smb_data[s->smb_index];
+ s->smb_index = 0;
+ s->smb_stat |= STS_INTR;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ } else {
+ s->smb_blkdata = s->smb_data[s->smb_index];
+ s->smb_stat |= STS_BYTE_DONE;
+ }
+ }
break;
case SMBHSTCNT:
- s->smb_ctl = val;
- if (val & 0x40)
+ s->smb_ctl = val & ~CTL_START; /* CTL_START always reads 0 */
+ if (val & CTL_START) {
+ if (!s->op_done) {
+ s->smb_index = 0;
+ s->op_done = true;
+ }
smb_transaction_start(s);
+ }
+ if (s->smb_ctl & CTL_KILL) {
+ s->op_done = true;
+ s->smb_index = 0;
+ s->smb_stat |= STS_FAILED;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ }
break;
case SMBHSTCMD:
s->smb_cmd = val;
@@ -174,13 +304,26 @@ static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
s->smb_data1 = val;
break;
case SMBBLKDAT:
- s->smb_data[s->smb_index++] = val;
- if (s->smb_index > 31)
+ if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
s->smb_index = 0;
+ }
+ if (s->smb_auxctl & AUX_BLK) {
+ s->smb_data[s->smb_index++] = val;
+ } else {
+ s->smb_blkdata = val;
+ }
+ break;
+ case SMBAUXCTL:
+ s->smb_auxctl = val & AUX_MASK;
break;
default:
break;
}
+
+ out:
+ if (s->set_irq) {
+ s->set_irq(s, smb_irq_value(s));
+ }
}
static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
@@ -193,12 +336,12 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
val = s->smb_stat;
if (s->smb_stat & STS_HOST_BUSY) {
/* execute command now */
+ s->smb_stat &= ~STS_HOST_BUSY;
smb_transaction(s);
}
break;
case SMBHSTCNT:
- s->smb_index = 0;
- val = s->smb_ctl & 0x1f;
+ val = s->smb_ctl & CTL_RETURN_MASK;
break;
case SMBHSTCMD:
val = s->smb_cmd;
@@ -213,18 +356,44 @@ static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
val = s->smb_data1;
break;
case SMBBLKDAT:
- val = s->smb_data[s->smb_index++];
- if (s->smb_index > 31)
+ if (s->smb_index >= PM_SMBUS_MAX_MSG_SIZE) {
s->smb_index = 0;
+ }
+ if (s->smb_auxctl & AUX_BLK) {
+ val = s->smb_data[s->smb_index++];
+ if (!s->op_done && s->smb_index == s->smb_data0) {
+ s->op_done = true;
+ s->smb_index = 0;
+ s->smb_stat &= ~STS_HOST_BUSY;
+ }
+ } else {
+ val = s->smb_blkdata;
+ }
+ break;
+ case SMBAUXCTL:
+ val = s->smb_auxctl;
break;
default:
val = 0;
break;
}
- SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", addr, val);
+ SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n",
+ addr, val);
+
+ if (s->set_irq) {
+ s->set_irq(s, smb_irq_value(s));
+ }
+
return val;
}
+static void pm_smbus_reset(PMSMBus *s)
+{
+ s->op_done = true;
+ s->smb_index = 0;
+ s->smb_stat = 0;
+}
+
static const MemoryRegionOps pm_smbus_ops = {
.read = smb_ioport_readb,
.write = smb_ioport_writeb,
@@ -233,9 +402,14 @@ static const MemoryRegionOps pm_smbus_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk)
{
+ smb->op_done = true;
+ smb->reset = pm_smbus_reset;
smb->smbus = i2c_init_bus(parent, "i2c");
+ if (force_aux_blk) {
+ smb->smb_auxctl |= AUX_BLK;
+ }
memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb,
"pm-smbus", 64);
}
diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
index 587ce1ab7f..6ff77c582f 100644
--- a/hw/i2c/smbus.c
+++ b/hw/i2c/smbus.c
@@ -293,33 +293,42 @@ int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data)
return 0;
}
-int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data)
+int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+ int len, bool recv_len, bool send_cmd)
{
- int len;
+ int rlen;
int i;
- if (i2c_start_transfer(bus, addr, 0)) {
- return -1;
+ if (send_cmd) {
+ if (i2c_start_transfer(bus, addr, 0)) {
+ return -1;
+ }
+ i2c_send(bus, command);
}
- i2c_send(bus, command);
if (i2c_start_transfer(bus, addr, 1)) {
- i2c_end_transfer(bus);
+ if (send_cmd) {
+ i2c_end_transfer(bus);
+ }
return -1;
}
- len = i2c_recv(bus);
- if (len > 32) {
- len = 0;
+ if (recv_len) {
+ rlen = i2c_recv(bus);
+ } else {
+ rlen = len;
}
- for (i = 0; i < len; i++) {
+ if (rlen > len) {
+ rlen = 0;
+ }
+ for (i = 0; i < rlen; i++) {
data[i] = i2c_recv(bus);
}
i2c_nack(bus);
i2c_end_transfer(bus);
- return len;
+ return rlen;
}
int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
- int len)
+ int len, bool send_len)
{
int i;
@@ -330,7 +339,9 @@ int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
return -1;
}
i2c_send(bus, command);
- i2c_send(bus, len);
+ if (send_len) {
+ i2c_send(bus, len);
+ }
for (i = 0; i < len; i++) {
i2c_send(bus, data[i]);
}
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
index 007cb6701d..2a8b49e02f 100644
--- a/hw/i2c/smbus_ich9.c
+++ b/hw/i2c/smbus_ich9.c
@@ -40,6 +40,8 @@
typedef struct ICH9SMBState {
PCIDevice dev;
+ bool irq_enabled;
+
PMSMBus smb;
} ICH9SMBState;
@@ -61,12 +63,16 @@ static void ich9_smbus_write_config(PCIDevice *d, uint32_t address,
pci_default_write_config(d, address, val, len);
if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) {
uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
- if ((hostc & ICH9_SMB_HOSTC_HST_EN) &&
- !(hostc & ICH9_SMB_HOSTC_I2C_EN)) {
+ if (hostc & ICH9_SMB_HOSTC_HST_EN) {
memory_region_set_enabled(&s->smb.io, true);
} else {
memory_region_set_enabled(&s->smb.io, false);
}
+ s->smb.i2c_enable = (hostc & ICH9_SMB_HOSTC_I2C_EN) != 0;
+ if (hostc & ICH9_SMB_HOSTC_SSRESET) {
+ s->smb.reset(&s->smb);
+ s->dev.config[ICH9_SMB_HOSTC] &= ~ICH9_SMB_HOSTC_SSRESET;
+ }
}
}
@@ -80,7 +86,7 @@ static void ich9_smbus_realize(PCIDevice *d, Error **errp)
pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
/* TODO bar0, bar1: 64bit BAR support*/
- pm_smbus_init(&d->qdev, &s->smb);
+ pm_smbus_init(&d->qdev, &s->smb, false);
pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
&s->smb.io);
}
@@ -105,11 +111,25 @@ static void ich9_smb_class_init(ObjectClass *klass, void *data)
dc->user_creatable = false;
}
+static void ich9_smb_set_irq(PMSMBus *pmsmb, bool enabled)
+{
+ ICH9SMBState *s = pmsmb->opaque;
+
+ if (enabled == s->irq_enabled) {
+ return;
+ }
+
+ s->irq_enabled = enabled;
+ pci_set_irq(&s->dev, enabled);
+}
+
I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
{
PCIDevice *d =
pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE);
ICH9SMBState *s = ICH9_SMB_DEVICE(d);
+ s->smb.set_irq = ich9_smb_set_irq;
+ s->smb.opaque = s;
return s->smb.smbus;
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 83a444472b..03148450c8 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1679,7 +1679,9 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
const PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+ const PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
+ const uint64_t legacy_align = TARGET_PAGE_SIZE;
/*
* When -no-acpi is used with Q35 machine type, no ACPI is built,
@@ -1696,6 +1698,9 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
error_setg(errp, "nvdimm is not enabled: missing 'nvdimm' in '-M'");
return;
}
+
+ pc_dimm_pre_plug(dev, MACHINE(hotplug_dev),
+ pcmc->enforce_aligned_dimm ? NULL : &legacy_align, errp);
}
static void pc_memory_plug(HotplugHandler *hotplug_dev,
@@ -1704,18 +1709,9 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
HotplugHandlerClass *hhc;
Error *local_err = NULL;
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
- PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
- PCDIMMDevice *dimm = PC_DIMM(dev);
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
- uint64_t align = TARGET_PAGE_SIZE;
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
- if (memory_region_get_alignment(mr) && pcmc->enforce_aligned_dimm) {
- align = memory_region_get_alignment(mr);
- }
-
- pc_dimm_plug(dev, MACHINE(pcms), align, &local_err);
+ pc_dimm_plug(dev, MACHINE(pcms), &local_err);
if (local_err) {
goto out;
}
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index 6fda52b86c..97ffdd820f 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -650,31 +650,17 @@ static void apic_timer(void *opaque)
apic_timer_update(s, s->next_time);
}
-static uint32_t apic_mem_readb(void *opaque, hwaddr addr)
-{
- return 0;
-}
-
-static uint32_t apic_mem_readw(void *opaque, hwaddr addr)
-{
- return 0;
-}
-
-static void apic_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-}
-
-static void apic_mem_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-}
-
-static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
+static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
{
DeviceState *dev;
APICCommonState *s;
uint32_t val;
int index;
+ if (size < 4) {
+ return 0;
+ }
+
dev = cpu_get_current_apic();
if (!dev) {
return 0;
@@ -765,11 +751,17 @@ static void apic_send_msi(MSIMessage *msi)
apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
}
-static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
+static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
{
DeviceState *dev;
APICCommonState *s;
int index = (addr >> 4) & 0xff;
+
+ if (size < 4) {
+ return;
+ }
+
if (addr > 0xfff || !index) {
/* MSI and MMIO APIC are at the same memory location,
* but actually not on the global bus: MSI is on PCI bus
@@ -880,10 +872,12 @@ static void apic_post_load(APICCommonState *s)
}
static const MemoryRegionOps apic_io_ops = {
- .old_mmio = {
- .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
- .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, },
- },
+ .read = apic_mem_read,
+ .write = apic_mem_write,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
.endianness = DEVICE_NATIVE_ENDIAN,
};
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index c1b35fc1ee..542b4b93ea 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -2084,7 +2084,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
for (i = 0; i < s->num_cpu; i++) {
memory_region_init_io(&s->vifaceiomem[i + 1], OBJECT(s),
&gic_viface_ops, &s->backref[i],
- "gic_viface", 0x1000);
+ "gic_viface", 0x200);
sysbus_init_mmio(sbd, &s->vifaceiomem[i + 1]);
}
}
diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c
index e946030e84..8bbb1fa785 100644
--- a/hw/ipmi/isa_ipmi_bt.c
+++ b/hw/ipmi/isa_ipmi_bt.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/ipmi/ipmi.h"
@@ -450,22 +451,63 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base);
}
-static const VMStateDescription vmstate_ISAIPMIBTDevice = {
- .name = TYPE_IPMI_INTERFACE,
+static int ipmi_bt_vmstate_post_load(void *opaque, int version)
+{
+ IPMIBT *ib = opaque;
+
+ /* Make sure all the values are sane. */
+ if (ib->outpos >= MAX_IPMI_MSG_SIZE || ib->outlen >= MAX_IPMI_MSG_SIZE ||
+ ib->outpos >= ib->outlen) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ipmi:bt: vmstate transfer received bad out values: %d %d\n",
+ ib->outpos, ib->outlen);
+ ib->outpos = 0;
+ ib->outlen = 0;
+ }
+
+ if (ib->inlen >= MAX_IPMI_MSG_SIZE) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ipmi:bt: vmstate transfer received bad in value: %d\n",
+ ib->inlen);
+ ib->inlen = 0;
+ }
+
+ return 0;
+}
+
+const VMStateDescription vmstate_IPMIBT = {
+ .name = TYPE_IPMI_INTERFACE_PREFIX "bt",
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = ipmi_bt_vmstate_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(obf_irq_set, IPMIBT),
+ VMSTATE_BOOL(atn_irq_set, IPMIBT),
+ VMSTATE_BOOL(irqs_enabled, IPMIBT),
+ VMSTATE_UINT32(outpos, IPMIBT),
+ VMSTATE_UINT32(outlen, IPMIBT),
+ VMSTATE_UINT8_ARRAY(outmsg, IPMIBT, MAX_IPMI_MSG_SIZE),
+ VMSTATE_UINT32(inlen, IPMIBT),
+ VMSTATE_UINT8_ARRAY(inmsg, IPMIBT, MAX_IPMI_MSG_SIZE),
+ VMSTATE_UINT8(control_reg, IPMIBT),
+ VMSTATE_UINT8(mask_reg, IPMIBT),
+ VMSTATE_UINT8(waiting_rsp, IPMIBT),
+ VMSTATE_UINT8(waiting_seq, IPMIBT),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_ISAIPMIBTDevice = {
+ .name = TYPE_IPMI_INTERFACE_PREFIX "isa-bt",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ /*
+ * Version 1 had messed up the array transfer, it's not even usable
+ * because it used VMSTATE_VBUFFER_UINT32, but it did not transfer
+ * the buffer length, so random things would happen.
+ */
.fields = (VMStateField[]) {
- VMSTATE_BOOL(bt.obf_irq_set, ISAIPMIBTDevice),
- VMSTATE_BOOL(bt.atn_irq_set, ISAIPMIBTDevice),
- VMSTATE_BOOL(bt.use_irq, ISAIPMIBTDevice),
- VMSTATE_BOOL(bt.irqs_enabled, ISAIPMIBTDevice),
- VMSTATE_UINT32(bt.outpos, ISAIPMIBTDevice),
- VMSTATE_VBUFFER_UINT32(bt.outmsg, ISAIPMIBTDevice, 1, NULL, bt.outlen),
- VMSTATE_VBUFFER_UINT32(bt.inmsg, ISAIPMIBTDevice, 1, NULL, bt.inlen),
- VMSTATE_UINT8(bt.control_reg, ISAIPMIBTDevice),
- VMSTATE_UINT8(bt.mask_reg, ISAIPMIBTDevice),
- VMSTATE_UINT8(bt.waiting_rsp, ISAIPMIBTDevice),
- VMSTATE_UINT8(bt.waiting_seq, ISAIPMIBTDevice),
+ VMSTATE_STRUCT(bt, ISAIPMIBTDevice, 1, vmstate_IPMIBT, IPMIBT),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index cff1946232..7302f6d74b 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -370,7 +370,7 @@ static void vt82c686b_pm_realize(PCIDevice *dev, Error **errp)
pci_conf[0x90] = s->smb_io_base | 1;
pci_conf[0x91] = s->smb_io_base >> 8;
pci_conf[0xd2] = 0x90;
- pm_smbus_init(&s->dev.qdev, &s->smb);
+ pm_smbus_init(&s->dev.qdev, &s->smb, false);
memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io);
apm_init(dev, &s->apm, NULL, s);
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 65843bc52a..fb6bcaedc4 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -29,57 +29,60 @@
static int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp);
-void pc_dimm_plug(DeviceState *dev, MachineState *machine, uint64_t align,
- Error **errp)
+void pc_dimm_pre_plug(DeviceState *dev, MachineState *machine,
+ const uint64_t *legacy_align, Error **errp)
{
- int slot;
PCDIMMDevice *dimm = PC_DIMM(dev);
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm,
- &error_abort);
- MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
Error *local_err = NULL;
- uint64_t addr;
+ MemoryRegion *mr;
+ uint64_t addr, align;
+ int slot;
- addr = object_property_get_uint(OBJECT(dimm),
- PC_DIMM_ADDR_PROP, &local_err);
+ slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
+ &error_abort);
+ slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot,
+ machine->ram_slots, &local_err);
if (local_err) {
goto out;
}
+ object_property_set_int(OBJECT(dev), slot, PC_DIMM_SLOT_PROP, &error_abort);
+ trace_mhp_pc_dimm_assigned_slot(slot);
- addr = memory_device_get_free_addr(machine, !addr ? NULL : &addr, align,
- memory_region_size(mr), &local_err);
+ mr = ddc->get_memory_region(dimm, &local_err);
if (local_err) {
goto out;
}
- object_property_set_uint(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, &local_err);
+ align = legacy_align ? *legacy_align : memory_region_get_alignment(mr);
+ addr = object_property_get_uint(OBJECT(dev), PC_DIMM_ADDR_PROP,
+ &error_abort);
+ addr = memory_device_get_free_addr(machine, !addr ? NULL : &addr, align,
+ memory_region_size(mr), &local_err);
if (local_err) {
goto out;
}
trace_mhp_pc_dimm_assigned_address(addr);
+ object_property_set_uint(OBJECT(dev), addr, PC_DIMM_ADDR_PROP,
+ &error_abort);
+out:
+ error_propagate(errp, local_err);
+}
- slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, &local_err);
- if (local_err) {
- goto out;
- }
+void pc_dimm_plug(DeviceState *dev, MachineState *machine, Error **errp)
+{
+ PCDIMMDevice *dimm = PC_DIMM(dev);
+ PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
+ MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm,
+ &error_abort);
+ MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
+ uint64_t addr;
- slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot,
- machine->ram_slots, &local_err);
- if (local_err) {
- goto out;
- }
- object_property_set_int(OBJECT(dev), slot, PC_DIMM_SLOT_PROP, &local_err);
- if (local_err) {
- goto out;
- }
- trace_mhp_pc_dimm_assigned_slot(slot);
+ addr = object_property_get_uint(OBJECT(dev), PC_DIMM_ADDR_PROP,
+ &error_abort);
memory_device_plug_region(machine, mr, addr);
vmstate_register_ram(vmstate_mr, dev);
-
-out:
- error_propagate(errp, local_err);
}
void pc_dimm_unplug(DeviceState *dev, MachineState *machine)
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 22714b0851..6d50b03cfd 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -64,8 +64,11 @@ obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
obj-$(CONFIG_TZ_MPC) += tz-mpc.o
+obj-$(CONFIG_TZ_MSC) += tz-msc.o
obj-$(CONFIG_TZ_PPC) += tz-ppc.o
obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
+obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
+obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
index 70eaafd325..145427ae0f 100644
--- a/hw/misc/bcm2835_property.c
+++ b/hw/misc/bcm2835_property.c
@@ -21,11 +21,14 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
uint32_t tmp;
int n;
uint32_t offset, length, color;
- uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha;
- uint32_t tmp_xres, tmp_yres, tmp_xoffset, tmp_yoffset;
- uint32_t tmp_bpp, tmp_pixo, tmp_alpha;
- uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL,
- *newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL;
+
+ /*
+ * Copy the current state of the framebuffer config; we will update
+ * this copy as we process tags and then ask the framebuffer to use
+ * it at the end.
+ */
+ BCM2835FBConfig fbconfig = s->fbdev->config;
+ bool fbconfig_updated = false;
value &= ~0xf;
@@ -141,12 +144,9 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
/* Frame buffer */
case 0x00040001: /* Allocate buffer */
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->base);
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
- tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres;
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.base);
stl_le_phys(&s->dma_as, value + 16,
- tmp_xres * tmp_yres * tmp_bpp / 8);
+ bcm2835_fb_get_size(&fbconfig));
resplen = 8;
break;
case 0x00048001: /* Release buffer */
@@ -155,86 +155,85 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
case 0x00040002: /* Blank screen */
resplen = 4;
break;
- case 0x00040003: /* Get display width/height */
- case 0x00040004:
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
- tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres;
- stl_le_phys(&s->dma_as, value + 12, tmp_xres);
- stl_le_phys(&s->dma_as, value + 16, tmp_yres);
+ case 0x00044003: /* Test physical display width/height */
+ case 0x00044004: /* Test virtual display width/height */
resplen = 8;
break;
- case 0x00044003: /* Test display width/height */
- case 0x00044004:
+ case 0x00048003: /* Set physical display width/height */
+ fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12);
+ fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16);
+ bcm2835_fb_validate_config(&fbconfig);
+ fbconfig_updated = true;
+ /* fall through */
+ case 0x00040003: /* Get physical display width/height */
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xres);
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yres);
resplen = 8;
break;
- case 0x00048003: /* Set display width/height */
- case 0x00048004:
- xres = ldl_le_phys(&s->dma_as, value + 12);
- newxres = &xres;
- yres = ldl_le_phys(&s->dma_as, value + 16);
- newyres = &yres;
+ case 0x00048004: /* Set virtual display width/height */
+ fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12);
+ fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16);
+ bcm2835_fb_validate_config(&fbconfig);
+ fbconfig_updated = true;
+ /* fall through */
+ case 0x00040004: /* Get virtual display width/height */
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual);
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual);
resplen = 8;
break;
- case 0x00040005: /* Get depth */
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
- stl_le_phys(&s->dma_as, value + 12, tmp_bpp);
- resplen = 4;
- break;
case 0x00044005: /* Test depth */
resplen = 4;
break;
case 0x00048005: /* Set depth */
- bpp = ldl_le_phys(&s->dma_as, value + 12);
- newbpp = &bpp;
- resplen = 4;
- break;
- case 0x00040006: /* Get pixel order */
- tmp_pixo = newpixo != NULL ? *newpixo : s->fbdev->pixo;
- stl_le_phys(&s->dma_as, value + 12, tmp_pixo);
+ fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12);
+ bcm2835_fb_validate_config(&fbconfig);
+ fbconfig_updated = true;
+ /* fall through */
+ case 0x00040005: /* Get depth */
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp);
resplen = 4;
break;
case 0x00044006: /* Test pixel order */
resplen = 4;
break;
case 0x00048006: /* Set pixel order */
- pixo = ldl_le_phys(&s->dma_as, value + 12);
- newpixo = &pixo;
- resplen = 4;
- break;
- case 0x00040007: /* Get alpha */
- tmp_alpha = newalpha != NULL ? *newalpha : s->fbdev->alpha;
- stl_le_phys(&s->dma_as, value + 12, tmp_alpha);
+ fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12);
+ bcm2835_fb_validate_config(&fbconfig);
+ fbconfig_updated = true;
+ /* fall through */
+ case 0x00040006: /* Get pixel order */
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo);
resplen = 4;
break;
case 0x00044007: /* Test pixel alpha */
resplen = 4;
break;
case 0x00048007: /* Set alpha */
- alpha = ldl_le_phys(&s->dma_as, value + 12);
- newalpha = &alpha;
+ fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12);
+ bcm2835_fb_validate_config(&fbconfig);
+ fbconfig_updated = true;
+ /* fall through */
+ case 0x00040007: /* Get alpha */
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha);
resplen = 4;
break;
case 0x00040008: /* Get pitch */
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
- stl_le_phys(&s->dma_as, value + 12, tmp_xres * tmp_bpp / 8);
+ stl_le_phys(&s->dma_as, value + 12,
+ bcm2835_fb_get_pitch(&fbconfig));
resplen = 4;
break;
- case 0x00040009: /* Get virtual offset */
- tmp_xoffset = newxoffset != NULL ? *newxoffset : s->fbdev->xoffset;
- tmp_yoffset = newyoffset != NULL ? *newyoffset : s->fbdev->yoffset;
- stl_le_phys(&s->dma_as, value + 12, tmp_xoffset);
- stl_le_phys(&s->dma_as, value + 16, tmp_yoffset);
- resplen = 8;
- break;
case 0x00044009: /* Test virtual offset */
resplen = 8;
break;
case 0x00048009: /* Set virtual offset */
- xoffset = ldl_le_phys(&s->dma_as, value + 12);
- newxoffset = &xoffset;
- yoffset = ldl_le_phys(&s->dma_as, value + 16);
- newyoffset = &yoffset;
+ fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12);
+ fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16);
+ bcm2835_fb_validate_config(&fbconfig);
+ fbconfig_updated = true;
+ /* fall through */
+ case 0x00040009: /* Get virtual offset */
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset);
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset);
resplen = 8;
break;
case 0x0004000a: /* Get/Test/Set overscan */
@@ -285,10 +284,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
}
/* Reconfigure framebuffer if required */
- if (newxres || newyres || newxoffset || newyoffset || newbpp || newpixo
- || newalpha) {
- bcm2835_fb_reconfigure(s->fbdev, newxres, newyres, newxoffset,
- newyoffset, newbpp, newpixo, newalpha);
+ if (fbconfig_updated) {
+ bcm2835_fb_reconfigure(s->fbdev, &fbconfig);
}
/* Buffer response code */
diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c
index de4fd8e36d..2222b3e147 100644
--- a/hw/misc/iotkit-secctl.c
+++ b/hw/misc/iotkit-secctl.c
@@ -190,12 +190,13 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr,
r = s->apbexp[offset_to_ppc_idx(offset)].sp;
break;
case A_SECMSCINTSTAT:
+ r = s->secmscintstat;
+ break;
case A_SECMSCINTEN:
+ r = s->secmscinten;
+ break;
case A_NSMSCEXP:
- qemu_log_mask(LOG_UNIMP,
- "IoTKit SecCtl S block read: "
- "unimplemented offset 0x%x\n", offset);
- r = 0;
+ r = s->nsmscexp;
break;
case A_PID4:
case A_PID5:
@@ -291,6 +292,23 @@ static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc)
qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1));
}
+static void iotkit_secctl_update_mscexp_irqs(qemu_irq *msc_irqs, uint32_t value)
+{
+ int i;
+
+ for (i = 0; i < IOTS_NUM_EXP_MSC; i++) {
+ qemu_set_irq(msc_irqs[i], extract32(value, i + 16, 1));
+ }
+}
+
+static void iotkit_secctl_update_msc_irq(IoTKitSecCtl *s)
+{
+ /* Update the combined MSC IRQ, based on S_MSCEXP_STATUS and S_MSCEXP_EN */
+ bool level = s->secmscintstat & s->secmscinten;
+
+ qemu_set_irq(s->msc_irq, level);
+}
+
static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
uint64_t value,
unsigned size, MemTxAttrs attrs)
@@ -370,10 +388,15 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
iotkit_secctl_ppc_sp_write(ppc, value);
break;
case A_SECMSCINTCLR:
+ iotkit_secctl_update_mscexp_irqs(s->mscexp_clear, value);
+ break;
case A_SECMSCINTEN:
- qemu_log_mask(LOG_UNIMP,
- "IoTKit SecCtl S block write: "
- "unimplemented offset 0x%x\n", offset);
+ s->secmscinten = value;
+ iotkit_secctl_update_msc_irq(s);
+ break;
+ case A_NSMSCEXP:
+ s->nsmscexp = value;
+ iotkit_secctl_update_mscexp_irqs(s->mscexp_ns, value);
break;
case A_SECMPCINTSTATUS:
case A_SECPPCINTSTAT:
@@ -381,7 +404,6 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
case A_BRGINTSTAT:
case A_AHBNSPPC0:
case A_AHBSPPPC0:
- case A_NSMSCEXP:
case A_PID4:
case A_PID5:
case A_PID6:
@@ -588,6 +610,14 @@ static void iotkit_secctl_mpcexp_status(void *opaque, int n, int level)
s->mpcintstatus = deposit32(s->mpcintstatus, n + 16, 1, !!level);
}
+static void iotkit_secctl_mscexp_status(void *opaque, int n, int level)
+{
+ IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
+
+ s->secmscintstat = deposit32(s->secmscintstat, n + 16, 1, !!level);
+ iotkit_secctl_update_msc_irq(s);
+}
+
static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level)
{
IoTKitSecCtlPPC *ppc = opaque;
@@ -660,6 +690,14 @@ static void iotkit_secctl_init(Object *obj)
qdev_init_gpio_in_named(dev, iotkit_secctl_mpcexp_status,
"mpcexp_status", IOTS_NUM_EXP_MPC);
+ qdev_init_gpio_in_named(dev, iotkit_secctl_mscexp_status,
+ "mscexp_status", IOTS_NUM_EXP_MSC);
+ qdev_init_gpio_out_named(dev, s->mscexp_clear, "mscexp_clear",
+ IOTS_NUM_EXP_MSC);
+ qdev_init_gpio_out_named(dev, s->mscexp_ns, "mscexp_ns",
+ IOTS_NUM_EXP_MSC);
+ qdev_init_gpio_out_named(dev, &s->msc_irq, "msc_irq", 1);
+
memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops,
s, "iotkit-secctl-s-regs", 0x1000);
memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops,
@@ -690,6 +728,24 @@ static const VMStateDescription iotkit_secctl_mpcintstatus_vmstate = {
}
};
+static bool needed_always(void *opaque)
+{
+ return true;
+}
+
+static const VMStateDescription iotkit_secctl_msc_vmstate = {
+ .name = "iotkit-secctl/msc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = needed_always,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(secmscintstat, IoTKitSecCtl),
+ VMSTATE_UINT32(secmscinten, IoTKitSecCtl),
+ VMSTATE_UINT32(nsmscexp, IoTKitSecCtl),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription iotkit_secctl_vmstate = {
.name = "iotkit-secctl",
.version_id = 1,
@@ -710,6 +766,7 @@ static const VMStateDescription iotkit_secctl_vmstate = {
},
.subsections = (const VMStateDescription*[]) {
&iotkit_secctl_mpcintstatus_vmstate,
+ &iotkit_secctl_msc_vmstate,
NULL
},
};
diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
new file mode 100644
index 0000000000..a21d8bd678
--- /dev/null
+++ b/hw/misc/iotkit-sysctl.c
@@ -0,0 +1,261 @@
+/*
+ * ARM IoTKit system control element
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/*
+ * This is a model of the "system control element" which is part of the
+ * Arm IoTKit and documented in
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * Specifically, it implements the "system control register" blocks.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/misc/iotkit-sysctl.h"
+
+REG32(SECDBGSTAT, 0x0)
+REG32(SECDBGSET, 0x4)
+REG32(SECDBGCLR, 0x8)
+REG32(RESET_SYNDROME, 0x100)
+REG32(RESET_MASK, 0x104)
+REG32(SWRESET, 0x108)
+ FIELD(SWRESET, SWRESETREQ, 9, 1)
+REG32(GRETREG, 0x10c)
+REG32(INITSVRTOR0, 0x110)
+REG32(CPUWAIT, 0x118)
+REG32(BUSWAIT, 0x11c)
+REG32(WICCTRL, 0x120)
+REG32(PID4, 0xfd0)
+REG32(PID5, 0xfd4)
+REG32(PID6, 0xfd8)
+REG32(PID7, 0xfdc)
+REG32(PID0, 0xfe0)
+REG32(PID1, 0xfe4)
+REG32(PID2, 0xfe8)
+REG32(PID3, 0xfec)
+REG32(CID0, 0xff0)
+REG32(CID1, 0xff4)
+REG32(CID2, 0xff8)
+REG32(CID3, 0xffc)
+
+/* PID/CID values */
+static const int sysctl_id[] = {
+ 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
+ 0x54, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
+ 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
+};
+
+static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
+ uint64_t r;
+
+ switch (offset) {
+ case A_SECDBGSTAT:
+ r = s->secure_debug;
+ break;
+ case A_RESET_SYNDROME:
+ r = s->reset_syndrome;
+ break;
+ case A_RESET_MASK:
+ r = s->reset_mask;
+ break;
+ case A_GRETREG:
+ r = s->gretreg;
+ break;
+ case A_INITSVRTOR0:
+ r = s->initsvrtor0;
+ break;
+ case A_CPUWAIT:
+ r = s->cpuwait;
+ break;
+ case A_BUSWAIT:
+ /* In IoTKit BUSWAIT is reserved, R/O, zero */
+ r = 0;
+ break;
+ case A_WICCTRL:
+ r = s->wicctrl;
+ break;
+ case A_PID4 ... A_CID3:
+ r = sysctl_id[(offset - A_PID4) / 4];
+ break;
+ case A_SECDBGSET:
+ case A_SECDBGCLR:
+ case A_SWRESET:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IoTKit SysCtl read: read of WO offset %x\n",
+ (int)offset);
+ r = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IoTKit SysCtl read: bad offset %x\n", (int)offset);
+ r = 0;
+ break;
+ }
+ trace_iotkit_sysctl_read(offset, r, size);
+ return r;
+}
+
+static void iotkit_sysctl_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
+
+ trace_iotkit_sysctl_write(offset, value, size);
+
+ /*
+ * Most of the state here has to do with control of reset and
+ * similar kinds of power up -- for instance the guest can ask
+ * what the reason for the last reset was, or forbid reset for
+ * some causes (like the non-secure watchdog). Most of this is
+ * not relevant to QEMU, which doesn't really model anything other
+ * than a full power-on reset.
+ * We just model the registers as reads-as-written.
+ */
+
+ switch (offset) {
+ case A_RESET_SYNDROME:
+ qemu_log_mask(LOG_UNIMP,
+ "IoTKit SysCtl RESET_SYNDROME unimplemented\n");
+ s->reset_syndrome = value;
+ break;
+ case A_RESET_MASK:
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl RESET_MASK unimplemented\n");
+ s->reset_mask = value;
+ break;
+ case A_GRETREG:
+ /*
+ * General retention register, which is only reset by a power-on
+ * reset. Technically this implementation is complete, since
+ * QEMU only supports power-on resets...
+ */
+ s->gretreg = value;
+ break;
+ case A_INITSVRTOR0:
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl INITSVRTOR0 unimplemented\n");
+ s->initsvrtor0 = value;
+ break;
+ case A_CPUWAIT:
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CPUWAIT unimplemented\n");
+ s->cpuwait = value;
+ break;
+ case A_WICCTRL:
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl WICCTRL unimplemented\n");
+ s->wicctrl = value;
+ break;
+ case A_SECDBGSET:
+ /* write-1-to-set */
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SECDBGSET unimplemented\n");
+ s->secure_debug |= value;
+ break;
+ case A_SECDBGCLR:
+ /* write-1-to-clear */
+ s->secure_debug &= ~value;
+ break;
+ case A_SWRESET:
+ /* One w/o bit to request a reset; all other bits reserved */
+ if (value & R_SWRESET_SWRESETREQ_MASK) {
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ }
+ break;
+ case A_BUSWAIT: /* In IoTKit BUSWAIT is reserved, R/O, zero */
+ case A_SECDBGSTAT:
+ case A_PID4 ... A_CID3:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IoTKit SysCtl write: write of RO offset %x\n",
+ (int)offset);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IoTKit SysCtl write: bad offset %x\n", (int)offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps iotkit_sysctl_ops = {
+ .read = iotkit_sysctl_read,
+ .write = iotkit_sysctl_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ /* byte/halfword accesses are just zero-padded on reads and writes */
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+};
+
+static void iotkit_sysctl_reset(DeviceState *dev)
+{
+ IoTKitSysCtl *s = IOTKIT_SYSCTL(dev);
+
+ trace_iotkit_sysctl_reset();
+ s->secure_debug = 0;
+ s->reset_syndrome = 1;
+ s->reset_mask = 0;
+ s->gretreg = 0;
+ s->initsvrtor0 = 0x10000000;
+ s->cpuwait = 0;
+ s->wicctrl = 0;
+}
+
+static void iotkit_sysctl_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ IoTKitSysCtl *s = IOTKIT_SYSCTL(obj);
+
+ memory_region_init_io(&s->iomem, obj, &iotkit_sysctl_ops,
+ s, "iotkit-sysctl", 0x1000);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription iotkit_sysctl_vmstate = {
+ .name = "iotkit-sysctl",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(secure_debug, IoTKitSysCtl),
+ VMSTATE_UINT32(reset_syndrome, IoTKitSysCtl),
+ VMSTATE_UINT32(reset_mask, IoTKitSysCtl),
+ VMSTATE_UINT32(gretreg, IoTKitSysCtl),
+ VMSTATE_UINT32(initsvrtor0, IoTKitSysCtl),
+ VMSTATE_UINT32(cpuwait, IoTKitSysCtl),
+ VMSTATE_UINT32(wicctrl, IoTKitSysCtl),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void iotkit_sysctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &iotkit_sysctl_vmstate;
+ dc->reset = iotkit_sysctl_reset;
+}
+
+static const TypeInfo iotkit_sysctl_info = {
+ .name = TYPE_IOTKIT_SYSCTL,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IoTKitSysCtl),
+ .instance_init = iotkit_sysctl_init,
+ .class_init = iotkit_sysctl_class_init,
+};
+
+static void iotkit_sysctl_register_types(void)
+{
+ type_register_static(&iotkit_sysctl_info);
+}
+
+type_init(iotkit_sysctl_register_types);
diff --git a/hw/misc/iotkit-sysinfo.c b/hw/misc/iotkit-sysinfo.c
new file mode 100644
index 0000000000..78955bc45f
--- /dev/null
+++ b/hw/misc/iotkit-sysinfo.c
@@ -0,0 +1,128 @@
+/*
+ * ARM IoTKit system information block
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/*
+ * This is a model of the "system information block" which is part of the
+ * Arm IoTKit and documented in
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * It consists of 2 read-only version/config registers, plus the
+ * usual ID registers.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/misc/iotkit-sysinfo.h"
+
+REG32(SYS_VERSION, 0x0)
+REG32(SYS_CONFIG, 0x4)
+REG32(PID4, 0xfd0)
+REG32(PID5, 0xfd4)
+REG32(PID6, 0xfd8)
+REG32(PID7, 0xfdc)
+REG32(PID0, 0xfe0)
+REG32(PID1, 0xfe4)
+REG32(PID2, 0xfe8)
+REG32(PID3, 0xfec)
+REG32(CID0, 0xff0)
+REG32(CID1, 0xff4)
+REG32(CID2, 0xff8)
+REG32(CID3, 0xffc)
+
+/* PID/CID values */
+static const int sysinfo_id[] = {
+ 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
+ 0x58, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
+ 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
+};
+
+static uint64_t iotkit_sysinfo_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ uint64_t r;
+
+ switch (offset) {
+ case A_SYS_VERSION:
+ r = 0x41743;
+ break;
+
+ case A_SYS_CONFIG:
+ r = 0x31;
+ break;
+ case A_PID4 ... A_CID3:
+ r = sysinfo_id[(offset - A_PID4) / 4];
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IoTKit SysInfo read: bad offset %x\n", (int)offset);
+ r = 0;
+ break;
+ }
+ trace_iotkit_sysinfo_read(offset, r, size);
+ return r;
+}
+
+static void iotkit_sysinfo_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ trace_iotkit_sysinfo_write(offset, value, size);
+
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IoTKit SysInfo: write to RO offset 0x%x\n", (int)offset);
+}
+
+static const MemoryRegionOps iotkit_sysinfo_ops = {
+ .read = iotkit_sysinfo_read,
+ .write = iotkit_sysinfo_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ /* byte/halfword accesses are just zero-padded on reads and writes */
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+};
+
+static void iotkit_sysinfo_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ IoTKitSysInfo *s = IOTKIT_SYSINFO(obj);
+
+ memory_region_init_io(&s->iomem, obj, &iotkit_sysinfo_ops,
+ s, "iotkit-sysinfo", 0x1000);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void iotkit_sysinfo_class_init(ObjectClass *klass, void *data)
+{
+ /*
+ * This device has no guest-modifiable state and so it
+ * does not need a reset function or VMState.
+ */
+}
+
+static const TypeInfo iotkit_sysinfo_info = {
+ .name = TYPE_IOTKIT_SYSINFO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IoTKitSysInfo),
+ .instance_init = iotkit_sysinfo_init,
+ .class_init = iotkit_sysinfo_class_init,
+};
+
+static void iotkit_sysinfo_register_types(void)
+{
+ type_register_static(&iotkit_sysinfo_info);
+}
+
+type_init(iotkit_sysinfo_register_types);
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
index 7394a057d8..5cf10ebd66 100644
--- a/hw/misc/mps2-fpgaio.c
+++ b/hw/misc/mps2-fpgaio.c
@@ -22,6 +22,7 @@
#include "hw/sysbus.h"
#include "hw/registerfields.h"
#include "hw/misc/mps2-fpgaio.h"
+#include "qemu/timer.h"
REG32(LED0, 0)
REG32(BUTTON, 8)
@@ -32,10 +33,92 @@ REG32(PRESCALE, 0x1c)
REG32(PSCNTR, 0x20)
REG32(MISC, 0x4c)
+static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq)
+{
+ return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND);
+}
+
+static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
+{
+ return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
+}
+
+static void resync_counter(MPS2FPGAIO *s)
+{
+ /*
+ * Update s->counter and s->pscntr to their true current values
+ * by calculating how many times PSCNTR has ticked since the
+ * last time we did a resync.
+ */
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ int64_t elapsed = now - s->pscntr_sync_ticks;
+
+ /*
+ * Round elapsed down to a whole number of PSCNTR ticks, so we don't
+ * lose time if we do multiple resyncs in a single tick.
+ */
+ uint64_t ticks = muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_SECOND);
+
+ /*
+ * Work out what PSCNTR and COUNTER have moved to. We assume that
+ * PSCNTR reloads from PRESCALE one tick-period after it hits zero,
+ * and that COUNTER increments at the same moment.
+ */
+ if (ticks == 0) {
+ /* We haven't ticked since the last time we were asked */
+ return;
+ } else if (ticks < s->pscntr) {
+ /* We haven't yet reached zero, just reduce the PSCNTR */
+ s->pscntr -= ticks;
+ } else {
+ if (s->prescale == 0) {
+ /*
+ * If the reload value is zero then the PSCNTR will stick
+ * at zero once it reaches it, and so we will increment
+ * COUNTER every tick after that.
+ */
+ s->counter += ticks - s->pscntr;
+ s->pscntr = 0;
+ } else {
+ /*
+ * This is the complicated bit. This ASCII art diagram gives an
+ * example with PRESCALE==5 PSCNTR==7:
+ *
+ * ticks 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+ * PSCNTR 7 6 5 4 3 2 1 0 5 4 3 2 1 0 5
+ * cinc 1 2
+ * y 0 1 2 3 4 5 6 7 8 9 10 11 12
+ * x 0 1 2 3 4 5 0 1 2 3 4 5 0
+ *
+ * where x = y % (s->prescale + 1)
+ * and so PSCNTR = s->prescale - x
+ * and COUNTER is incremented by y / (s->prescale + 1)
+ *
+ * The case where PSCNTR < PRESCALE works out the same,
+ * though we must be careful to calculate y as 64-bit unsigned
+ * for all parts of the expression.
+ * y < 0 is not possible because that implies ticks < s->pscntr.
+ */
+ uint64_t y = ticks - s->pscntr + s->prescale;
+ s->pscntr = s->prescale - (y % (s->prescale + 1));
+ s->counter += y / (s->prescale + 1);
+ }
+ }
+
+ /*
+ * Only advance the sync time to the timestamp of the last PSCNTR tick,
+ * not all the way to 'now', so we don't lose time if we do multiple
+ * resyncs in a single tick.
+ */
+ s->pscntr_sync_ticks += muldiv64(ticks, NANOSECONDS_PER_SECOND,
+ s->prescale_clk);
+}
+
static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
{
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
uint64_t r;
+ int64_t now;
switch (offset) {
case A_LED0:
@@ -54,12 +137,20 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
r = s->misc;
break;
case A_CLK1HZ:
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ r = counter_from_tickoff(now, s->clk1hz_tick_offset, 1);
+ break;
case A_CLK100HZ:
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
+ break;
case A_COUNTER:
+ resync_counter(s);
+ r = s->counter;
+ break;
case A_PSCNTR:
- /* These are all upcounters of various frequencies. */
- qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
- r = 0;
+ resync_counter(s);
+ r = s->pscntr;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
@@ -76,6 +167,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
+ int64_t now;
trace_mps2_fpgaio_write(offset, value, size);
@@ -89,6 +181,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
s->led0 = value & 0x3;
break;
case A_PRESCALE:
+ resync_counter(s);
s->prescale = value;
break;
case A_MISC:
@@ -100,6 +193,22 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
"MPS2 FPGAIO: MISC control bits unimplemented\n");
s->misc = value;
break;
+ case A_CLK1HZ:
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ s->clk1hz_tick_offset = tickoff_from_counter(now, value, 1);
+ break;
+ case A_CLK100HZ:
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
+ break;
+ case A_COUNTER:
+ resync_counter(s);
+ s->counter = value;
+ break;
+ case A_PSCNTR:
+ resync_counter(s);
+ s->pscntr = value;
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
@@ -116,11 +225,17 @@ static const MemoryRegionOps mps2_fpgaio_ops = {
static void mps2_fpgaio_reset(DeviceState *dev)
{
MPS2FPGAIO *s = MPS2_FPGAIO(dev);
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
trace_mps2_fpgaio_reset();
s->led0 = 0;
s->prescale = 0;
s->misc = 0;
+ s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
+ s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
+ s->counter = 0;
+ s->pscntr = 0;
+ s->pscntr_sync_ticks = now;
}
static void mps2_fpgaio_init(Object *obj)
@@ -133,6 +248,27 @@ static void mps2_fpgaio_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
}
+static bool mps2_fpgaio_counters_needed(void *opaque)
+{
+ /* Currently vmstate.c insists all subsections have a 'needed' function */
+ return true;
+}
+
+static const VMStateDescription mps2_fpgaio_counters_vmstate = {
+ .name = "mps2-fpgaio/counters",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .needed = mps2_fpgaio_counters_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
+ VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
+ VMSTATE_UINT32(counter, MPS2FPGAIO),
+ VMSTATE_UINT32(pscntr, MPS2FPGAIO),
+ VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription mps2_fpgaio_vmstate = {
.name = "mps2-fpgaio",
.version_id = 1,
@@ -142,6 +278,10 @@ static const VMStateDescription mps2_fpgaio_vmstate = {
VMSTATE_UINT32(prescale, MPS2FPGAIO),
VMSTATE_UINT32(misc, MPS2FPGAIO),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription*[]) {
+ &mps2_fpgaio_counters_vmstate,
+ NULL
}
};
diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c
index b26250dec9..9d8961ba0c 100644
--- a/hw/misc/pvpanic.c
+++ b/hw/misc/pvpanic.c
@@ -99,17 +99,6 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
isa_register_ioport(d, &s->io, s->ioport);
}
-#define PVPANIC_IOPORT_PROP "ioport"
-
-uint16_t pvpanic_port(void)
-{
- Object *o = object_resolve_path_type("", TYPE_PVPANIC, NULL);
- if (!o) {
- return 0;
- }
- return object_property_get_uint(o, PVPANIC_IOPORT_PROP, NULL);
-}
-
static Property pvpanic_isa_properties[] = {
DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicState, ioport, 0x505),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 1341508b33..52466c77c4 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -92,6 +92,15 @@ tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secur
tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s"
tz_mpc_iommu_notify(uint64_t addr) "TZ MPC iommu: notifying UNMAP/MAP for 0x%" PRIx64
+# hw/misc/tz-msc.c
+tz_msc_reset(void) "TZ MSC: reset"
+tz_msc_cfg_nonsec(int level) "TZ MSC: cfg_nonsec = %d"
+tz_msc_cfg_sec_resp(int level) "TZ MSC: cfg_sec_resp = %d"
+tz_msc_irq_enable(int level) "TZ MSC: int_enable = %d"
+tz_msc_irq_clear(int level) "TZ MSC: int_clear = %d"
+tz_msc_update_irq(int level) "TZ MSC: setting irq line to %d"
+tz_msc_access_blocked(uint64_t offset) "TZ MSC: offset 0x%" PRIx64 " access blocked"
+
# hw/misc/tz-ppc.c
tz_ppc_reset(void) "TZ PPC: reset"
tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d"
@@ -116,3 +125,10 @@ ccm_freq(uint32_t freq) "freq = %d\n"
ccm_clock_freq(uint32_t clock, uint32_t freq) "(Clock = %d) = %d\n"
ccm_read_reg(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32 "\n"
ccm_write_reg(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32 "\n"
+
+# hw/misc/iotkit-sysctl.c
+iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+iotkit_sysinfo_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+iotkit_sysctl_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+iotkit_sysctl_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+iotkit_sysctl_reset(void) "IoTKit SysCtl: reset"
diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c
new file mode 100644
index 0000000000..9e352044ea
--- /dev/null
+++ b/hw/misc/tz-msc.c
@@ -0,0 +1,308 @@
+/*
+ * ARM TrustZone master security controller emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/misc/tz-msc.h"
+
+static void tz_msc_update_irq(TZMSC *s)
+{
+ bool level = s->irq_status;
+
+ trace_tz_msc_update_irq(level);
+ qemu_set_irq(s->irq, level);
+}
+
+static void tz_msc_cfg_nonsec(void *opaque, int n, int level)
+{
+ TZMSC *s = TZ_MSC(opaque);
+
+ trace_tz_msc_cfg_nonsec(level);
+ s->cfg_nonsec = level;
+}
+
+static void tz_msc_cfg_sec_resp(void *opaque, int n, int level)
+{
+ TZMSC *s = TZ_MSC(opaque);
+
+ trace_tz_msc_cfg_sec_resp(level);
+ s->cfg_sec_resp = level;
+}
+
+static void tz_msc_irq_clear(void *opaque, int n, int level)
+{
+ TZMSC *s = TZ_MSC(opaque);
+
+ trace_tz_msc_irq_clear(level);
+
+ s->irq_clear = level;
+ if (level) {
+ s->irq_status = false;
+ tz_msc_update_irq(s);
+ }
+}
+
+/* The MSC may either block a transaction by aborting it, block a
+ * transaction by making it RAZ/WI, allow it through with
+ * MemTxAttrs indicating a secure transaction, or allow it with
+ * MemTxAttrs indicating a non-secure transaction.
+ */
+typedef enum MSCAction {
+ MSCBlockAbort,
+ MSCBlockRAZWI,
+ MSCAllowSecure,
+ MSCAllowNonSecure,
+} MSCAction;
+
+static MSCAction tz_msc_check(TZMSC *s, hwaddr addr)
+{
+ /*
+ * Check whether to allow an access from the bus master, returning
+ * an MSCAction indicating the required behaviour. If the transaction
+ * is blocked, the caller must check cfg_sec_resp to determine
+ * whether to abort or RAZ/WI the transaction.
+ */
+ IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(s->idau);
+ IDAUInterface *ii = IDAU_INTERFACE(s->idau);
+ bool idau_exempt = false, idau_ns = true, idau_nsc = true;
+ int idau_region = IREGION_NOTVALID;
+
+ iic->check(ii, addr, &idau_region, &idau_exempt, &idau_ns, &idau_nsc);
+
+ if (idau_exempt) {
+ /*
+ * Uncheck region -- OK, transaction type depends on
+ * whether bus master is configured as Secure or NonSecure
+ */
+ return s->cfg_nonsec ? MSCAllowNonSecure : MSCAllowSecure;
+ }
+
+ if (idau_ns) {
+ /* NonSecure region -- always forward as NS transaction */
+ return MSCAllowNonSecure;
+ }
+
+ if (!s->cfg_nonsec) {
+ /* Access to Secure region by Secure bus master: OK */
+ return MSCAllowSecure;
+ }
+
+ /* Attempted access to Secure region by NS bus master: block */
+ trace_tz_msc_access_blocked(addr);
+ if (!s->cfg_sec_resp) {
+ return MSCBlockRAZWI;
+ }
+
+ /*
+ * The TRM isn't clear on behaviour if irq_clear is high when a
+ * transaction is blocked. We assume that the MSC behaves like the
+ * PPC, where holding irq_clear high suppresses the interrupt.
+ */
+ if (!s->irq_clear) {
+ s->irq_status = true;
+ tz_msc_update_irq(s);
+ }
+ return MSCBlockAbort;
+}
+
+static MemTxResult tz_msc_read(void *opaque, hwaddr addr, uint64_t *pdata,
+ unsigned size, MemTxAttrs attrs)
+{
+ TZMSC *s = opaque;
+ AddressSpace *as = &s->downstream_as;
+ uint64_t data;
+ MemTxResult res;
+
+ switch (tz_msc_check(s, addr)) {
+ case MSCBlockAbort:
+ return MEMTX_ERROR;
+ case MSCBlockRAZWI:
+ *pdata = 0;
+ return MEMTX_OK;
+ case MSCAllowSecure:
+ attrs.secure = 1;
+ attrs.unspecified = 0;
+ break;
+ case MSCAllowNonSecure:
+ attrs.secure = 0;
+ attrs.unspecified = 0;
+ break;
+ }
+
+ switch (size) {
+ case 1:
+ data = address_space_ldub(as, addr, attrs, &res);
+ break;
+ case 2:
+ data = address_space_lduw_le(as, addr, attrs, &res);
+ break;
+ case 4:
+ data = address_space_ldl_le(as, addr, attrs, &res);
+ break;
+ case 8:
+ data = address_space_ldq_le(as, addr, attrs, &res);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ *pdata = data;
+ return res;
+}
+
+static MemTxResult tz_msc_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size, MemTxAttrs attrs)
+{
+ TZMSC *s = opaque;
+ AddressSpace *as = &s->downstream_as;
+ MemTxResult res;
+
+ switch (tz_msc_check(s, addr)) {
+ case MSCBlockAbort:
+ return MEMTX_ERROR;
+ case MSCBlockRAZWI:
+ return MEMTX_OK;
+ case MSCAllowSecure:
+ attrs.secure = 1;
+ attrs.unspecified = 0;
+ break;
+ case MSCAllowNonSecure:
+ attrs.secure = 0;
+ attrs.unspecified = 0;
+ break;
+ }
+
+ switch (size) {
+ case 1:
+ address_space_stb(as, addr, val, attrs, &res);
+ break;
+ case 2:
+ address_space_stw_le(as, addr, val, attrs, &res);
+ break;
+ case 4:
+ address_space_stl_le(as, addr, val, attrs, &res);
+ break;
+ case 8:
+ address_space_stq_le(as, addr, val, attrs, &res);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return res;
+}
+
+static const MemoryRegionOps tz_msc_ops = {
+ .read_with_attrs = tz_msc_read,
+ .write_with_attrs = tz_msc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void tz_msc_reset(DeviceState *dev)
+{
+ TZMSC *s = TZ_MSC(dev);
+
+ trace_tz_msc_reset();
+ s->cfg_sec_resp = false;
+ s->cfg_nonsec = false;
+ s->irq_clear = 0;
+ s->irq_status = 0;
+}
+
+static void tz_msc_init(Object *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+ TZMSC *s = TZ_MSC(obj);
+
+ qdev_init_gpio_in_named(dev, tz_msc_cfg_nonsec, "cfg_nonsec", 1);
+ qdev_init_gpio_in_named(dev, tz_msc_cfg_sec_resp, "cfg_sec_resp", 1);
+ qdev_init_gpio_in_named(dev, tz_msc_irq_clear, "irq_clear", 1);
+ qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
+}
+
+static void tz_msc_realize(DeviceState *dev, Error **errp)
+{
+ Object *obj = OBJECT(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ TZMSC *s = TZ_MSC(dev);
+ const char *name = "tz-msc-downstream";
+ uint64_t size;
+
+ /*
+ * We can't create the upstream end of the port until realize,
+ * as we don't know the size of the MR used as the downstream until then.
+ * We insist on having a downstream, to avoid complicating the
+ * code with handling the "don't know how big this is" case. It's easy
+ * enough for the user to create an unimplemented_device as downstream
+ * if they have nothing else to plug into this.
+ */
+ if (!s->downstream) {
+ error_setg(errp, "MSC 'downstream' link not set");
+ return;
+ }
+ if (!s->idau) {
+ error_setg(errp, "MSC 'idau' link not set");
+ return;
+ }
+
+ size = memory_region_size(s->downstream);
+ address_space_init(&s->downstream_as, s->downstream, name);
+ memory_region_init_io(&s->upstream, obj, &tz_msc_ops, s, name, size);
+ sysbus_init_mmio(sbd, &s->upstream);
+}
+
+static const VMStateDescription tz_msc_vmstate = {
+ .name = "tz-msc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(cfg_nonsec, TZMSC),
+ VMSTATE_BOOL(cfg_sec_resp, TZMSC),
+ VMSTATE_BOOL(irq_clear, TZMSC),
+ VMSTATE_BOOL(irq_status, TZMSC),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property tz_msc_properties[] = {
+ DEFINE_PROP_LINK("downstream", TZMSC, downstream,
+ TYPE_MEMORY_REGION, MemoryRegion *),
+ DEFINE_PROP_LINK("idau", TZMSC, idau,
+ TYPE_IDAU_INTERFACE, IDAUInterface *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tz_msc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = tz_msc_realize;
+ dc->vmsd = &tz_msc_vmstate;
+ dc->reset = tz_msc_reset;
+ dc->props = tz_msc_properties;
+}
+
+static const TypeInfo tz_msc_info = {
+ .name = TYPE_TZ_MSC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TZMSC),
+ .instance_init = tz_msc_init,
+ .class_init = tz_msc_class_init,
+};
+
+static void tz_msc_register_types(void)
+{
+ type_register_static(&tz_msc_info);
+}
+
+type_init(tz_msc_register_types);
diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c
index a2805527cb..304c6287c7 100644
--- a/hw/misc/vmcoreinfo.c
+++ b/hw/misc/vmcoreinfo.c
@@ -19,7 +19,7 @@ static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len)
VMCoreInfoState *s = VMCOREINFO(dev);
s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo)
- && s->vmcoreinfo.guest_format != VMCOREINFO_FORMAT_NONE;
+ && s->vmcoreinfo.guest_format != FW_CFG_VMCOREINFO_FORMAT_NONE;
}
static void vmcoreinfo_reset(void *dev)
@@ -28,7 +28,7 @@ static void vmcoreinfo_reset(void *dev)
s->has_vmcoreinfo = false;
memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo));
- s->vmcoreinfo.host_format = cpu_to_le16(VMCOREINFO_FORMAT_ELF);
+ s->vmcoreinfo.host_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF);
}
static void vmcoreinfo_realize(DeviceState *dev, Error **errp)
@@ -53,7 +53,7 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp)
return;
}
- fw_cfg_add_file_callback(fw_cfg, "etc/vmcoreinfo",
+ fw_cfg_add_file_callback(fw_cfg, FW_CFG_VMCOREINFO_FILENAME,
NULL, fw_cfg_vmci_write, s,
&s->vmcoreinfo, sizeof(s->vmcoreinfo), false);
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 47146ba12a..162b27a3b8 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -608,6 +608,9 @@ static int prep_set_cmos_checksum(DeviceState *dev, void *opaque)
rtc_set_memory(rtc, 0x3e, checksum & 0xff);
rtc_set_memory(rtc, 0x2f, checksum >> 8);
rtc_set_memory(rtc, 0x3f, checksum >> 8);
+
+ object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(rtc),
+ "date", NULL);
}
return 0;
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index ddd4478a34..4edb6c7d16 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -562,9 +562,12 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
{
+ CPUState **rev;
CPUState *cs;
+ int n_cpus;
int cpus_offset;
char *nodename;
+ int i;
cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
_FDT(cpus_offset);
@@ -575,8 +578,19 @@ static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
* We walk the CPUs in reverse order to ensure that CPU DT nodes
* created by fdt_add_subnode() end up in the right order in FDT
* for the guest kernel the enumerate the CPUs correctly.
+ *
+ * The CPU list cannot be traversed in reverse order, so we need
+ * to do extra work.
*/
- CPU_FOREACH_REVERSE(cs) {
+ n_cpus = 0;
+ rev = NULL;
+ CPU_FOREACH(cs) {
+ rev = g_renew(CPUState *, rev, n_cpus + 1);
+ rev[n_cpus++] = cs;
+ }
+
+ for (i = n_cpus - 1; i >= 0; i--) {
+ CPUState *cs = rev[i];
PowerPCCPU *cpu = POWERPC_CPU(cs);
int index = spapr_get_vcpu_id(cpu);
DeviceClass *dc = DEVICE_GET_CLASS(cs);
@@ -3113,13 +3127,12 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
PCDIMMDevice *dimm = PC_DIMM(dev);
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
- uint64_t align, size, addr;
+ uint64_t size, addr;
uint32_t node;
- align = memory_region_get_alignment(mr);
size = memory_region_size(mr);
- pc_dimm_plug(dev, MACHINE(ms), align, &local_err);
+ pc_dimm_plug(dev, MACHINE(ms), &local_err);
if (local_err) {
goto out;
}
@@ -3154,6 +3167,7 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev);
PCDIMMDevice *dimm = PC_DIMM(dev);
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
+ Error *local_err = NULL;
MemoryRegion *mr;
uint64_t size;
Object *memdev;
@@ -3179,7 +3193,13 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
memdev = object_property_get_link(OBJECT(dimm), PC_DIMM_MEMDEV_PROP,
&error_abort);
pagesize = host_memory_backend_pagesize(MEMORY_BACKEND(memdev));
- spapr_check_pagesize(spapr, pagesize, errp);
+ spapr_check_pagesize(spapr, pagesize, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ pc_dimm_pre_plug(dev, MACHINE(hotplug_dev), NULL, errp);
}
struct sPAPRDIMMState {
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 160657f4b9..955ba94800 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -959,6 +959,10 @@ static void lsi_do_msgout(LSIState *s)
DPRINTF("WDTR (ignored)\n");
lsi_skip_msgbytes(s, 1);
break;
+ case 4:
+ DPRINTF("PPR (ignored)\n");
+ lsi_skip_msgbytes(s, 5);
+ break;
default:
goto bad;
}
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index ba1afa3c1e..a56317e026 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -464,6 +464,7 @@ static void megasas_unmap_frame(MegasasState *s, MegasasCmd *cmd)
cmd->frame = NULL;
cmd->pa = 0;
cmd->pa_size = 0;
+ qemu_sglist_destroy(&cmd->qsg);
clear_bit(cmd->index, s->frame_map);
}
@@ -580,7 +581,6 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
static void megasas_complete_command(MegasasCmd *cmd)
{
- qemu_sglist_destroy(&cmd->qsg);
cmd->iov_size = 0;
cmd->iov_offset = 0;
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index 4176e871e1..929404fb48 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -1431,6 +1431,7 @@ static void mptsas1068_class_init(ObjectClass *oc, void *data)
dc->reset = mptsas_reset;
dc->vmsd = &vmstate_mptsas;
dc->desc = "LSI SAS 1068";
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
static const TypeInfo mptsas_info = {
diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c
index e2a5828af1..b7fbab65dd 100644
--- a/hw/scsi/vhost-scsi-common.c
+++ b/hw/scsi/vhost-scsi-common.c
@@ -96,6 +96,9 @@ uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features,
{
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev);
+ /* Turn on predefined features supported by this device */
+ features |= vsc->host_features;
+
return vhost_get_features(&vsc->dev, vsc->feature_bits, features);
}
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 9c1bea8ff3..becf550085 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -238,6 +238,9 @@ static Property vhost_scsi_properties[] = {
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
0xFFFF),
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
+ DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
+ VIRTIO_SCSI_F_T10_PI,
+ false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c
index 9355cfdf07..2e1ba4a87b 100644
--- a/hw/scsi/vhost-user-scsi.c
+++ b/hw/scsi/vhost-user-scsi.c
@@ -137,17 +137,6 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp)
}
}
-static uint64_t vhost_user_scsi_get_features(VirtIODevice *vdev,
- uint64_t features, Error **errp)
-{
- VHostUserSCSI *s = VHOST_USER_SCSI(vdev);
-
- /* Turn on predefined features supported by this device */
- features |= s->host_features;
-
- return vhost_scsi_common_get_features(vdev, features, errp);
-}
-
static Property vhost_user_scsi_properties[] = {
DEFINE_PROP_CHR("chardev", VirtIOSCSICommon, conf.chardev),
DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
@@ -157,12 +146,15 @@ static Property vhost_user_scsi_properties[] = {
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
0xFFFF),
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
- DEFINE_PROP_BIT64("hotplug", VHostUserSCSI, host_features,
- VIRTIO_SCSI_F_HOTPLUG,
- true),
- DEFINE_PROP_BIT64("param_change", VHostUserSCSI, host_features,
- VIRTIO_SCSI_F_CHANGE,
- true),
+ DEFINE_PROP_BIT64("hotplug", VHostSCSICommon, host_features,
+ VIRTIO_SCSI_F_HOTPLUG,
+ true),
+ DEFINE_PROP_BIT64("param_change", VHostSCSICommon, host_features,
+ VIRTIO_SCSI_F_CHANGE,
+ true),
+ DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
+ VIRTIO_SCSI_F_T10_PI,
+ false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -187,7 +179,7 @@ static void vhost_user_scsi_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
vdc->realize = vhost_user_scsi_realize;
vdc->unrealize = vhost_user_scsi_unrealize;
- vdc->get_features = vhost_user_scsi_get_features;
+ vdc->get_features = vhost_scsi_common_get_features;
vdc->set_config = vhost_scsi_common_set_config;
vdc->set_status = vhost_user_scsi_set_status;
fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
index c1368018ee..e58247554c 100644
--- a/hw/ssi/pl022.c
+++ b/hw/ssi/pl022.c
@@ -9,6 +9,7 @@
#include "qemu/osdep.h"
#include "hw/sysbus.h"
+#include "hw/ssi/pl022.h"
#include "hw/ssi/ssi.h"
#include "qemu/log.h"
@@ -37,35 +38,10 @@ do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
#define PL022_SR_BSY 0x10
#define PL022_INT_ROR 0x01
-#define PL022_INT_RT 0x04
+#define PL022_INT_RT 0x02
#define PL022_INT_RX 0x04
#define PL022_INT_TX 0x08
-#define TYPE_PL022 "pl022"
-#define PL022(obj) OBJECT_CHECK(PL022State, (obj), TYPE_PL022)
-
-typedef struct PL022State {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t cr0;
- uint32_t cr1;
- uint32_t bitmask;
- uint32_t sr;
- uint32_t cpsr;
- uint32_t is;
- uint32_t im;
- /* The FIFO head points to the next empty entry. */
- int tx_fifo_head;
- int rx_fifo_head;
- int tx_fifo_len;
- int rx_fifo_len;
- uint16_t tx_fifo[8];
- uint16_t rx_fifo[8];
- qemu_irq irq;
- SSIBus *ssi;
-} PL022State;
-
static const unsigned char pl022_id[8] =
{ 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
@@ -170,7 +146,7 @@ static uint64_t pl022_read(void *opaque, hwaddr offset,
return s->is;
case 0x1c: /* MIS */
return s->im & s->is;
- case 0x20: /* DMACR */
+ case 0x24: /* DMACR */
/* Not implemented. */
return 0;
default:
@@ -216,7 +192,15 @@ static void pl022_write(void *opaque, hwaddr offset,
s->im = value;
pl022_update(s);
break;
- case 0x20: /* DMACR */
+ case 0x20: /* ICR */
+ /*
+ * write-1-to-clear: bit 0 clears ROR, bit 1 clears RT;
+ * RX and TX interrupts cannot be cleared this way.
+ */
+ value &= PL022_INT_ROR | PL022_INT_RT;
+ s->is &= ~value;
+ break;
+ case 0x24: /* DMACR */
if (value) {
qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n");
}
@@ -227,8 +211,10 @@ static void pl022_write(void *opaque, hwaddr offset,
}
}
-static void pl022_reset(PL022State *s)
+static void pl022_reset(DeviceState *dev)
{
+ PL022State *s = PL022(dev);
+
s->rx_fifo_len = 0;
s->tx_fifo_len = 0;
s->im = 0;
@@ -292,25 +278,24 @@ static const VMStateDescription vmstate_pl022 = {
}
};
-static int pl022_init(SysBusDevice *sbd)
+static void pl022_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
PL022State *s = PL022(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &pl022_ops, s, "pl022", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
s->ssi = ssi_create_bus(dev, "ssi");
- pl022_reset(s);
- vmstate_register(dev, -1, &vmstate_pl022, s);
- return 0;
}
static void pl022_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = pl022_init;
+ dc->reset = pl022_reset;
+ dc->vmsd = &vmstate_pl022;
+ dc->realize = pl022_realize;
}
static const TypeInfo pl022_info = {
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index e16b2b913c..b32194d153 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -44,4 +44,5 @@ common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
+common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) += cmsdk-apb-dualtimer.o
common-obj-$(CONFIG_MSF2) += mss-timer.o
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
new file mode 100644
index 0000000000..ccd49753b7
--- /dev/null
+++ b/hw/timer/cmsdk-apb-dualtimer.c
@@ -0,0 +1,515 @@
+/*
+ * ARM CMSDK APB dual-timer emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/*
+ * This is a model of the "APB dual-input timer" which is part of the Cortex-M
+ * System Design Kit (CMSDK) and documented in the Cortex-M System
+ * Design Kit Technical Reference Manual (ARM DDI0479C):
+ * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "qemu/main-loop.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/timer/cmsdk-apb-dualtimer.h"
+
+REG32(TIMER1LOAD, 0x0)
+REG32(TIMER1VALUE, 0x4)
+REG32(TIMER1CONTROL, 0x8)
+ FIELD(CONTROL, ONESHOT, 0, 1)
+ FIELD(CONTROL, SIZE, 1, 1)
+ FIELD(CONTROL, PRESCALE, 2, 2)
+ FIELD(CONTROL, INTEN, 5, 1)
+ FIELD(CONTROL, MODE, 6, 1)
+ FIELD(CONTROL, ENABLE, 7, 1)
+#define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
+ R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
+ R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
+REG32(TIMER1INTCLR, 0xc)
+REG32(TIMER1RIS, 0x10)
+REG32(TIMER1MIS, 0x14)
+REG32(TIMER1BGLOAD, 0x18)
+REG32(TIMER2LOAD, 0x20)
+REG32(TIMER2VALUE, 0x24)
+REG32(TIMER2CONTROL, 0x28)
+REG32(TIMER2INTCLR, 0x2c)
+REG32(TIMER2RIS, 0x30)
+REG32(TIMER2MIS, 0x34)
+REG32(TIMER2BGLOAD, 0x38)
+REG32(TIMERITCR, 0xf00)
+ FIELD(TIMERITCR, ENABLE, 0, 1)
+#define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
+REG32(TIMERITOP, 0xf04)
+ FIELD(TIMERITOP, TIMINT1, 0, 1)
+ FIELD(TIMERITOP, TIMINT2, 1, 1)
+#define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
+ R_TIMERITOP_TIMINT2_MASK)
+REG32(PID4, 0xfd0)
+REG32(PID5, 0xfd4)
+REG32(PID6, 0xfd8)
+REG32(PID7, 0xfdc)
+REG32(PID0, 0xfe0)
+REG32(PID1, 0xfe4)
+REG32(PID2, 0xfe8)
+REG32(PID3, 0xfec)
+REG32(CID0, 0xff0)
+REG32(CID1, 0xff4)
+REG32(CID2, 0xff8)
+REG32(CID3, 0xffc)
+
+/* PID/CID values */
+static const int timer_id[] = {
+ 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
+ 0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
+ 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
+};
+
+static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule *m)
+{
+ /* Return masked interrupt status for the timer module */
+ return m->intstatus && (m->control & R_CONTROL_INTEN_MASK);
+}
+
+static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s)
+{
+ bool timint1, timint2, timintc;
+
+ if (s->timeritcr) {
+ /* Integration test mode: outputs driven directly from TIMERITOP bits */
+ timint1 = s->timeritop & R_TIMERITOP_TIMINT1_MASK;
+ timint2 = s->timeritop & R_TIMERITOP_TIMINT2_MASK;
+ } else {
+ timint1 = cmsdk_dualtimermod_intstatus(&s->timermod[0]);
+ timint2 = cmsdk_dualtimermod_intstatus(&s->timermod[1]);
+ }
+
+ timintc = timint1 || timint2;
+
+ qemu_set_irq(s->timermod[0].timerint, timint1);
+ qemu_set_irq(s->timermod[1].timerint, timint2);
+ qemu_set_irq(s->timerintc, timintc);
+}
+
+static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
+ uint32_t newctrl)
+{
+ /* Handle a write to the CONTROL register */
+ uint32_t changed;
+
+ newctrl &= R_CONTROL_VALID_MASK;
+
+ changed = m->control ^ newctrl;
+
+ if (changed & ~newctrl & R_CONTROL_ENABLE_MASK) {
+ /* ENABLE cleared, stop timer before any further changes */
+ ptimer_stop(m->timer);
+ }
+
+ if (changed & R_CONTROL_PRESCALE_MASK) {
+ int divisor;
+
+ switch (FIELD_EX32(newctrl, CONTROL, PRESCALE)) {
+ case 0:
+ divisor = 1;
+ break;
+ case 1:
+ divisor = 16;
+ break;
+ case 2:
+ divisor = 256;
+ break;
+ case 3:
+ /* UNDEFINED; complain, and arbitrarily treat like 2 */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
+ " is undefined behaviour\n");
+ divisor = 256;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ ptimer_set_freq(m->timer, m->parent->pclk_frq / divisor);
+ }
+
+ if (changed & R_CONTROL_MODE_MASK) {
+ uint32_t load;
+ if (newctrl & R_CONTROL_MODE_MASK) {
+ /* Periodic: the limit is the LOAD register value */
+ load = m->load;
+ } else {
+ /* Free-running: counter wraps around */
+ load = ptimer_get_limit(m->timer);
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
+ load = deposit32(m->load, 0, 16, load);
+ }
+ m->load = load;
+ load = 0xffffffff;
+ }
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
+ load &= 0xffff;
+ }
+ ptimer_set_limit(m->timer, load, 0);
+ }
+
+ if (changed & R_CONTROL_SIZE_MASK) {
+ /* Timer switched between 16 and 32 bit count */
+ uint32_t value, load;
+
+ value = ptimer_get_count(m->timer);
+ load = ptimer_get_limit(m->timer);
+ if (newctrl & R_CONTROL_SIZE_MASK) {
+ /* 16 -> 32, top half of VALUE is in struct field */
+ value = deposit32(m->value, 0, 16, value);
+ } else {
+ /* 32 -> 16: save top half to struct field and truncate */
+ m->value = value;
+ value &= 0xffff;
+ }
+
+ if (newctrl & R_CONTROL_MODE_MASK) {
+ /* Periodic, timer limit has LOAD value */
+ if (newctrl & R_CONTROL_SIZE_MASK) {
+ load = deposit32(m->load, 0, 16, load);
+ } else {
+ m->load = load;
+ load &= 0xffff;
+ }
+ } else {
+ /* Free-running, timer limit is set to give wraparound */
+ if (newctrl & R_CONTROL_SIZE_MASK) {
+ load = 0xffffffff;
+ } else {
+ load = 0xffff;
+ }
+ }
+ ptimer_set_count(m->timer, value);
+ ptimer_set_limit(m->timer, load, 0);
+ }
+
+ if (newctrl & R_CONTROL_ENABLE_MASK) {
+ /*
+ * ENABLE is set; start the timer after all other changes.
+ * We start it even if the ENABLE bit didn't actually change,
+ * in case the timer was an expired one-shot timer that has
+ * now been changed into a free-running or periodic timer.
+ */
+ ptimer_run(m->timer, !!(newctrl & R_CONTROL_ONESHOT_MASK));
+ }
+
+ m->control = newctrl;
+}
+
+static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
+ uint64_t r;
+
+ if (offset >= A_TIMERITCR) {
+ switch (offset) {
+ case A_TIMERITCR:
+ r = s->timeritcr;
+ break;
+ case A_PID4 ... A_CID3:
+ r = timer_id[(offset - A_PID4) / 4];
+ break;
+ default:
+ bad_offset:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CMSDK APB dual-timer read: bad offset %x\n",
+ (int) offset);
+ r = 0;
+ break;
+ }
+ } else {
+ int timer = offset >> 5;
+ CMSDKAPBDualTimerModule *m;
+
+ if (timer >= ARRAY_SIZE(s->timermod)) {
+ goto bad_offset;
+ }
+
+ m = &s->timermod[timer];
+
+ switch (offset & 0x1F) {
+ case A_TIMER1LOAD:
+ case A_TIMER1BGLOAD:
+ if (m->control & R_CONTROL_MODE_MASK) {
+ /*
+ * Periodic: the ptimer limit is the LOAD register value, (or
+ * just the low 16 bits of it if the timer is in 16-bit mode)
+ */
+ r = ptimer_get_limit(m->timer);
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
+ r = deposit32(m->load, 0, 16, r);
+ }
+ } else {
+ /* Free-running: LOAD register value is just in m->load */
+ r = m->load;
+ }
+ break;
+ case A_TIMER1VALUE:
+ r = ptimer_get_count(m->timer);
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
+ r = deposit32(m->value, 0, 16, r);
+ }
+ break;
+ case A_TIMER1CONTROL:
+ r = m->control;
+ break;
+ case A_TIMER1RIS:
+ r = m->intstatus;
+ break;
+ case A_TIMER1MIS:
+ r = cmsdk_dualtimermod_intstatus(m);
+ break;
+ default:
+ goto bad_offset;
+ }
+ }
+
+ trace_cmsdk_apb_dualtimer_read(offset, r, size);
+ return r;
+}
+
+static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
+
+ trace_cmsdk_apb_dualtimer_write(offset, value, size);
+
+ if (offset >= A_TIMERITCR) {
+ switch (offset) {
+ case A_TIMERITCR:
+ s->timeritcr = value & R_TIMERITCR_VALID_MASK;
+ cmsdk_apb_dualtimer_update(s);
+ case A_TIMERITOP:
+ s->timeritop = value & R_TIMERITOP_VALID_MASK;
+ cmsdk_apb_dualtimer_update(s);
+ default:
+ bad_offset:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CMSDK APB dual-timer write: bad offset %x\n",
+ (int) offset);
+ break;
+ }
+ } else {
+ int timer = offset >> 5;
+ CMSDKAPBDualTimerModule *m;
+
+ if (timer >= ARRAY_SIZE(s->timermod)) {
+ goto bad_offset;
+ }
+
+ m = &s->timermod[timer];
+
+ switch (offset & 0x1F) {
+ case A_TIMER1LOAD:
+ /* Set the limit, and immediately reload the count from it */
+ m->load = value;
+ m->value = value;
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
+ value &= 0xffff;
+ }
+ if (!(m->control & R_CONTROL_MODE_MASK)) {
+ /*
+ * In free-running mode this won't set the limit but will
+ * still change the current count value.
+ */
+ ptimer_set_count(m->timer, value);
+ } else {
+ if (!value) {
+ ptimer_stop(m->timer);
+ }
+ ptimer_set_limit(m->timer, value, 1);
+ if (value && (m->control & R_CONTROL_ENABLE_MASK)) {
+ /* Force possibly-expired oneshot timer to restart */
+ ptimer_run(m->timer, 1);
+ }
+ }
+ break;
+ case A_TIMER1BGLOAD:
+ /* Set the limit, but not the current count */
+ m->load = value;
+ if (!(m->control & R_CONTROL_MODE_MASK)) {
+ /* In free-running mode there is no limit */
+ break;
+ }
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
+ value &= 0xffff;
+ }
+ ptimer_set_limit(m->timer, value, 0);
+ break;
+ case A_TIMER1CONTROL:
+ cmsdk_dualtimermod_write_control(m, value);
+ cmsdk_apb_dualtimer_update(s);
+ break;
+ case A_TIMER1INTCLR:
+ m->intstatus = 0;
+ cmsdk_apb_dualtimer_update(s);
+ break;
+ default:
+ goto bad_offset;
+ }
+ }
+}
+
+static const MemoryRegionOps cmsdk_apb_dualtimer_ops = {
+ .read = cmsdk_apb_dualtimer_read,
+ .write = cmsdk_apb_dualtimer_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ /* byte/halfword accesses are just zero-padded on reads and writes */
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+};
+
+static void cmsdk_dualtimermod_tick(void *opaque)
+{
+ CMSDKAPBDualTimerModule *m = opaque;
+
+ m->intstatus = 1;
+ cmsdk_apb_dualtimer_update(m->parent);
+}
+
+static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
+{
+ m->control = R_CONTROL_INTEN_MASK;
+ m->intstatus = 0;
+ m->load = 0;
+ m->value = 0xffffffff;
+ ptimer_stop(m->timer);
+ /*
+ * We start in free-running mode, with VALUE at 0xffffffff, and
+ * in 16-bit counter mode. This means that the ptimer count and
+ * limit must both be set to 0xffff, so we wrap at 16 bits.
+ */
+ ptimer_set_limit(m->timer, 0xffff, 1);
+ ptimer_set_freq(m->timer, m->parent->pclk_frq);
+}
+
+static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
+{
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
+ int i;
+
+ trace_cmsdk_apb_dualtimer_reset();
+
+ for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
+ cmsdk_dualtimermod_reset(&s->timermod[i]);
+ }
+ s->timeritcr = 0;
+ s->timeritop = 0;
+}
+
+static void cmsdk_apb_dualtimer_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(obj);
+ int i;
+
+ memory_region_init_io(&s->iomem, obj, &cmsdk_apb_dualtimer_ops,
+ s, "cmsdk-apb-dualtimer", 0x1000);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->timerintc);
+
+ for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
+ sysbus_init_irq(sbd, &s->timermod[i].timerint);
+ }
+}
+
+static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
+{
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
+ int i;
+
+ if (s->pclk_frq == 0) {
+ error_setg(errp, "CMSDK APB timer: pclk-frq property must be set");
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
+ CMSDKAPBDualTimerModule *m = &s->timermod[i];
+ QEMUBH *bh = qemu_bh_new(cmsdk_dualtimermod_tick, m);
+
+ m->parent = s;
+ m->timer = ptimer_init(bh,
+ PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
+ PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
+ PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
+ PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+ }
+}
+
+static const VMStateDescription cmsdk_dualtimermod_vmstate = {
+ .name = "cmsdk-apb-dualtimer-module",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PTIMER(timer, CMSDKAPBDualTimerModule),
+ VMSTATE_UINT32(load, CMSDKAPBDualTimerModule),
+ VMSTATE_UINT32(value, CMSDKAPBDualTimerModule),
+ VMSTATE_UINT32(control, CMSDKAPBDualTimerModule),
+ VMSTATE_UINT32(intstatus, CMSDKAPBDualTimerModule),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
+ .name = "cmsdk-apb-dualtimer",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer,
+ CMSDK_APB_DUALTIMER_NUM_MODULES,
+ 1, cmsdk_dualtimermod_vmstate,
+ CMSDKAPBDualTimerModule),
+ VMSTATE_UINT32(timeritcr, CMSDKAPBDualTimer),
+ VMSTATE_UINT32(timeritop, CMSDKAPBDualTimer),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property cmsdk_apb_dualtimer_properties[] = {
+ DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer, pclk_frq, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = cmsdk_apb_dualtimer_realize;
+ dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
+ dc->reset = cmsdk_apb_dualtimer_reset;
+ dc->props = cmsdk_apb_dualtimer_properties;
+}
+
+static const TypeInfo cmsdk_apb_dualtimer_info = {
+ .name = TYPE_CMSDK_APB_DUALTIMER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(CMSDKAPBDualTimer),
+ .instance_init = cmsdk_apb_dualtimer_init,
+ .class_init = cmsdk_apb_dualtimer_class_init,
+};
+
+static void cmsdk_apb_dualtimer_register_types(void)
+{
+ type_register_static(&cmsdk_apb_dualtimer_info);
+}
+
+type_init(cmsdk_apb_dualtimer_register_types);
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 6f1f723b1f..a504f0308d 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -120,7 +120,7 @@ static void rtc_coalesced_timer_update(RTCState *s)
timer_del(s->coalesced_timer);
} else {
/* divide each RTC interval to 2 - 8 smaller intervals */
- int c = MIN(s->irq_coalesced, 7) + 1;
+ int c = MIN(s->irq_coalesced, 7) + 1;
int64_t next_clock = qemu_clock_get_ns(rtc_clock) +
periodic_clock_to_ns(s->period / c);
timer_mod(s->coalesced_timer, next_clock);
@@ -485,7 +485,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr,
s->cmos_data[s->cmos_index] = data;
check_update_timer(s);
break;
- case RTC_IBM_PS2_CENTURY_BYTE:
+ case RTC_IBM_PS2_CENTURY_BYTE:
s->cmos_index = RTC_CENTURY;
/* fall through */
case RTC_CENTURY:
@@ -713,7 +713,7 @@ static uint64_t cmos_ioport_read(void *opaque, hwaddr addr,
return 0xff;
} else {
switch(s->cmos_index) {
- case RTC_IBM_PS2_CENTURY_BYTE:
+ case RTC_IBM_PS2_CENTURY_BYTE:
s->cmos_index = RTC_CENTURY;
/* fall through */
case RTC_CENTURY:
@@ -915,7 +915,7 @@ static void rtc_reset(void *opaque)
if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
s->irq_coalesced = 0;
- s->irq_reinject_on_ack_count = 0;
+ s->irq_reinject_on_ack_count = 0;
}
}
@@ -995,9 +995,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
object_property_add_tm(OBJECT(s), "date", rtc_get_date, NULL);
- object_property_add_alias(qdev_get_machine(), "rtc-time",
- OBJECT(s), "date", NULL);
-
qdev_init_gpio_out(dev, &s->irq, 1);
}
@@ -1019,6 +1016,9 @@ ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
}
QLIST_INSERT_HEAD(&rtc_devices, s, link);
+ object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(s),
+ "date", NULL);
+
return isadev;
}
@@ -1052,17 +1052,11 @@ static void rtc_class_initfn(ObjectClass *klass, void *data)
dc->user_creatable = false;
}
-static void rtc_finalize(Object *obj)
-{
- object_property_del(qdev_get_machine(), "rtc", NULL);
-}
-
static const TypeInfo mc146818rtc_info = {
.name = TYPE_MC146818_RTC,
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(RTCState),
.class_init = rtc_class_initfn,
- .instance_finalize = rtc_finalize,
};
static void mc146818rtc_register_types(void)
diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c
index 5f8736cf10..91b18ba312 100644
--- a/hw/timer/sh_timer.c
+++ b/hw/timer/sh_timer.c
@@ -74,6 +74,7 @@ static uint32_t sh_timer_read(void *opaque, hwaddr offset)
case OFFSET_TCPR:
if (s->feat & TIMER_FEAT_CAPT)
return s->tcpr;
+ /* fall through */
default:
hw_error("sh_timer_read: Bad offset %x\n", (int)offset);
return 0;
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index e6e042fddb..fa4213df5b 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -61,5 +61,10 @@ cmsdk_apb_timer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB t
cmsdk_apb_timer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_timer_reset(void) "CMSDK APB timer: reset"
+# hw/timer/cmsdk_apb_dualtimer.c
+cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
+
# hw/timer/xlnx-zynqmp-rtc.c
xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 1ded7ac9a3..3fdc4b0da1 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -82,6 +82,7 @@ enum mtp_code {
FMT_ASSOCIATION = 0x3001,
/* event codes */
+ EVT_CANCEL_TRANSACTION = 0x4001,
EVT_OBJ_ADDED = 0x4002,
EVT_OBJ_REMOVED = 0x4003,
EVT_OBJ_INFO_CHANGED = 0x4007,
@@ -146,9 +147,12 @@ struct MTPData {
uint32_t trans;
uint64_t offset;
uint64_t length;
- uint32_t alloc;
+ uint64_t alloc;
uint8_t *data;
bool first;
+ /* Used for >4G file sizes */
+ bool pending;
+ uint64_t cached_length;
int fd;
};
@@ -1551,14 +1555,35 @@ static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p,
int length, uint8_t *data)
{
int ret;
+ MTPState *s = USB_MTP(dev);
+ uint16_t *event = (uint16_t *)data;
- ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
- if (ret >= 0) {
- return;
+ switch (request) {
+ case ClassInterfaceOutRequest | 0x64:
+ if (*event == EVT_CANCEL_TRANSACTION) {
+ g_free(s->result);
+ s->result = NULL;
+ usb_mtp_data_free(s->data_in);
+ s->data_in = NULL;
+ if (s->write_pending) {
+ g_free(s->dataset.filename);
+ s->write_pending = false;
+ }
+ usb_mtp_data_free(s->data_out);
+ s->data_out = NULL;
+ } else {
+ p->status = USB_RET_STALL;
+ }
+ break;
+ default:
+ ret = usb_desc_handle_control(dev, p, request,
+ value, index, length, data);
+ if (ret >= 0) {
+ return;
+ }
}
trace_usb_mtp_stall(dev->addr, "unknown control request");
- p->status = USB_RET_STALL;
}
static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
@@ -1580,13 +1605,31 @@ static void utf16_to_str(uint8_t len, uint16_t *arr, char *name)
g_free(wstr);
}
+/* Wrapper around write, returns 0 on failure */
+static uint64_t write_retry(int fd, void *buf, uint64_t size)
+{
+ uint64_t bytes_left = size, ret;
+
+ while (bytes_left > 0) {
+ ret = write(fd, buf, bytes_left);
+ if ((ret == -1) && (errno != EINTR || errno != EAGAIN ||
+ errno != EWOULDBLOCK)) {
+ break;
+ }
+ bytes_left -= ret;
+ buf += ret;
+ }
+
+ return size - bytes_left;
+}
+
static void usb_mtp_write_data(MTPState *s)
{
MTPData *d = s->data_out;
MTPObject *parent =
usb_mtp_object_lookup(s, s->dataset.parent_handle);
char *path = NULL;
- int rc = -1;
+ uint64_t rc;
mode_t mask = 0644;
assert(d != NULL);
@@ -1603,7 +1646,7 @@ static void usb_mtp_write_data(MTPState *s)
d->fd = mkdir(path, mask);
goto free;
}
- if (s->dataset.size < d->length) {
+ if ((s->dataset.size != 0xFFFFFFFF) && (s->dataset.size < d->length)) {
usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
0, 0, 0, 0);
goto done;
@@ -1622,8 +1665,8 @@ static void usb_mtp_write_data(MTPState *s)
goto success;
}
- rc = write(d->fd, d->data, s->dataset.size);
- if (rc == -1) {
+ rc = write_retry(d->fd, d->data, s->dataset.size);
+ if (!rc) {
usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
0, 0, 0, 0);
goto done;
@@ -1699,6 +1742,7 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container,
MTPData *d = s->data_out;
uint64_t dlen;
uint32_t data_len = p->iov.size;
+ uint64_t total_len;
if (!d) {
usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, 0,
@@ -1707,18 +1751,33 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container,
}
if (d->first) {
/* Total length of incoming data */
- d->length = cpu_to_le32(container->length) - sizeof(mtp_container);
+ total_len = cpu_to_le32(container->length) - sizeof(mtp_container);
/* Length of data in this packet */
data_len -= sizeof(mtp_container);
- usb_mtp_realloc(d, d->length);
+ usb_mtp_realloc(d, total_len);
+ d->length += total_len;
d->offset = 0;
+ d->cached_length = total_len;
d->first = false;
+ d->pending = false;
+ }
+
+ if (d->pending) {
+ usb_mtp_realloc(d, d->cached_length);
+ d->length += d->cached_length;
+ d->pending = false;
}
if (d->length - d->offset > data_len) {
dlen = data_len;
} else {
dlen = d->length - d->offset;
+ /* Check for cached data for large files */
+ if ((s->dataset.size == 0xFFFFFFFF) && (dlen < p->iov.size)) {
+ usb_mtp_realloc(d, p->iov.size - dlen);
+ d->length += p->iov.size - dlen;
+ dlen = p->iov.size;
+ }
}
switch (d->code) {
@@ -1738,12 +1797,18 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container,
case CMD_SEND_OBJECT:
usb_packet_copy(p, d->data + d->offset, dlen);
d->offset += dlen;
- if (d->offset == d->length) {
+ if ((p->iov.size % 64) || !p->iov.size) {
+ assert((s->dataset.size == 0xFFFFFFFF) ||
+ (s->dataset.size == d->length));
+
usb_mtp_write_data(s);
usb_mtp_data_free(s->data_out);
s->data_out = NULL;
return;
}
+ if (d->offset == d->length) {
+ d->pending = true;
+ }
break;
default:
p->status = USB_RET_STALL;
@@ -1953,7 +2018,7 @@ static void usb_mtp_realize(USBDevice *dev, Error **errp)
QTAILQ_INIT(&s->objects);
if (s->desc == NULL) {
if (s->root == NULL) {
- error_setg(errp, "usb-mtp: x-root property must be configured");
+ error_setg(errp, "usb-mtp: rootdir property must be configured");
return;
}
s->desc = strrchr(s->root, '/');
@@ -1982,7 +2047,7 @@ static const VMStateDescription vmstate_usb_mtp = {
};
static Property mtp_properties[] = {
- DEFINE_PROP_STRING("x-root", MTPState, root),
+ DEFINE_PROP_STRING("rootdir", MTPState, root),
DEFINE_PROP_STRING("desc", MTPState, desc),
DEFINE_PROP_BOOL("readonly", MTPState, readonly, true),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index d4c0293db5..98da5f0f04 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -1156,6 +1156,9 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
OHCI_SET_BM(td.flags, TD_EC, 3);
break;
}
+ /* An error occured so we have to clear the interrupt counter. See
+ * spec at 6.4.4 on page 104 */
+ ohci->done_count = 0;
}
ed->head |= OHCI_ED_H;
}
diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h
index 71cd069478..c67271f1ba 100644
--- a/include/chardev/char-fe.h
+++ b/include/chardev/char-fe.h
@@ -113,7 +113,7 @@ void qemu_chr_fe_accept_input(CharBackend *be);
/**
* @qemu_chr_fe_disconnect:
*
- * Close a fd accpeted by character backend.
+ * Close a fd accepted by character backend.
* Without associated Chardev, do nothing.
*/
void qemu_chr_fe_disconnect(CharBackend *be);
@@ -122,7 +122,7 @@ void qemu_chr_fe_disconnect(CharBackend *be);
* @qemu_chr_fe_wait_connected:
*
* Wait for characted backend to be connected, return < 0 on error or
- * if no assicated Chardev.
+ * if no associated Chardev.
*/
int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
@@ -186,7 +186,7 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
* @buf the data
* @len the number of bytes to send
*
- * Returns: the number of bytes consumed (0 if no assicated Chardev)
+ * Returns: the number of bytes consumed (0 if no associated Chardev)
*/
int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
@@ -201,7 +201,7 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
* @buf the data
* @len the number of bytes to send
*
- * Returns: the number of bytes consumed (0 if no assicated Chardev)
+ * Returns: the number of bytes consumed (0 if no associated Chardev)
*/
int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
@@ -213,7 +213,7 @@ int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
* @buf the data buffer
* @len the number of bytes to read
*
- * Returns: the number of bytes read (0 if no assicated Chardev)
+ * Returns: the number of bytes read (0 if no associated Chardev)
*/
int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index 69f4dbc4db..cc1b58b029 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -190,49 +190,88 @@ enum {
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
+
+float16 int16_to_float16_scalbn(int16_t a, int, float_status *status);
+float16 int32_to_float16_scalbn(int32_t a, int, float_status *status);
+float16 int64_to_float16_scalbn(int64_t a, int, float_status *status);
+float16 uint16_to_float16_scalbn(uint16_t a, int, float_status *status);
+float16 uint32_to_float16_scalbn(uint32_t a, int, float_status *status);
+float16 uint64_to_float16_scalbn(uint64_t a, int, float_status *status);
+
+float16 int16_to_float16(int16_t a, float_status *status);
+float16 int32_to_float16(int32_t a, float_status *status);
+float16 int64_to_float16(int64_t a, float_status *status);
+float16 uint16_to_float16(uint16_t a, float_status *status);
+float16 uint32_to_float16(uint32_t a, float_status *status);
+float16 uint64_to_float16(uint64_t a, float_status *status);
+
+float32 int16_to_float32_scalbn(int16_t, int, float_status *status);
+float32 int32_to_float32_scalbn(int32_t, int, float_status *status);
+float32 int64_to_float32_scalbn(int64_t, int, float_status *status);
+float32 uint16_to_float32_scalbn(uint16_t, int, float_status *status);
+float32 uint32_to_float32_scalbn(uint32_t, int, float_status *status);
+float32 uint64_to_float32_scalbn(uint64_t, int, float_status *status);
+
float32 int16_to_float32(int16_t, float_status *status);
float32 int32_to_float32(int32_t, float_status *status);
-float64 int16_to_float64(int16_t, float_status *status);
-float64 int32_to_float64(int32_t, float_status *status);
+float32 int64_to_float32(int64_t, float_status *status);
float32 uint16_to_float32(uint16_t, float_status *status);
float32 uint32_to_float32(uint32_t, float_status *status);
+float32 uint64_to_float32(uint64_t, float_status *status);
+
+float64 int16_to_float64_scalbn(int16_t, int, float_status *status);
+float64 int32_to_float64_scalbn(int32_t, int, float_status *status);
+float64 int64_to_float64_scalbn(int64_t, int, float_status *status);
+float64 uint16_to_float64_scalbn(uint16_t, int, float_status *status);
+float64 uint32_to_float64_scalbn(uint32_t, int, float_status *status);
+float64 uint64_to_float64_scalbn(uint64_t, int, float_status *status);
+
+float64 int16_to_float64(int16_t, float_status *status);
+float64 int32_to_float64(int32_t, float_status *status);
+float64 int64_to_float64(int64_t, float_status *status);
float64 uint16_to_float64(uint16_t, float_status *status);
float64 uint32_to_float64(uint32_t, float_status *status);
+float64 uint64_to_float64(uint64_t, float_status *status);
+
floatx80 int32_to_floatx80(int32_t, float_status *status);
-float128 int32_to_float128(int32_t, float_status *status);
-float32 int64_to_float32(int64_t, float_status *status);
-float64 int64_to_float64(int64_t, float_status *status);
floatx80 int64_to_floatx80(int64_t, float_status *status);
+
+float128 int32_to_float128(int32_t, float_status *status);
float128 int64_to_float128(int64_t, float_status *status);
-float32 uint64_to_float32(uint64_t, float_status *status);
-float64 uint64_to_float64(uint64_t, float_status *status);
float128 uint64_to_float128(uint64_t, float_status *status);
/*----------------------------------------------------------------------------
| Software half-precision conversion routines.
*----------------------------------------------------------------------------*/
+
float16 float32_to_float16(float32, bool ieee, float_status *status);
float32 float16_to_float32(float16, bool ieee, float_status *status);
float16 float64_to_float16(float64 a, bool ieee, float_status *status);
float64 float16_to_float64(float16 a, bool ieee, float_status *status);
+
+int16_t float16_to_int16_scalbn(float16, int, int, float_status *status);
+int32_t float16_to_int32_scalbn(float16, int, int, float_status *status);
+int64_t float16_to_int64_scalbn(float16, int, int, float_status *status);
+
int16_t float16_to_int16(float16, float_status *status);
-uint16_t float16_to_uint16(float16 a, float_status *status);
-int16_t float16_to_int16_round_to_zero(float16, float_status *status);
-uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *status);
int32_t float16_to_int32(float16, float_status *status);
-uint32_t float16_to_uint32(float16 a, float_status *status);
-int32_t float16_to_int32_round_to_zero(float16, float_status *status);
-uint32_t float16_to_uint32_round_to_zero(float16 a, float_status *status);
int64_t float16_to_int64(float16, float_status *status);
-uint64_t float16_to_uint64(float16 a, float_status *status);
+
+int16_t float16_to_int16_round_to_zero(float16, float_status *status);
+int32_t float16_to_int32_round_to_zero(float16, float_status *status);
int64_t float16_to_int64_round_to_zero(float16, float_status *status);
+
+uint16_t float16_to_uint16_scalbn(float16 a, int, int, float_status *status);
+uint32_t float16_to_uint32_scalbn(float16 a, int, int, float_status *status);
+uint64_t float16_to_uint64_scalbn(float16 a, int, int, float_status *status);
+
+uint16_t float16_to_uint16(float16 a, float_status *status);
+uint32_t float16_to_uint32(float16 a, float_status *status);
+uint64_t float16_to_uint64(float16 a, float_status *status);
+
+uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *status);
+uint32_t float16_to_uint32_round_to_zero(float16 a, float_status *status);
uint64_t float16_to_uint64_round_to_zero(float16 a, float_status *status);
-float16 int16_to_float16(int16_t a, float_status *status);
-float16 int32_to_float16(int32_t a, float_status *status);
-float16 int64_to_float16(int64_t a, float_status *status);
-float16 uint16_to_float16(uint16_t a, float_status *status);
-float16 uint32_to_float16(uint32_t a, float_status *status);
-float16 uint64_to_float16(uint64_t a, float_status *status);
/*----------------------------------------------------------------------------
| Software half-precision operations.
@@ -321,18 +360,31 @@ float16 float16_default_nan(float_status *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
+
+int16_t float32_to_int16_scalbn(float32, int, int, float_status *status);
+int32_t float32_to_int32_scalbn(float32, int, int, float_status *status);
+int64_t float32_to_int64_scalbn(float32, int, int, float_status *status);
+
int16_t float32_to_int16(float32, float_status *status);
-uint16_t float32_to_uint16(float32, float_status *status);
-int16_t float32_to_int16_round_to_zero(float32, float_status *status);
-uint16_t float32_to_uint16_round_to_zero(float32, float_status *status);
int32_t float32_to_int32(float32, float_status *status);
+int64_t float32_to_int64(float32, float_status *status);
+
+int16_t float32_to_int16_round_to_zero(float32, float_status *status);
int32_t float32_to_int32_round_to_zero(float32, float_status *status);
+int64_t float32_to_int64_round_to_zero(float32, float_status *status);
+
+uint16_t float32_to_uint16_scalbn(float32, int, int, float_status *status);
+uint32_t float32_to_uint32_scalbn(float32, int, int, float_status *status);
+uint64_t float32_to_uint64_scalbn(float32, int, int, float_status *status);
+
+uint16_t float32_to_uint16(float32, float_status *status);
uint32_t float32_to_uint32(float32, float_status *status);
-uint32_t float32_to_uint32_round_to_zero(float32, float_status *status);
-int64_t float32_to_int64(float32, float_status *status);
uint64_t float32_to_uint64(float32, float_status *status);
+
+uint16_t float32_to_uint16_round_to_zero(float32, float_status *status);
+uint32_t float32_to_uint32_round_to_zero(float32, float_status *status);
uint64_t float32_to_uint64_round_to_zero(float32, float_status *status);
-int64_t float32_to_int64_round_to_zero(float32, float_status *status);
+
float64 float32_to_float64(float32, float_status *status);
floatx80 float32_to_floatx80(float32, float_status *status);
float128 float32_to_float128(float32, float_status *status);
@@ -450,18 +502,31 @@ float32 float32_default_nan(float_status *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
+
+int16_t float64_to_int16_scalbn(float64, int, int, float_status *status);
+int32_t float64_to_int32_scalbn(float64, int, int, float_status *status);
+int64_t float64_to_int64_scalbn(float64, int, int, float_status *status);
+
int16_t float64_to_int16(float64, float_status *status);
-uint16_t float64_to_uint16(float64, float_status *status);
-int16_t float64_to_int16_round_to_zero(float64, float_status *status);
-uint16_t float64_to_uint16_round_to_zero(float64, float_status *status);
int32_t float64_to_int32(float64, float_status *status);
+int64_t float64_to_int64(float64, float_status *status);
+
+int16_t float64_to_int16_round_to_zero(float64, float_status *status);
int32_t float64_to_int32_round_to_zero(float64, float_status *status);
+int64_t float64_to_int64_round_to_zero(float64, float_status *status);
+
+uint16_t float64_to_uint16_scalbn(float64, int, int, float_status *status);
+uint32_t float64_to_uint32_scalbn(float64, int, int, float_status *status);
+uint64_t float64_to_uint64_scalbn(float64, int, int, float_status *status);
+
+uint16_t float64_to_uint16(float64, float_status *status);
uint32_t float64_to_uint32(float64, float_status *status);
+uint64_t float64_to_uint64(float64, float_status *status);
+
+uint16_t float64_to_uint16_round_to_zero(float64, float_status *status);
uint32_t float64_to_uint32_round_to_zero(float64, float_status *status);
-int64_t float64_to_int64(float64, float_status *status);
-int64_t float64_to_int64_round_to_zero(float64, float_status *status);
-uint64_t float64_to_uint64(float64 a, float_status *status);
-uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *status);
+uint64_t float64_to_uint64_round_to_zero(float64, float_status *status);
+
float32 float64_to_float32(float64, float_status *status);
floatx80 float64_to_floatx80(float64, float_status *status);
float128 float64_to_float128(float64, float_status *status);
diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
index 2cddde55dd..3a8ee63908 100644
--- a/include/hw/arm/iotkit.h
+++ b/include/hw/arm/iotkit.h
@@ -28,6 +28,9 @@
* + QOM property "EXP_NUMIRQ" sets the number of expansion interrupts
* + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts, which
* are wired to the NVIC lines 32 .. n+32
+ * + sysbus MMIO region 0 is the "AHB Slave Expansion" which allows
+ * bus master devices in the board model to make transactions into
+ * all the devices and memory areas in the IoTKit
* Controlling up to 4 AHB expansion PPBs which a system using the IoTKit
* might provide:
* + named GPIO outputs apb_ppcexp{0,1,2,3}_nonsec[0..15]
@@ -45,6 +48,11 @@
* Controlling each of the 16 expansion MPCs which a system using the IoTKit
* might provide:
* + named GPIO inputs mpcexp_status[0..15]
+ * Controlling each of the 16 expansion MSCs which a system using the IoTKit
+ * might provide:
+ * + named GPIO inputs mscexp_status[0..15]
+ * + named GPIO outputs mscexp_clear[0..15]
+ * + named GPIO outputs mscexp_ns[0..15]
*/
#ifndef IOTKIT_H
@@ -56,7 +64,10 @@
#include "hw/misc/tz-ppc.h"
#include "hw/misc/tz-mpc.h"
#include "hw/timer/cmsdk-apb-timer.h"
-#include "hw/misc/unimp.h"
+#include "hw/timer/cmsdk-apb-dualtimer.h"
+#include "hw/watchdog/cmsdk-apb-watchdog.h"
+#include "hw/misc/iotkit-sysctl.h"
+#include "hw/misc/iotkit-sysinfo.h"
#include "hw/or-irq.h"
#include "hw/core/split-irq.h"
@@ -81,14 +92,22 @@ typedef struct IoTKit {
TZMPC mpc;
CMSDKAPBTIMER timer0;
CMSDKAPBTIMER timer1;
+ CMSDKAPBTIMER s32ktimer;
qemu_or_irq ppc_irq_orgate;
SplitIRQ sec_resp_splitter;
SplitIRQ ppc_irq_splitter[NUM_PPCS];
SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC];
qemu_or_irq mpc_irq_orgate;
+ qemu_or_irq nmi_orgate;
+
+ CMSDKAPBDualTimer dualtimer;
+
+ CMSDKAPBWatchdog s32kwatchdog;
+ CMSDKAPBWatchdog nswatchdog;
+ CMSDKAPBWatchdog swatchdog;
- UnimplementedDeviceState dualtimer;
- UnimplementedDeviceState s32ktimer;
+ IoTKitSysCtl sysctl;
+ IoTKitSysCtl sysinfo;
MemoryRegion container;
MemoryRegion alias1;
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
index ae0a3807f2..228988ba05 100644
--- a/include/hw/display/bcm2835_fb.h
+++ b/include/hw/display/bcm2835_fb.h
@@ -17,6 +17,20 @@
#define TYPE_BCM2835_FB "bcm2835-fb"
#define BCM2835_FB(obj) OBJECT_CHECK(BCM2835FBState, (obj), TYPE_BCM2835_FB)
+/*
+ * Configuration information about the fb which the guest can program
+ * via the mailbox property interface.
+ */
+typedef struct {
+ uint32_t xres, yres;
+ uint32_t xres_virtual, yres_virtual;
+ uint32_t xoffset, yoffset;
+ uint32_t bpp;
+ uint32_t base;
+ uint32_t pixo;
+ uint32_t alpha;
+} BCM2835FBConfig;
+
typedef struct {
/*< private >*/
SysBusDevice busdev;
@@ -31,16 +45,43 @@ typedef struct {
qemu_irq mbox_irq;
bool lock, invalidate, pending;
- uint32_t xres, yres;
- uint32_t xres_virtual, yres_virtual;
- uint32_t xoffset, yoffset;
- uint32_t bpp;
- uint32_t base, pitch, size;
- uint32_t pixo, alpha;
+
+ BCM2835FBConfig config;
+ BCM2835FBConfig initial_config;
} BCM2835FBState;
-void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
- uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
- uint32_t *pixo, uint32_t *alpha);
+void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig);
+
+/**
+ * bcm2835_fb_get_pitch: return number of bytes per line of the framebuffer
+ * @config: configuration info for the framebuffer
+ *
+ * Return the number of bytes per line of the framebuffer, ie the number
+ * that must be added to a pixel address to get the address of the pixel
+ * directly below it on screen.
+ */
+static inline uint32_t bcm2835_fb_get_pitch(BCM2835FBConfig *config)
+{
+ uint32_t xres = MAX(config->xres, config->xres_virtual);
+ return xres * (config->bpp >> 3);
+}
+
+/**
+ * bcm2835_fb_get_size: return total size of framebuffer in bytes
+ * @config: configuration info for the framebuffer
+ */
+static inline uint32_t bcm2835_fb_get_size(BCM2835FBConfig *config)
+{
+ uint32_t yres = MAX(config->yres, config->yres_virtual);
+ return yres * bcm2835_fb_get_pitch(config);
+}
+
+/**
+ * bcm2835_fb_validate_config: check provided config
+ *
+ * Validates the configuration information provided by the guest and
+ * adjusts it if necessary.
+ */
+void bcm2835_fb_validate_config(BCM2835FBConfig *config);
#endif
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
index 2a837afdcb..060d3c6ac0 100644
--- a/include/hw/i2c/pm_smbus.h
+++ b/include/hw/i2c/pm_smbus.h
@@ -1,6 +1,8 @@
#ifndef PM_SMBUS_H
#define PM_SMBUS_H
+#define PM_SMBUS_MAX_MSG_SIZE 32
+
typedef struct PMSMBus {
I2CBus *smbus;
MemoryRegion io;
@@ -11,10 +13,26 @@ typedef struct PMSMBus {
uint8_t smb_addr;
uint8_t smb_data0;
uint8_t smb_data1;
- uint8_t smb_data[32];
- uint8_t smb_index;
+ uint8_t smb_data[PM_SMBUS_MAX_MSG_SIZE];
+ uint8_t smb_blkdata;
+ uint8_t smb_auxctl;
+ uint32_t smb_index;
+
+ /* Set by pm_smbus.c */
+ void (*reset)(struct PMSMBus *s);
+
+ /* Set by the user. */
+ bool i2c_enable;
+ void (*set_irq)(struct PMSMBus *s, bool enabled);
+ void *opaque;
+
+ /* Internally used by pm_smbus. */
+
+ /* Set on block transfers after the last byte has been read, so the
+ INTR bit can be set at the right time. */
+ bool op_done;
} PMSMBus;
-void pm_smbus_init(DeviceState *parent, PMSMBus *smb);
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb, bool force_aux_blk);
#endif /* PM_SMBUS_H */
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
index 4fdba022c1..d8b1b9ee81 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus.h
@@ -72,9 +72,22 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command);
int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data);
int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command);
int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data);
-int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data);
+
+/*
+ * Do a block transfer from an I2C device. If recv_len is set, then the
+ * first received byte is a length field and is used to know how much data
+ * to receive. Otherwise receive "len" bytes. If send_cmd is set, send
+ * the command byte first before receiving the data.
+ */
+int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+ int len, bool recv_len, bool send_cmd);
+
+/*
+ * Do a block transfer to an I2C device. If send_len is set, send the
+ * "len" value before the data.
+ */
int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
- int len);
+ int len, bool send_len);
void smbus_eeprom_init_one(I2CBus *smbus, uint8_t address, uint8_t *eeprom_buf);
void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom,
diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h
index 26ebb7d5e9..b382eb4303 100644
--- a/include/hw/mem/pc-dimm.h
+++ b/include/hw/mem/pc-dimm.h
@@ -79,7 +79,8 @@ typedef struct PCDIMMDeviceClass {
Error **errp);
} PCDIMMDeviceClass;
-void pc_dimm_plug(DeviceState *dev, MachineState *machine, uint64_t align,
- Error **errp);
+void pc_dimm_pre_plug(DeviceState *dev, MachineState *machine,
+ const uint64_t *legacy_align, Error **errp);
+void pc_dimm_plug(DeviceState *dev, MachineState *machine, Error **errp);
void pc_dimm_unplug(DeviceState *dev, MachineState *machine);
#endif
diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h
index 082c14c925..1a193b306f 100644
--- a/include/hw/misc/iotkit-secctl.h
+++ b/include/hw/misc/iotkit-secctl.h
@@ -19,6 +19,7 @@
* + named GPIO output "sec_resp_cfg" indicating whether blocked accesses
* should RAZ/WI or bus error
* + named GPIO output "nsc_cfg" whose value tracks the NSCCFG register value
+ * + named GPIO output "msc_irq" for the combined IRQ line from the MSCs
* Controlling the 2 APB PPCs in the IoTKit:
* + named GPIO outputs apb_ppc0_nonsec[0..2] and apb_ppc1_nonsec
* + named GPIO outputs apb_ppc0_ap[0..2] and apb_ppc1_ap
@@ -44,6 +45,11 @@
* Controlling each of the 16 expansion MPCs which a system using the IoTKit
* might provide:
* + named GPIO inputs mpcexp_status[0..15]
+ * Controlling each of the 16 expansion MSCs which a system using the IoTKit
+ * might provide:
+ * + named GPIO inputs mscexp_status[0..15]
+ * + named GPIO outputs mscexp_clear[0..15]
+ * + named GPIO outputs mscexp_ns[0..15]
*/
#ifndef IOTKIT_SECCTL_H
@@ -62,6 +68,7 @@
#define IOTS_NUM_AHB_EXP_PPC 4
#define IOTS_NUM_EXP_MPC 16
#define IOTS_NUM_MPC 1
+#define IOTS_NUM_EXP_MSC 16
typedef struct IoTKitSecCtl IoTKitSecCtl;
@@ -103,6 +110,13 @@ struct IoTKitSecCtl {
uint32_t brginten;
uint32_t mpcintstatus;
+ uint32_t secmscintstat;
+ uint32_t secmscinten;
+ uint32_t nsmscexp;
+ qemu_irq mscexp_clear[IOTS_NUM_EXP_MSC];
+ qemu_irq mscexp_ns[IOTS_NUM_EXP_MSC];
+ qemu_irq msc_irq;
+
IoTKitSecCtlPPC apb[IOTS_NUM_APB_PPC];
IoTKitSecCtlPPC apbexp[IOTS_NUM_APB_EXP_PPC];
IoTKitSecCtlPPC ahbexp[IOTS_NUM_APB_EXP_PPC];
diff --git a/include/hw/misc/iotkit-sysctl.h b/include/hw/misc/iotkit-sysctl.h
new file mode 100644
index 0000000000..e36613cb5e
--- /dev/null
+++ b/include/hw/misc/iotkit-sysctl.h
@@ -0,0 +1,49 @@
+/*
+ * ARM IoTKit system control element
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/*
+ * This is a model of the "system control element" which is part of the
+ * Arm IoTKit and documented in
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * Specifically, it implements the "system information block" and
+ * "system control register" blocks.
+ *
+ * QEMU interface:
+ * + sysbus MMIO region 0: the system information register bank
+ * + sysbus MMIO region 1: the system control register bank
+ */
+
+#ifndef HW_MISC_IOTKIT_SYSCTL_H
+#define HW_MISC_IOTKIT_SYSCTL_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_IOTKIT_SYSCTL "iotkit-sysctl"
+#define IOTKIT_SYSCTL(obj) OBJECT_CHECK(IoTKitSysCtl, (obj), \
+ TYPE_IOTKIT_SYSCTL)
+
+typedef struct IoTKitSysCtl {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion iomem;
+
+ uint32_t secure_debug;
+ uint32_t reset_syndrome;
+ uint32_t reset_mask;
+ uint32_t gretreg;
+ uint32_t initsvrtor0;
+ uint32_t cpuwait;
+ uint32_t wicctrl;
+} IoTKitSysCtl;
+
+#endif
diff --git a/include/hw/misc/iotkit-sysinfo.h b/include/hw/misc/iotkit-sysinfo.h
new file mode 100644
index 0000000000..7b2e1a5e48
--- /dev/null
+++ b/include/hw/misc/iotkit-sysinfo.h
@@ -0,0 +1,37 @@
+/*
+ * ARM IoTKit system information block
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/*
+ * This is a model of the "system information block" which is part of the
+ * Arm IoTKit and documented in
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * QEMU interface:
+ * + sysbus MMIO region 0: the system information register bank
+ */
+
+#ifndef HW_MISC_IOTKIT_SYSINFO_H
+#define HW_MISC_IOTKIT_SYSINFO_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_IOTKIT_SYSINFO "iotkit-sysinfo"
+#define IOTKIT_SYSINFO(obj) OBJECT_CHECK(IoTKitSysInfo, (obj), \
+ TYPE_IOTKIT_SYSINFO)
+
+typedef struct IoTKitSysInfo {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion iomem;
+} IoTKitSysInfo;
+
+#endif
diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h
index eedf17ebc6..69e265cd4b 100644
--- a/include/hw/misc/mps2-fpgaio.h
+++ b/include/hw/misc/mps2-fpgaio.h
@@ -37,7 +37,17 @@ typedef struct {
uint32_t prescale;
uint32_t misc;
+ /* QEMU_CLOCK_VIRTUAL time at which counter and pscntr were last synced */
+ int64_t pscntr_sync_ticks;
+ /* Values of COUNTER and PSCNTR at time pscntr_sync_ticks */
+ uint32_t counter;
+ uint32_t pscntr;
+
uint32_t prescale_clk;
+
+ /* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was zero */
+ int64_t clk1hz_tick_offset;
+ int64_t clk100hz_tick_offset;
} MPS2FPGAIO;
#endif
diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h
index 36a54e270c..1ee071a703 100644
--- a/include/hw/misc/pvpanic.h
+++ b/include/hw/misc/pvpanic.h
@@ -16,6 +16,15 @@
#define TYPE_PVPANIC "pvpanic"
-uint16_t pvpanic_port(void);
+#define PVPANIC_IOPORT_PROP "ioport"
+
+static inline uint16_t pvpanic_port(void)
+{
+ Object *o = object_resolve_path_type("", TYPE_PVPANIC, NULL);
+ if (!o) {
+ return 0;
+ }
+ return object_property_get_uint(o, PVPANIC_IOPORT_PROP, NULL);
+}
#endif
diff --git a/include/hw/misc/tz-msc.h b/include/hw/misc/tz-msc.h
new file mode 100644
index 0000000000..116b96ae9b
--- /dev/null
+++ b/include/hw/misc/tz-msc.h
@@ -0,0 +1,79 @@
+/*
+ * ARM TrustZone master security controller emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/*
+ * This is a model of the TrustZone master security controller (MSC).
+ * It is documented in the ARM CoreLink SIE-200 System IP for Embedded TRM
+ * (DDI 0571G):
+ * https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g
+ *
+ * The MSC sits in front of a device which can be a bus master (such as
+ * a DMA controller) and allows secure software to configure it to either
+ * pass through or reject transactions made by that bus master.
+ * Rejected transactions may be configured to either be aborted, or to
+ * behave as RAZ/WI. An interrupt can be signalled for a rejected transaction.
+ *
+ * The MSC has no register interface -- it is configured purely by a
+ * collection of input signals from other hardware in the system. Typically
+ * they are either hardwired or exposed in an ad-hoc register interface by
+ * the SoC that uses the MSC.
+ *
+ * We don't currently implement the irq_enable GPIO input, because on
+ * the MPS2 FPGA images it is always tied high, which is awkward to
+ * implement in QEMU.
+ *
+ * QEMU interface:
+ * + Named GPIO input "cfg_nonsec": set to 1 if the bus master should be
+ * treated as nonsecure, or 0 for secure
+ * + Named GPIO input "cfg_sec_resp": set to 1 if a rejected transaction should
+ * result in a transaction error, or 0 for the transaction to RAZ/WI
+ * + Named GPIO input "irq_clear": set to 1 to clear a pending interrupt
+ * + Named GPIO output "irq": set for a transaction-failed interrupt
+ * + Property "downstream": MemoryRegion defining where bus master transactions
+ * are made if they are not blocked
+ * + Property "idau": an object implementing IDAUInterface, which defines which
+ * addresses should be treated as secure and which as non-secure.
+ * This need not be the same IDAU as the one used by the CPU.
+ * + sysbus MMIO region 0: MemoryRegion defining the upstream end of the MSC;
+ * this should be passed to the bus master device as the region it should
+ * make memory transactions to
+ */
+
+#ifndef TZ_MSC_H
+#define TZ_MSC_H
+
+#include "hw/sysbus.h"
+#include "target/arm/idau.h"
+
+#define TYPE_TZ_MSC "tz-msc"
+#define TZ_MSC(obj) OBJECT_CHECK(TZMSC, (obj), TYPE_TZ_MSC)
+
+typedef struct TZMSC {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+
+ /* State: these just track the values of our input signals */
+ bool cfg_nonsec;
+ bool cfg_sec_resp;
+ bool irq_clear;
+ /* State: are we asserting irq ? */
+ bool irq_status;
+
+ qemu_irq irq;
+ MemoryRegion *downstream;
+ AddressSpace downstream_as;
+ MemoryRegion upstream;
+ IDAUInterface *idau;
+} TZMSC;
+
+#endif
diff --git a/include/hw/misc/vmcoreinfo.h b/include/hw/misc/vmcoreinfo.h
index c3aa856545..0d11578059 100644
--- a/include/hw/misc/vmcoreinfo.h
+++ b/include/hw/misc/vmcoreinfo.h
@@ -13,20 +13,12 @@
#define VMCOREINFO_H
#include "hw/qdev.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
#define VMCOREINFO_DEVICE "vmcoreinfo"
#define VMCOREINFO(obj) OBJECT_CHECK(VMCoreInfoState, (obj), VMCOREINFO_DEVICE)
-#define VMCOREINFO_FORMAT_NONE 0x0
-#define VMCOREINFO_FORMAT_ELF 0x1
-
-/* all fields are little-endian */
-typedef struct FWCfgVMCoreInfo {
- uint16_t host_format; /* set on reset */
- uint16_t guest_format;
- uint32_t size;
- uint64_t paddr;
-} QEMU_PACKED FWCfgVMCoreInfo;
+typedef struct fw_cfg_vmcoreinfo FWCfgVMCoreInfo;
typedef struct VMCoreInfoState {
DeviceClass parent_obj;
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index b2259cc4a3..f5a6895a74 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -2,7 +2,7 @@
#define FW_CFG_H
#include "exec/hwaddr.h"
-#include "hw/nvram/fw_cfg_keys.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
#include "hw/sysbus.h"
#include "sysemu/dma.h"
@@ -14,12 +14,7 @@
#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
-typedef struct FWCfgFile {
- uint32_t size; /* file size */
- uint16_t select; /* write this to 0x510 to read it */
- uint16_t reserved;
- char name[FW_CFG_MAX_FILE_PATH];
-} FWCfgFile;
+typedef struct fw_cfg_file FWCfgFile;
#define FW_CFG_ORDER_OVERRIDE_VGA 70
#define FW_CFG_ORDER_OVERRIDE_NIC 80
@@ -34,14 +29,7 @@ typedef struct FWCfgFiles {
FWCfgFile f[];
} FWCfgFiles;
-/* Control as first field allows for different structures selected by this
- * field, which might be useful in the future
- */
-typedef struct FWCfgDmaAccess {
- uint32_t control;
- uint32_t length;
- uint64_t address;
-} QEMU_PACKED FWCfgDmaAccess;
+typedef struct fw_cfg_dma_access FWCfgDmaAccess;
typedef void (*FWCfgCallback)(void *opaque);
typedef void (*FWCfgWriteCallback)(void *opaque, off_t start, size_t len);
diff --git a/include/hw/nvram/fw_cfg_keys.h b/include/hw/nvram/fw_cfg_keys.h
deleted file mode 100644
index b6919451f5..0000000000
--- a/include/hw/nvram/fw_cfg_keys.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef FW_CFG_KEYS_H
-#define FW_CFG_KEYS_H
-
-#define FW_CFG_SIGNATURE 0x00
-#define FW_CFG_ID 0x01
-#define FW_CFG_UUID 0x02
-#define FW_CFG_RAM_SIZE 0x03
-#define FW_CFG_NOGRAPHIC 0x04
-#define FW_CFG_NB_CPUS 0x05
-#define FW_CFG_MACHINE_ID 0x06
-#define FW_CFG_KERNEL_ADDR 0x07
-#define FW_CFG_KERNEL_SIZE 0x08
-#define FW_CFG_KERNEL_CMDLINE 0x09
-#define FW_CFG_INITRD_ADDR 0x0a
-#define FW_CFG_INITRD_SIZE 0x0b
-#define FW_CFG_BOOT_DEVICE 0x0c
-#define FW_CFG_NUMA 0x0d
-#define FW_CFG_BOOT_MENU 0x0e
-#define FW_CFG_MAX_CPUS 0x0f
-#define FW_CFG_KERNEL_ENTRY 0x10
-#define FW_CFG_KERNEL_DATA 0x11
-#define FW_CFG_INITRD_DATA 0x12
-#define FW_CFG_CMDLINE_ADDR 0x13
-#define FW_CFG_CMDLINE_SIZE 0x14
-#define FW_CFG_CMDLINE_DATA 0x15
-#define FW_CFG_SETUP_ADDR 0x16
-#define FW_CFG_SETUP_SIZE 0x17
-#define FW_CFG_SETUP_DATA 0x18
-#define FW_CFG_FILE_DIR 0x19
-
-#define FW_CFG_FILE_FIRST 0x20
-#define FW_CFG_FILE_SLOTS_MIN 0x10
-
-#define FW_CFG_WRITE_CHANNEL 0x4000
-#define FW_CFG_ARCH_LOCAL 0x8000
-#define FW_CFG_ENTRY_MASK (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
-
-#define FW_CFG_INVALID 0xffff
-
-/* width in bytes of fw_cfg control register */
-#define FW_CFG_CTL_SIZE 0x02
-
-#define FW_CFG_MAX_FILE_PATH 56
-
-#endif
diff --git a/include/hw/ssi/pl022.h b/include/hw/ssi/pl022.h
new file mode 100644
index 0000000000..a080519366
--- /dev/null
+++ b/include/hw/ssi/pl022.h
@@ -0,0 +1,51 @@
+/*
+ * ARM PrimeCell PL022 Synchronous Serial Port
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/* This is a model of the Arm PrimeCell PL022 synchronous serial port.
+ * The PL022 TRM is:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0194h/DDI0194H_ssp_pl022_trm.pdf
+ *
+ * QEMU interface:
+ * + sysbus IRQ: SSPINTR combined interrupt line
+ * + sysbus MMIO region 0: MemoryRegion for the device's registers
+ */
+
+#ifndef HW_SSI_PL022_H
+#define HW_SSI_PL022_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_PL022 "pl022"
+#define PL022(obj) OBJECT_CHECK(PL022State, (obj), TYPE_PL022)
+
+typedef struct PL022State {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ uint32_t cr0;
+ uint32_t cr1;
+ uint32_t bitmask;
+ uint32_t sr;
+ uint32_t cpsr;
+ uint32_t is;
+ uint32_t im;
+ /* The FIFO head points to the next empty entry. */
+ int tx_fifo_head;
+ int rx_fifo_head;
+ int tx_fifo_len;
+ int rx_fifo_len;
+ uint16_t tx_fifo[8];
+ uint16_t rx_fifo[8];
+ qemu_irq irq;
+ SSIBus *ssi;
+} PL022State;
+
+#endif
diff --git a/include/hw/timer/cmsdk-apb-dualtimer.h b/include/hw/timer/cmsdk-apb-dualtimer.h
new file mode 100644
index 0000000000..9843a9dbb1
--- /dev/null
+++ b/include/hw/timer/cmsdk-apb-dualtimer.h
@@ -0,0 +1,72 @@
+/*
+ * ARM CMSDK APB dual-timer emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/*
+ * This is a model of the "APB dual-input timer" which is part of the Cortex-M
+ * System Design Kit (CMSDK) and documented in the Cortex-M System
+ * Design Kit Technical Reference Manual (ARM DDI0479C):
+ * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
+ *
+ * QEMU interface:
+ * + QOM property "pclk-frq": frequency at which the timer is clocked
+ * + sysbus MMIO region 0: the register bank
+ * + sysbus IRQ 0: combined timer interrupt TIMINTC
+ * + sysbus IRO 1: timer block 1 interrupt TIMINT1
+ * + sysbus IRQ 2: timer block 2 interrupt TIMINT2
+ */
+
+#ifndef CMSDK_APB_DUALTIMER_H
+#define CMSDK_APB_DUALTIMER_H
+
+#include "hw/sysbus.h"
+#include "hw/ptimer.h"
+
+#define TYPE_CMSDK_APB_DUALTIMER "cmsdk-apb-dualtimer"
+#define CMSDK_APB_DUALTIMER(obj) OBJECT_CHECK(CMSDKAPBDualTimer, (obj), \
+ TYPE_CMSDK_APB_DUALTIMER)
+
+typedef struct CMSDKAPBDualTimer CMSDKAPBDualTimer;
+
+/* One of the two identical timer modules in the dual-timer module */
+typedef struct CMSDKAPBDualTimerModule {
+ CMSDKAPBDualTimer *parent;
+ struct ptimer_state *timer;
+ qemu_irq timerint;
+ /*
+ * We must track the guest LOAD and VALUE register state by hand
+ * rather than leaving this state only in the ptimer limit/count,
+ * because if CONTROL.SIZE is 0 then only the low 16 bits of the
+ * counter actually counts, but the high half is still guest
+ * accessible.
+ */
+ uint32_t load;
+ uint32_t value;
+ uint32_t control;
+ uint32_t intstatus;
+} CMSDKAPBDualTimerModule;
+
+#define CMSDK_APB_DUALTIMER_NUM_MODULES 2
+
+struct CMSDKAPBDualTimer {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion iomem;
+ qemu_irq timerintc;
+ uint32_t pclk_frq;
+
+ CMSDKAPBDualTimerModule timermod[CMSDK_APB_DUALTIMER_NUM_MODULES];
+ uint32_t timeritcr;
+ uint32_t timeritop;
+};
+
+#endif
diff --git a/include/hw/virtio/vhost-scsi-common.h b/include/hw/virtio/vhost-scsi-common.h
index 4553be4bc3..57fb1d87b5 100644
--- a/include/hw/virtio/vhost-scsi-common.h
+++ b/include/hw/virtio/vhost-scsi-common.h
@@ -35,6 +35,7 @@ typedef struct VHostSCSICommon {
int channel;
int target;
int lun;
+ uint64_t host_features;
} VHostSCSICommon;
int vhost_scsi_common_start(VHostSCSICommon *vsc);
diff --git a/include/hw/virtio/vhost-user-scsi.h b/include/hw/virtio/vhost-user-scsi.h
index 3ec34ae867..e429cacd8e 100644
--- a/include/hw/virtio/vhost-user-scsi.h
+++ b/include/hw/virtio/vhost-user-scsi.h
@@ -30,7 +30,6 @@
typedef struct VHostUserSCSI {
VHostSCSICommon parent_obj;
- uint64_t host_features;
VhostUserState *vhost_user;
} VHostUserSCSI;
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index 721aa2416a..e59f9ae1e9 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -276,7 +276,9 @@ bool qemu_mutex_iothread_locked(void);
* NOTE: tools currently are single-threaded and qemu_mutex_lock_iothread
* is a no-op there.
*/
-void qemu_mutex_lock_iothread(void);
+#define qemu_mutex_lock_iothread() \
+ qemu_mutex_lock_iothread_impl(__FILE__, __LINE__)
+void qemu_mutex_lock_iothread_impl(const char *file, int line);
/**
* qemu_mutex_unlock_iothread: Unlock the main loop mutex.
diff --git a/include/qemu/qht.h b/include/qemu/qht.h
index 1fb9116fa0..c9a11cc29a 100644
--- a/include/qemu/qht.h
+++ b/include/qemu/qht.h
@@ -46,6 +46,7 @@ typedef bool (*qht_lookup_func_t)(const void *obj, const void *userp);
typedef void (*qht_iter_func_t)(struct qht *ht, void *p, uint32_t h, void *up);
#define QHT_MODE_AUTO_RESIZE 0x1 /* auto-resize when heavily loaded */
+#define QHT_MODE_RAW_MUTEXES 0x2 /* bypass the profiler (QSP) */
/**
* qht_init - Initialize a QHT
diff --git a/include/qemu/qsp.h b/include/qemu/qsp.h
new file mode 100644
index 0000000000..a94c464f90
--- /dev/null
+++ b/include/qemu/qsp.h
@@ -0,0 +1,29 @@
+/*
+ * qsp.c - QEMU Synchronization Profiler
+ *
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * Note: this header file can *only* be included from thread.h.
+ */
+#ifndef QEMU_QSP_H
+#define QEMU_QSP_H
+
+#include "qemu/fprintf-fn.h"
+
+enum QSPSortBy {
+ QSP_SORT_BY_TOTAL_WAIT_TIME,
+ QSP_SORT_BY_AVG_WAIT_TIME,
+};
+
+void qsp_report(FILE *f, fprintf_function cpu_fprintf, size_t max,
+ enum QSPSortBy sort_by, bool callsite_coalesce);
+
+bool qsp_is_enabled(void);
+void qsp_enable(void);
+void qsp_disable(void);
+void qsp_reset(void);
+
+#endif /* QEMU_QSP_H */
diff --git a/include/qemu/rcu_queue.h b/include/qemu/rcu_queue.h
index 01be77407b..904b3372dc 100644
--- a/include/qemu/rcu_queue.h
+++ b/include/qemu/rcu_queue.h
@@ -36,7 +36,7 @@ extern "C" {
/*
* List access methods.
*/
-#define QLIST_EMPTY_RCU(head) (atomic_rcu_read(&(head)->lh_first) == NULL)
+#define QLIST_EMPTY_RCU(head) (atomic_read(&(head)->lh_first) == NULL)
#define QLIST_FIRST_RCU(head) (atomic_rcu_read(&(head)->lh_first))
#define QLIST_NEXT_RCU(elm, field) (atomic_rcu_read(&(elm)->field.le_next))
@@ -112,7 +112,7 @@ extern "C" {
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
} \
- *(elm)->field.le_prev = (elm)->field.le_next; \
+ atomic_set((elm)->field.le_prev, (elm)->field.le_next); \
} while (/*CONSTCOND*/0)
/* List traversal must occur within an RCU critical section. */
@@ -128,6 +128,137 @@ extern "C" {
((next_var) = atomic_rcu_read(&(var)->field.le_next), 1); \
(var) = (next_var))
+/*
+ * RCU simple queue
+ */
+
+/* Simple queue access methods */
+#define QSIMPLEQ_EMPTY_RCU(head) (atomic_read(&(head)->sqh_first) == NULL)
+#define QSIMPLEQ_FIRST_RCU(head) atomic_rcu_read(&(head)->sqh_first)
+#define QSIMPLEQ_NEXT_RCU(elm, field) atomic_rcu_read(&(elm)->field.sqe_next)
+
+/* Simple queue functions */
+#define QSIMPLEQ_INSERT_HEAD_RCU(head, elm, field) do { \
+ (elm)->field.sqe_next = (head)->sqh_first; \
+ if ((elm)->field.sqe_next == NULL) { \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ } \
+ atomic_rcu_set(&(head)->sqh_first, (elm)); \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_INSERT_TAIL_RCU(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ atomic_rcu_set((head)->sqh_last, (elm)); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_INSERT_AFTER_RCU(head, listelm, elm, field) do { \
+ (elm)->field.sqe_next = (listelm)->field.sqe_next; \
+ if ((elm)->field.sqe_next == NULL) { \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ } \
+ atomic_rcu_set(&(listelm)->field.sqe_next, (elm)); \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_REMOVE_HEAD_RCU(head, field) do { \
+ atomic_set(&(head)->sqh_first, (head)->sqh_first->field.sqe_next); \
+ if ((head)->sqh_first == NULL) { \
+ (head)->sqh_last = &(head)->sqh_first; \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_REMOVE_RCU(head, elm, type, field) do { \
+ if ((head)->sqh_first == (elm)) { \
+ QSIMPLEQ_REMOVE_HEAD_RCU((head), field); \
+ } else { \
+ struct type *curr = (head)->sqh_first; \
+ while (curr->field.sqe_next != (elm)) { \
+ curr = curr->field.sqe_next; \
+ } \
+ atomic_set(&curr->field.sqe_next, \
+ curr->field.sqe_next->field.sqe_next); \
+ if (curr->field.sqe_next == NULL) { \
+ (head)->sqh_last = &(curr)->field.sqe_next; \
+ } \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define QSIMPLEQ_FOREACH_RCU(var, head, field) \
+ for ((var) = atomic_rcu_read(&(head)->sqh_first); \
+ (var); \
+ (var) = atomic_rcu_read(&(var)->field.sqe_next))
+
+#define QSIMPLEQ_FOREACH_SAFE_RCU(var, head, field, next) \
+ for ((var) = atomic_rcu_read(&(head)->sqh_first); \
+ (var) && ((next) = atomic_rcu_read(&(var)->field.sqe_next), 1); \
+ (var) = (next))
+
+/*
+ * RCU tail queue
+ */
+
+/* Tail queue access methods */
+#define QTAILQ_EMPTY_RCU(head) (atomic_read(&(head)->tqh_first) == NULL)
+#define QTAILQ_FIRST_RCU(head) atomic_rcu_read(&(head)->tqh_first)
+#define QTAILQ_NEXT_RCU(elm, field) atomic_rcu_read(&(elm)->field.tqe_next)
+
+/* Tail queue functions */
+#define QTAILQ_INSERT_HEAD_RCU(head, elm, field) do { \
+ (elm)->field.tqe_next = (head)->tqh_first; \
+ if ((elm)->field.tqe_next != NULL) { \
+ (head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \
+ } else { \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ } \
+ atomic_rcu_set(&(head)->tqh_first, (elm)); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_TAIL_RCU(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ atomic_rcu_set((head)->tqh_last, (elm)); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_AFTER_RCU(head, listelm, elm, field) do { \
+ (elm)->field.tqe_next = (listelm)->field.tqe_next; \
+ if ((elm)->field.tqe_next != NULL) { \
+ (elm)->field.tqe_next->field.tqe_prev = &(elm)->field.tqe_next; \
+ } else { \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ } \
+ atomic_rcu_set(&(listelm)->field.tqe_next, (elm)); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_BEFORE_RCU(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ atomic_rcu_set((listelm)->field.tqe_prev, (elm)); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+ } while (/*CONSTCOND*/0)
+
+#define QTAILQ_REMOVE_RCU(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) { \
+ (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \
+ } else { \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ } \
+ atomic_set((elm)->field.tqe_prev, (elm)->field.tqe_next); \
+ (elm)->field.tqe_prev = NULL; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_FOREACH_RCU(var, head, field) \
+ for ((var) = atomic_rcu_read(&(head)->tqh_first); \
+ (var); \
+ (var) = atomic_rcu_read(&(var)->field.tqe_next))
+
+#define QTAILQ_FOREACH_SAFE_RCU(var, head, field, next) \
+ for ((var) = atomic_rcu_read(&(head)->tqh_first); \
+ (var) && ((next) = atomic_rcu_read(&(var)->field.tqe_next), 1); \
+ (var) = (next))
+
#ifdef __cplusplus
}
#endif
diff --git a/include/qemu/seqlock.h b/include/qemu/seqlock.h
index 8dee11d101..fd408b7ec5 100644
--- a/include/qemu/seqlock.h
+++ b/include/qemu/seqlock.h
@@ -16,6 +16,7 @@
#include "qemu/atomic.h"
#include "qemu/thread.h"
+#include "qemu/lockable.h"
typedef struct QemuSeqLock QemuSeqLock;
@@ -45,7 +46,26 @@ static inline void seqlock_write_end(QemuSeqLock *sl)
atomic_set(&sl->sequence, sl->sequence + 1);
}
-static inline unsigned seqlock_read_begin(QemuSeqLock *sl)
+/* Lock out other writers and update the count. */
+static inline void seqlock_write_lock_impl(QemuSeqLock *sl, QemuLockable *lock)
+{
+ qemu_lockable_lock(lock);
+ seqlock_write_begin(sl);
+}
+#define seqlock_write_lock(sl, lock) \
+ seqlock_write_lock_impl(sl, QEMU_MAKE_LOCKABLE(lock))
+
+/* Lock out other writers and update the count. */
+static inline void seqlock_write_unlock_impl(QemuSeqLock *sl, QemuLockable *lock)
+{
+ qemu_lockable_unlock(lock);
+ seqlock_write_begin(sl);
+}
+#define seqlock_write_unlock(sl, lock) \
+ seqlock_write_unlock_impl(sl, QEMU_MAKE_LOCKABLE(lock))
+
+
+static inline unsigned seqlock_read_begin(const QemuSeqLock *sl)
{
/* Always fail if a write is in progress. */
unsigned ret = atomic_read(&sl->sequence);
diff --git a/include/qemu/thread-posix.h b/include/qemu/thread-posix.h
index fd27b34128..c903525062 100644
--- a/include/qemu/thread-posix.h
+++ b/include/qemu/thread-posix.h
@@ -6,8 +6,8 @@
typedef QemuMutex QemuRecMutex;
#define qemu_rec_mutex_destroy qemu_mutex_destroy
-#define qemu_rec_mutex_lock qemu_mutex_lock
-#define qemu_rec_mutex_trylock qemu_mutex_trylock
+#define qemu_rec_mutex_lock_impl qemu_mutex_lock_impl
+#define qemu_rec_mutex_trylock_impl qemu_mutex_trylock_impl
#define qemu_rec_mutex_unlock qemu_mutex_unlock
struct QemuMutex {
diff --git a/include/qemu/thread-win32.h b/include/qemu/thread-win32.h
index d668d789b4..50af5dd7ab 100644
--- a/include/qemu/thread-win32.h
+++ b/include/qemu/thread-win32.h
@@ -19,8 +19,9 @@ struct QemuRecMutex {
};
void qemu_rec_mutex_destroy(QemuRecMutex *mutex);
-void qemu_rec_mutex_lock(QemuRecMutex *mutex);
-int qemu_rec_mutex_trylock(QemuRecMutex *mutex);
+void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line);
+int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file,
+ int line);
void qemu_rec_mutex_unlock(QemuRecMutex *mutex);
struct QemuCond {
diff --git a/include/qemu/thread.h b/include/qemu/thread.h
index ef7bd16123..dacebcfff0 100644
--- a/include/qemu/thread.h
+++ b/include/qemu/thread.h
@@ -16,6 +16,9 @@ typedef struct QemuThread QemuThread;
#include "qemu/thread-posix.h"
#endif
+/* include QSP header once QemuMutex, QemuCond etc. are defined */
+#include "qemu/qsp.h"
+
#define QEMU_THREAD_JOINABLE 0
#define QEMU_THREAD_DETACHED 1
@@ -25,10 +28,52 @@ int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line);
void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line);
void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line);
-#define qemu_mutex_lock(mutex) \
- qemu_mutex_lock_impl(mutex, __FILE__, __LINE__)
-#define qemu_mutex_trylock(mutex) \
- qemu_mutex_trylock_impl(mutex, __FILE__, __LINE__)
+typedef void (*QemuMutexLockFunc)(QemuMutex *m, const char *f, int l);
+typedef int (*QemuMutexTrylockFunc)(QemuMutex *m, const char *f, int l);
+typedef void (*QemuRecMutexLockFunc)(QemuRecMutex *m, const char *f, int l);
+typedef int (*QemuRecMutexTrylockFunc)(QemuRecMutex *m, const char *f, int l);
+typedef void (*QemuCondWaitFunc)(QemuCond *c, QemuMutex *m, const char *f,
+ int l);
+
+extern QemuMutexLockFunc qemu_bql_mutex_lock_func;
+extern QemuMutexLockFunc qemu_mutex_lock_func;
+extern QemuMutexTrylockFunc qemu_mutex_trylock_func;
+extern QemuRecMutexLockFunc qemu_rec_mutex_lock_func;
+extern QemuRecMutexTrylockFunc qemu_rec_mutex_trylock_func;
+extern QemuCondWaitFunc qemu_cond_wait_func;
+
+/* convenience macros to bypass the profiler */
+#define qemu_mutex_lock__raw(m) \
+ qemu_mutex_lock_impl(m, __FILE__, __LINE__)
+#define qemu_mutex_trylock__raw(m) \
+ qemu_mutex_trylock_impl(m, __FILE__, __LINE__)
+
+#define qemu_mutex_lock(m) ({ \
+ QemuMutexLockFunc _f = atomic_read(&qemu_mutex_lock_func); \
+ _f(m, __FILE__, __LINE__); \
+ })
+
+#define qemu_mutex_trylock(m) ({ \
+ QemuMutexTrylockFunc _f = atomic_read(&qemu_mutex_trylock_func); \
+ _f(m, __FILE__, __LINE__); \
+ })
+
+#define qemu_rec_mutex_lock(m) ({ \
+ QemuRecMutexLockFunc _f = atomic_read(&qemu_rec_mutex_lock_func); \
+ _f(m, __FILE__, __LINE__); \
+ })
+
+#define qemu_rec_mutex_trylock(m) ({ \
+ QemuRecMutexTrylockFunc _f; \
+ _f = atomic_read(&qemu_rec_mutex_trylock_func); \
+ _f(m, __FILE__, __LINE__); \
+ })
+
+#define qemu_cond_wait(c, m) ({ \
+ QemuCondWaitFunc _f = atomic_read(&qemu_cond_wait_func); \
+ _f(c, m, __FILE__, __LINE__); \
+ })
+
#define qemu_mutex_unlock(mutex) \
qemu_mutex_unlock_impl(mutex, __FILE__, __LINE__)
@@ -47,6 +92,16 @@ static inline void (qemu_mutex_unlock)(QemuMutex *mutex)
qemu_mutex_unlock(mutex);
}
+static inline void (qemu_rec_mutex_lock)(QemuRecMutex *mutex)
+{
+ qemu_rec_mutex_lock(mutex);
+}
+
+static inline int (qemu_rec_mutex_trylock)(QemuRecMutex *mutex)
+{
+ return qemu_rec_mutex_trylock(mutex);
+}
+
/* Prototypes for other functions are in thread-posix.h/thread-win32.h. */
void qemu_rec_mutex_init(QemuRecMutex *mutex);
@@ -63,9 +118,6 @@ void qemu_cond_broadcast(QemuCond *cond);
void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex,
const char *file, const int line);
-#define qemu_cond_wait(cond, mutex) \
- qemu_cond_wait_impl(cond, mutex, __FILE__, __LINE__)
-
static inline void (qemu_cond_wait)(QemuCond *cond, QemuMutex *mutex)
{
qemu_cond_wait(cond, mutex);
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index ecf6ed556a..dc130cd307 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -26,6 +26,7 @@
#include "exec/memattrs.h"
#include "qapi/qapi-types-run-state.h"
#include "qemu/bitmap.h"
+#include "qemu/rcu_queue.h"
#include "qemu/queue.h"
#include "qemu/thread.h"
@@ -442,13 +443,11 @@ struct CPUState {
QTAILQ_HEAD(CPUTailQ, CPUState);
extern struct CPUTailQ cpus;
-#define CPU_NEXT(cpu) QTAILQ_NEXT(cpu, node)
-#define CPU_FOREACH(cpu) QTAILQ_FOREACH(cpu, &cpus, node)
+#define first_cpu QTAILQ_FIRST_RCU(&cpus)
+#define CPU_NEXT(cpu) QTAILQ_NEXT_RCU(cpu, node)
+#define CPU_FOREACH(cpu) QTAILQ_FOREACH_RCU(cpu, &cpus, node)
#define CPU_FOREACH_SAFE(cpu, next_cpu) \
- QTAILQ_FOREACH_SAFE(cpu, &cpus, node, next_cpu)
-#define CPU_FOREACH_REVERSE(cpu) \
- QTAILQ_FOREACH_REVERSE(cpu, &cpus, CPUTailQ, node)
-#define first_cpu QTAILQ_FIRST(&cpus)
+ QTAILQ_FOREACH_SAFE_RCU(cpu, &cpus, node, next_cpu)
extern __thread CPUState *current_cpu;
diff --git a/include/standard-headers/linux/qemu_fw_cfg.h b/include/standard-headers/linux/qemu_fw_cfg.h
new file mode 100644
index 0000000000..cb93f6678d
--- /dev/null
+++ b/include/standard-headers/linux/qemu_fw_cfg.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+#ifndef _LINUX_FW_CFG_H
+#define _LINUX_FW_CFG_H
+
+#include "standard-headers/linux/types.h"
+
+#define FW_CFG_ACPI_DEVICE_ID "QEMU0002"
+
+/* selector key values for "well-known" fw_cfg entries */
+#define FW_CFG_SIGNATURE 0x00
+#define FW_CFG_ID 0x01
+#define FW_CFG_UUID 0x02
+#define FW_CFG_RAM_SIZE 0x03
+#define FW_CFG_NOGRAPHIC 0x04
+#define FW_CFG_NB_CPUS 0x05
+#define FW_CFG_MACHINE_ID 0x06
+#define FW_CFG_KERNEL_ADDR 0x07
+#define FW_CFG_KERNEL_SIZE 0x08
+#define FW_CFG_KERNEL_CMDLINE 0x09
+#define FW_CFG_INITRD_ADDR 0x0a
+#define FW_CFG_INITRD_SIZE 0x0b
+#define FW_CFG_BOOT_DEVICE 0x0c
+#define FW_CFG_NUMA 0x0d
+#define FW_CFG_BOOT_MENU 0x0e
+#define FW_CFG_MAX_CPUS 0x0f
+#define FW_CFG_KERNEL_ENTRY 0x10
+#define FW_CFG_KERNEL_DATA 0x11
+#define FW_CFG_INITRD_DATA 0x12
+#define FW_CFG_CMDLINE_ADDR 0x13
+#define FW_CFG_CMDLINE_SIZE 0x14
+#define FW_CFG_CMDLINE_DATA 0x15
+#define FW_CFG_SETUP_ADDR 0x16
+#define FW_CFG_SETUP_SIZE 0x17
+#define FW_CFG_SETUP_DATA 0x18
+#define FW_CFG_FILE_DIR 0x19
+
+#define FW_CFG_FILE_FIRST 0x20
+#define FW_CFG_FILE_SLOTS_MIN 0x10
+
+#define FW_CFG_WRITE_CHANNEL 0x4000
+#define FW_CFG_ARCH_LOCAL 0x8000
+#define FW_CFG_ENTRY_MASK (~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL))
+
+#define FW_CFG_INVALID 0xffff
+
+/* width in bytes of fw_cfg control register */
+#define FW_CFG_CTL_SIZE 0x02
+
+/* fw_cfg "file name" is up to 56 characters (including terminating nul) */
+#define FW_CFG_MAX_FILE_PATH 56
+
+/* size in bytes of fw_cfg signature */
+#define FW_CFG_SIG_SIZE 4
+
+/* FW_CFG_ID bits */
+#define FW_CFG_VERSION 0x01
+#define FW_CFG_VERSION_DMA 0x02
+
+/* fw_cfg file directory entry type */
+struct fw_cfg_file {
+ uint32_t size;
+ uint16_t select;
+ uint16_t reserved;
+ char name[FW_CFG_MAX_FILE_PATH];
+};
+
+/* FW_CFG_DMA_CONTROL bits */
+#define FW_CFG_DMA_CTL_ERROR 0x01
+#define FW_CFG_DMA_CTL_READ 0x02
+#define FW_CFG_DMA_CTL_SKIP 0x04
+#define FW_CFG_DMA_CTL_SELECT 0x08
+#define FW_CFG_DMA_CTL_WRITE 0x10
+
+#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
+
+/* Control as first field allows for different structures selected by this
+ * field, which might be useful in the future
+ */
+struct fw_cfg_dma_access {
+ uint32_t control;
+ uint32_t length;
+ uint64_t address;
+};
+
+#define FW_CFG_VMCOREINFO_FILENAME "etc/vmcoreinfo"
+
+#define FW_CFG_VMCOREINFO_FORMAT_NONE 0x0
+#define FW_CFG_VMCOREINFO_FORMAT_ELF 0x1
+
+struct fw_cfg_vmcoreinfo {
+ uint16_t host_format;
+ uint16_t guest_format;
+ uint32_t size;
+ uint64_t paddr;
+};
+
+#endif
diff --git a/job.c b/job.c
index fa671b431a..e36ebaafd8 100644
--- a/job.c
+++ b/job.c
@@ -732,10 +732,10 @@ static void job_cancel_async(Job *job, bool force)
{
if (job->user_paused) {
/* Do not call job_enter here, the caller will handle it. */
- job->user_paused = false;
if (job->driver->user_resume) {
job->driver->user_resume(job);
}
+ job->user_paused = false;
assert(job->pause_count > 0);
job->pause_count--;
}
diff --git a/linux-user/main.c b/linux-user/main.c
index ea00dd9057..923cbb753a 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -126,7 +126,7 @@ void fork_end(int child)
Discard information about the parent threads. */
CPU_FOREACH_SAFE(cpu, next_cpu) {
if (cpu != thread_cpu) {
- QTAILQ_REMOVE(&cpus, cpu, node);
+ QTAILQ_REMOVE_RCU(&cpus, cpu, node);
}
}
qemu_init_cpu_list();
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 202aa777ad..850b72a0c7 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -163,7 +163,6 @@
* (The one remaining unallocated bit is 0x1000 which used to be CLONE_PID.)
*/
-//#define DEBUG
/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
* once. This exercises the codepaths for restart.
*/
@@ -5884,9 +5883,6 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg)
ie++;
}
arg_type = ie->arg_type;
-#if defined(DEBUG)
- gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
-#endif
if (ie->do_ioctl) {
return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
} else if (!ie->host_cmd) {
@@ -8096,13 +8092,15 @@ static int host_to_target_cpu_mask(const unsigned long *host_mask,
return 0;
}
-/* do_syscall() should always have a single exit point at the end so
- that actions, such as logging of syscall results, can be performed.
- All errnos that do_syscall() returns must be -TARGET_<errcode>. */
-abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
- abi_long arg2, abi_long arg3, abi_long arg4,
- abi_long arg5, abi_long arg6, abi_long arg7,
- abi_long arg8)
+/* This is an internal helper for do_syscall so that it is easier
+ * to have a single return point, so that actions, such as logging
+ * of syscall results, can be performed.
+ * All errnos that do_syscall() returns must be -TARGET_<errcode>.
+ */
+static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
+ abi_long arg2, abi_long arg3, abi_long arg4,
+ abi_long arg5, abi_long arg6, abi_long arg7,
+ abi_long arg8)
{
CPUState *cpu = ENV_GET_CPU(cpu_env);
abi_long ret;
@@ -8117,28 +8115,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
void *p;
-#if defined(DEBUG_ERESTARTSYS)
- /* Debug-only code for exercising the syscall-restart code paths
- * in the per-architecture cpu main loops: restart every syscall
- * the guest makes once before letting it through.
- */
- {
- static int flag;
-
- flag = !flag;
- if (flag) {
- return -TARGET_ERESTARTSYS;
- }
- }
-#endif
-
-#ifdef DEBUG
- gemu_log("syscall %d", num);
-#endif
- trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
- if(do_strace)
- print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
-
switch(num) {
case TARGET_NR_exit:
/* In old applications this may be used to implement _exit(2).
@@ -8147,8 +8123,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
Do thread termination if we have more then one thread. */
if (block_signals()) {
- ret = -TARGET_ERESTARTSYS;
- break;
+ return -TARGET_ERESTARTSYS;
}
cpu_list_lock();
@@ -8157,7 +8132,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
TaskState *ts;
/* Remove the CPU from the list. */
- QTAILQ_REMOVE(&cpus, cpu, node);
+ QTAILQ_REMOVE_RCU(&cpus, cpu, node);
cpu_list_unlock();
@@ -8177,14 +8152,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
cpu_list_unlock();
preexit_cleanup(cpu_env, arg1);
_exit(arg1);
- ret = 0; /* avoid warning */
- break;
+ return 0; /* avoid warning */
case TARGET_NR_read:
- if (arg3 == 0)
- ret = 0;
- else {
+ if (arg3 == 0) {
+ return 0;
+ } else {
if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(safe_read(arg1, p, arg3));
if (ret >= 0 &&
fd_trans_host_to_target_data(arg1)) {
@@ -8192,10 +8166,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
unlock_user(p, arg2, ret);
}
- break;
+ return ret;
case TARGET_NR_write:
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
- goto efault;
+ return -TARGET_EFAULT;
if (fd_trans_target_to_host_data(arg1)) {
void *copy = g_malloc(arg3);
memcpy(copy, p, arg3);
@@ -8208,49 +8182,48 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(safe_write(arg1, p, arg3));
}
unlock_user(p, arg2, 0);
- break;
+ return ret;
+
#ifdef TARGET_NR_open
case TARGET_NR_open:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
target_to_host_bitmask(arg2, fcntl_flags_tbl),
arg3));
fd_trans_unregister(ret);
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
case TARGET_NR_openat:
if (!(p = lock_user_string(arg2)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(do_openat(cpu_env, arg1, p,
target_to_host_bitmask(arg3, fcntl_flags_tbl),
arg4));
fd_trans_unregister(ret);
unlock_user(p, arg2, 0);
- break;
+ return ret;
#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
case TARGET_NR_name_to_handle_at:
ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
- break;
+ return ret;
#endif
#if defined(TARGET_NR_open_by_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
case TARGET_NR_open_by_handle_at:
ret = do_open_by_handle_at(arg1, arg2, arg3);
fd_trans_unregister(ret);
- break;
+ return ret;
#endif
case TARGET_NR_close:
fd_trans_unregister(arg1);
- ret = get_errno(close(arg1));
- break;
+ return get_errno(close(arg1));
+
case TARGET_NR_brk:
- ret = do_brk(arg1);
- break;
+ return do_brk(arg1);
#ifdef TARGET_NR_fork
case TARGET_NR_fork:
- ret = get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
- break;
+ return get_errno(do_fork(cpu_env, TARGET_SIGCHLD, 0, 0, 0, 0));
#endif
#ifdef TARGET_NR_waitpid
case TARGET_NR_waitpid:
@@ -8259,9 +8232,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
if (!is_error(ret) && arg2 && ret
&& put_user_s32(host_to_target_waitstatus(status), arg2))
- goto efault;
+ return -TARGET_EFAULT;
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_waitid
case TARGET_NR_waitid:
@@ -8271,21 +8244,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
if (!is_error(ret) && arg3 && info.si_pid != 0) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
- goto efault;
+ return -TARGET_EFAULT;
host_to_target_siginfo(p, &info);
unlock_user(p, arg3, sizeof(target_siginfo_t));
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_creat /* not on alpha */
case TARGET_NR_creat:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(creat(p, arg2));
fd_trans_unregister(ret);
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_link
case TARGET_NR_link:
@@ -8300,14 +8273,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p2, arg2, 0);
unlock_user(p, arg1, 0);
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_linkat)
case TARGET_NR_linkat:
{
void * p2 = NULL;
if (!arg2 || !arg4)
- goto efault;
+ return -TARGET_EFAULT;
p = lock_user_string(arg2);
p2 = lock_user_string(arg4);
if (!p || !p2)
@@ -8317,23 +8290,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg2, 0);
unlock_user(p2, arg4, 0);
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_unlink
case TARGET_NR_unlink:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(unlink(p));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#if defined(TARGET_NR_unlinkat)
case TARGET_NR_unlinkat:
if (!(p = lock_user_string(arg2)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(unlinkat(arg1, p, arg3));
unlock_user(p, arg2, 0);
- break;
+ return ret;
#endif
case TARGET_NR_execve:
{
@@ -8350,7 +8323,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
guest_argp = arg2;
for (gp = guest_argp; gp; gp += sizeof(abi_ulong)) {
if (get_user_ual(addr, gp))
- goto efault;
+ return -TARGET_EFAULT;
if (!addr)
break;
argc++;
@@ -8359,7 +8332,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
guest_envp = arg3;
for (gp = guest_envp; gp; gp += sizeof(abi_ulong)) {
if (get_user_ual(addr, gp))
- goto efault;
+ return -TARGET_EFAULT;
if (!addr)
break;
envc++;
@@ -8431,13 +8404,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
g_free(argp);
g_free(envp);
}
- break;
+ return ret;
case TARGET_NR_chdir:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(chdir(p));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#ifdef TARGET_NR_time
case TARGET_NR_time:
{
@@ -8446,58 +8419,47 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret)
&& arg1
&& put_user_sal(host_time, arg1))
- goto efault;
+ return -TARGET_EFAULT;
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_mknod
case TARGET_NR_mknod:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(mknod(p, arg2, arg3));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#if defined(TARGET_NR_mknodat)
case TARGET_NR_mknodat:
if (!(p = lock_user_string(arg2)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(mknodat(arg1, p, arg3, arg4));
unlock_user(p, arg2, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_chmod
case TARGET_NR_chmod:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(chmod(p, arg2));
unlock_user(p, arg1, 0);
- break;
-#endif
-#ifdef TARGET_NR_break
- case TARGET_NR_break:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_oldstat
- case TARGET_NR_oldstat:
- goto unimplemented;
+ return ret;
#endif
#ifdef TARGET_NR_lseek
case TARGET_NR_lseek:
- ret = get_errno(lseek(arg1, arg2, arg3));
- break;
+ return get_errno(lseek(arg1, arg2, arg3));
#endif
#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
/* Alpha specific */
case TARGET_NR_getxpid:
((CPUAlphaState *)cpu_env)->ir[IR_A4] = getppid();
- ret = get_errno(getpid());
- break;
+ return get_errno(getpid());
#endif
#ifdef TARGET_NR_getpid
case TARGET_NR_getpid:
- ret = get_errno(getpid());
- break;
+ return get_errno(getpid());
#endif
case TARGET_NR_mount:
{
@@ -8507,7 +8469,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg1) {
p = lock_user_string(arg1);
if (!p) {
- goto efault;
+ return -TARGET_EFAULT;
}
} else {
p = NULL;
@@ -8518,7 +8480,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg1) {
unlock_user(p, arg1, 0);
}
- goto efault;
+ return -TARGET_EFAULT;
}
if (arg3) {
@@ -8528,7 +8490,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
}
unlock_user(p2, arg2, 0);
- goto efault;
+ return -TARGET_EFAULT;
}
} else {
p3 = NULL;
@@ -8553,43 +8515,34 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p3, arg3, 0);
}
}
- break;
+ return ret;
#ifdef TARGET_NR_umount
case TARGET_NR_umount:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(umount(p));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_stime /* not on alpha */
case TARGET_NR_stime:
{
time_t host_time;
if (get_user_sal(host_time, arg1))
- goto efault;
- ret = get_errno(stime(&host_time));
+ return -TARGET_EFAULT;
+ return get_errno(stime(&host_time));
}
- break;
#endif
- case TARGET_NR_ptrace:
- goto unimplemented;
#ifdef TARGET_NR_alarm /* not on alpha */
case TARGET_NR_alarm:
- ret = alarm(arg1);
- break;
-#endif
-#ifdef TARGET_NR_oldfstat
- case TARGET_NR_oldfstat:
- goto unimplemented;
+ return alarm(arg1);
#endif
#ifdef TARGET_NR_pause /* not on alpha */
case TARGET_NR_pause:
if (!block_signals()) {
sigsuspend(&((TaskState *)cpu->opaque)->signal_mask);
}
- ret = -TARGET_EINTR;
- break;
+ return -TARGET_EINTR;
#endif
#ifdef TARGET_NR_utime
case TARGET_NR_utime:
@@ -8598,7 +8551,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_utimbuf *target_tbuf;
if (arg2) {
if (!lock_user_struct(VERIFY_READ, target_tbuf, arg2, 1))
- goto efault;
+ return -TARGET_EFAULT;
tbuf.actime = tswapal(target_tbuf->actime);
tbuf.modtime = tswapal(target_tbuf->modtime);
unlock_user_struct(target_tbuf, arg2, 0);
@@ -8607,11 +8560,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
host_tbuf = NULL;
}
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(utime(p, host_tbuf));
unlock_user(p, arg1, 0);
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_utimes
case TARGET_NR_utimes:
@@ -8621,17 +8574,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (copy_from_user_timeval(&tv[0], arg2)
|| copy_from_user_timeval(&tv[1],
arg2 + sizeof(struct target_timeval)))
- goto efault;
+ return -TARGET_EFAULT;
tvp = tv;
} else {
tvp = NULL;
}
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(utimes(p, tvp));
unlock_user(p, arg1, 0);
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_futimesat)
case TARGET_NR_futimesat:
@@ -8641,63 +8594,50 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (copy_from_user_timeval(&tv[0], arg3)
|| copy_from_user_timeval(&tv[1],
arg3 + sizeof(struct target_timeval)))
- goto efault;
+ return -TARGET_EFAULT;
tvp = tv;
} else {
tvp = NULL;
}
- if (!(p = lock_user_string(arg2)))
- goto efault;
+ if (!(p = lock_user_string(arg2))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(futimesat(arg1, path(p), tvp));
unlock_user(p, arg2, 0);
}
- break;
-#endif
-#ifdef TARGET_NR_stty
- case TARGET_NR_stty:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_gtty
- case TARGET_NR_gtty:
- goto unimplemented;
+ return ret;
#endif
#ifdef TARGET_NR_access
case TARGET_NR_access:
- if (!(p = lock_user_string(arg1)))
- goto efault;
+ if (!(p = lock_user_string(arg1))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(access(path(p), arg2));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
case TARGET_NR_faccessat:
- if (!(p = lock_user_string(arg2)))
- goto efault;
+ if (!(p = lock_user_string(arg2))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(faccessat(arg1, p, arg3, 0));
unlock_user(p, arg2, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_nice /* not on alpha */
case TARGET_NR_nice:
- ret = get_errno(nice(arg1));
- break;
-#endif
-#ifdef TARGET_NR_ftime
- case TARGET_NR_ftime:
- goto unimplemented;
+ return get_errno(nice(arg1));
#endif
case TARGET_NR_sync:
sync();
- ret = 0;
- break;
+ return 0;
#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS)
case TARGET_NR_syncfs:
- ret = get_errno(syncfs(arg1));
- break;
+ return get_errno(syncfs(arg1));
#endif
case TARGET_NR_kill:
- ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
- break;
+ return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
#ifdef TARGET_NR_rename
case TARGET_NR_rename:
{
@@ -8711,7 +8651,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p2, arg2, 0);
unlock_user(p, arg1, 0);
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_renameat)
case TARGET_NR_renameat:
@@ -8726,7 +8666,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p2, arg4, 0);
unlock_user(p, arg2, 0);
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_renameat2)
case TARGET_NR_renameat2:
@@ -8742,48 +8682,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p2, arg4, 0);
unlock_user(p, arg2, 0);
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_mkdir
case TARGET_NR_mkdir:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(mkdir(p, arg2));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#if defined(TARGET_NR_mkdirat)
case TARGET_NR_mkdirat:
if (!(p = lock_user_string(arg2)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(mkdirat(arg1, p, arg3));
unlock_user(p, arg2, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_rmdir
case TARGET_NR_rmdir:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(rmdir(p));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
case TARGET_NR_dup:
ret = get_errno(dup(arg1));
if (ret >= 0) {
fd_trans_dup(arg1, ret);
}
- break;
+ return ret;
#ifdef TARGET_NR_pipe
case TARGET_NR_pipe:
- ret = do_pipe(cpu_env, arg1, 0, 0);
- break;
+ return do_pipe(cpu_env, arg1, 0, 0);
#endif
#ifdef TARGET_NR_pipe2
case TARGET_NR_pipe2:
- ret = do_pipe(cpu_env, arg1,
- target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
- break;
+ return do_pipe(cpu_env, arg1,
+ target_to_host_bitmask(arg2, fcntl_flags_tbl), 1);
#endif
case TARGET_NR_times:
{
@@ -8793,7 +8731,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg1) {
tmsp = lock_user(VERIFY_WRITE, arg1, sizeof(struct target_tms), 0);
if (!tmsp)
- goto efault;
+ return -TARGET_EFAULT;
tmsp->tms_utime = tswapal(host_to_target_clock_t(tms.tms_utime));
tmsp->tms_stime = tswapal(host_to_target_clock_t(tms.tms_stime));
tmsp->tms_cutime = tswapal(host_to_target_clock_t(tms.tms_cutime));
@@ -8802,80 +8740,49 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret))
ret = host_to_target_clock_t(ret);
}
- break;
-#ifdef TARGET_NR_prof
- case TARGET_NR_prof:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_signal
- case TARGET_NR_signal:
- goto unimplemented;
-#endif
+ return ret;
case TARGET_NR_acct:
if (arg1 == 0) {
ret = get_errno(acct(NULL));
} else {
- if (!(p = lock_user_string(arg1)))
- goto efault;
+ if (!(p = lock_user_string(arg1))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(acct(path(p)));
unlock_user(p, arg1, 0);
}
- break;
+ return ret;
#ifdef TARGET_NR_umount2
case TARGET_NR_umount2:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(umount2(p, arg2));
unlock_user(p, arg1, 0);
- break;
-#endif
-#ifdef TARGET_NR_lock
- case TARGET_NR_lock:
- goto unimplemented;
+ return ret;
#endif
case TARGET_NR_ioctl:
- ret = do_ioctl(arg1, arg2, arg3);
- break;
+ return do_ioctl(arg1, arg2, arg3);
#ifdef TARGET_NR_fcntl
case TARGET_NR_fcntl:
- ret = do_fcntl(arg1, arg2, arg3);
- break;
-#endif
-#ifdef TARGET_NR_mpx
- case TARGET_NR_mpx:
- goto unimplemented;
+ return do_fcntl(arg1, arg2, arg3);
#endif
case TARGET_NR_setpgid:
- ret = get_errno(setpgid(arg1, arg2));
- break;
-#ifdef TARGET_NR_ulimit
- case TARGET_NR_ulimit:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_oldolduname
- case TARGET_NR_oldolduname:
- goto unimplemented;
-#endif
+ return get_errno(setpgid(arg1, arg2));
case TARGET_NR_umask:
- ret = get_errno(umask(arg1));
- break;
+ return get_errno(umask(arg1));
case TARGET_NR_chroot:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(chroot(p));
unlock_user(p, arg1, 0);
- break;
-#ifdef TARGET_NR_ustat
- case TARGET_NR_ustat:
- goto unimplemented;
-#endif
+ return ret;
#ifdef TARGET_NR_dup2
case TARGET_NR_dup2:
ret = get_errno(dup2(arg1, arg2));
if (ret >= 0) {
fd_trans_dup(arg1, arg2);
}
- break;
+ return ret;
#endif
#if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
case TARGET_NR_dup3:
@@ -8890,22 +8797,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (ret >= 0) {
fd_trans_dup(arg1, arg2);
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_getppid /* not on alpha */
case TARGET_NR_getppid:
- ret = get_errno(getppid());
- break;
+ return get_errno(getppid());
#endif
#ifdef TARGET_NR_getpgrp
case TARGET_NR_getpgrp:
- ret = get_errno(getpgrp());
- break;
+ return get_errno(getpgrp());
#endif
case TARGET_NR_setsid:
- ret = get_errno(setsid());
- break;
+ return get_errno(setsid());
#ifdef TARGET_NR_sigaction
case TARGET_NR_sigaction:
{
@@ -8914,7 +8818,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_old_sigaction *old_act;
if (arg2) {
if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
- goto efault;
+ return -TARGET_EFAULT;
act._sa_handler = old_act->_sa_handler;
target_siginitset(&act.sa_mask, old_act->sa_mask);
act.sa_flags = old_act->sa_flags;
@@ -8925,7 +8829,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(do_sigaction(arg1, pact, &oact));
if (!is_error(ret) && arg3) {
if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
- goto efault;
+ return -TARGET_EFAULT;
old_act->_sa_handler = oact._sa_handler;
old_act->sa_mask = oact.sa_mask.sig[0];
old_act->sa_flags = oact.sa_flags;
@@ -8936,7 +8840,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg2) {
if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
- goto efault;
+ return -TARGET_EFAULT;
act._sa_handler = old_act->_sa_handler;
target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
act.sa_flags = old_act->sa_flags;
@@ -8950,7 +8854,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret) && arg3) {
if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
- goto efault;
+ return -TARGET_EFAULT;
old_act->_sa_handler = oact._sa_handler;
old_act->sa_flags = oact.sa_flags;
old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
@@ -8964,7 +8868,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_sigaction act, oact, *pact;
if (arg2) {
if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
- goto efault;
+ return -TARGET_EFAULT;
act._sa_handler = old_act->_sa_handler;
target_siginitset(&act.sa_mask, old_act->sa_mask);
act.sa_flags = old_act->sa_flags;
@@ -8980,7 +8884,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(do_sigaction(arg1, pact, &oact));
if (!is_error(ret) && arg3) {
if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
- goto efault;
+ return -TARGET_EFAULT;
old_act->_sa_handler = oact._sa_handler;
old_act->sa_mask = oact.sa_mask.sig[0];
old_act->sa_flags = oact.sa_flags;
@@ -8989,7 +8893,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
#endif
}
- break;
+ return ret;
#endif
case TARGET_NR_rt_sigaction:
{
@@ -9006,12 +8910,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_sigaction act, oact, *pact = 0;
if (arg4 != sizeof(target_sigset_t)) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
if (arg2) {
if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
- goto efault;
+ return -TARGET_EFAULT;
act._sa_handler = rt_act->_sa_handler;
act.sa_mask = rt_act->sa_mask;
act.sa_flags = rt_act->sa_flags;
@@ -9022,7 +8925,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(do_sigaction(arg1, pact, &oact));
if (!is_error(ret) && arg3) {
if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
- goto efault;
+ return -TARGET_EFAULT;
rt_act->_sa_handler = oact._sa_handler;
rt_act->sa_mask = oact.sa_mask;
rt_act->sa_flags = oact.sa_flags;
@@ -9039,12 +8942,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_sigaction *oact;
if (sigsetsize != sizeof(target_sigset_t)) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
if (arg2) {
if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
- goto efault;
+ return -TARGET_EFAULT;
}
#ifdef TARGET_ARCH_HAS_KA_RESTORER
act->ka_restorer = restorer;
@@ -9067,7 +8969,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user_struct(oact, arg3, 1);
#endif
}
- break;
+ return ret;
#ifdef TARGET_NR_sgetmask /* not on alpha */
case TARGET_NR_sgetmask:
{
@@ -9079,7 +8981,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = target_set;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_ssetmask /* not on alpha */
case TARGET_NR_ssetmask:
@@ -9093,7 +8995,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = target_set;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_sigprocmask
case TARGET_NR_sigprocmask:
@@ -9114,8 +9016,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = SIG_SETMASK;
break;
default:
- ret = -TARGET_EINVAL;
- goto fail;
+ return -TARGET_EINVAL;
}
mask = arg2;
target_to_host_old_sigset(&set, &mask);
@@ -9142,11 +9043,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = SIG_SETMASK;
break;
default:
- ret = -TARGET_EINVAL;
- goto fail;
+ return -TARGET_EINVAL;
}
if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
- goto efault;
+ return -TARGET_EFAULT;
target_to_host_old_sigset(&set, p);
unlock_user(p, arg2, 0);
set_ptr = &set;
@@ -9157,13 +9057,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = do_sigprocmask(how, set_ptr, &oldset);
if (!is_error(ret) && arg3) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
- goto efault;
+ return -TARGET_EFAULT;
host_to_target_old_sigset(p, &oldset);
unlock_user(p, arg3, sizeof(target_sigset_t));
}
#endif
}
- break;
+ return ret;
#endif
case TARGET_NR_rt_sigprocmask:
{
@@ -9171,8 +9071,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
sigset_t set, oldset, *set_ptr;
if (arg4 != sizeof(target_sigset_t)) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
if (arg2) {
@@ -9187,11 +9086,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = SIG_SETMASK;
break;
default:
- ret = -TARGET_EINVAL;
- goto fail;
+ return -TARGET_EINVAL;
}
if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
- goto efault;
+ return -TARGET_EFAULT;
target_to_host_sigset(&set, p);
unlock_user(p, arg2, 0);
set_ptr = &set;
@@ -9202,12 +9100,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = do_sigprocmask(how, set_ptr, &oldset);
if (!is_error(ret) && arg3) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
- goto efault;
+ return -TARGET_EFAULT;
host_to_target_sigset(p, &oldset);
unlock_user(p, arg3, sizeof(target_sigset_t));
}
}
- break;
+ return ret;
#ifdef TARGET_NR_sigpending
case TARGET_NR_sigpending:
{
@@ -9215,12 +9113,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(sigpending(&set));
if (!is_error(ret)) {
if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
- goto efault;
+ return -TARGET_EFAULT;
host_to_target_old_sigset(p, &set);
unlock_user(p, arg1, sizeof(target_sigset_t));
}
}
- break;
+ return ret;
#endif
case TARGET_NR_rt_sigpending:
{
@@ -9232,19 +9130,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
* the old_sigset_t is smaller in size.
*/
if (arg2 > sizeof(target_sigset_t)) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
ret = get_errno(sigpending(&set));
if (!is_error(ret)) {
if (!(p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0)))
- goto efault;
+ return -TARGET_EFAULT;
host_to_target_sigset(p, &set);
unlock_user(p, arg1, sizeof(target_sigset_t));
}
}
- break;
+ return ret;
#ifdef TARGET_NR_sigsuspend
case TARGET_NR_sigsuspend:
{
@@ -9254,7 +9151,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
#else
if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
- goto efault;
+ return -TARGET_EFAULT;
target_to_host_old_sigset(&ts->sigsuspend_mask, p);
unlock_user(p, arg1, 0);
#endif
@@ -9264,18 +9161,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ts->in_sigsuspend = 1;
}
}
- break;
+ return ret;
#endif
case TARGET_NR_rt_sigsuspend:
{
TaskState *ts = cpu->opaque;
if (arg2 != sizeof(target_sigset_t)) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
- goto efault;
+ return -TARGET_EFAULT;
target_to_host_sigset(&ts->sigsuspend_mask, p);
unlock_user(p, arg1, 0);
ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
@@ -9284,7 +9180,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ts->in_sigsuspend = 1;
}
}
- break;
+ return ret;
case TARGET_NR_rt_sigtimedwait:
{
sigset_t set;
@@ -9292,12 +9188,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
siginfo_t uinfo;
if (arg4 != sizeof(target_sigset_t)) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
- goto efault;
+ return -TARGET_EFAULT;
target_to_host_sigset(&set, p);
unlock_user(p, arg1, 0);
if (arg3) {
@@ -9313,7 +9208,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t),
0);
if (!p) {
- goto efault;
+ return -TARGET_EFAULT;
}
host_to_target_siginfo(p, &uinfo);
unlock_user(p, arg2, sizeof(target_siginfo_t));
@@ -9321,55 +9216,51 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = host_to_target_signal(ret);
}
}
- break;
+ return ret;
case TARGET_NR_rt_sigqueueinfo:
{
siginfo_t uinfo;
p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
if (!p) {
- goto efault;
+ return -TARGET_EFAULT;
}
target_to_host_siginfo(&uinfo, p);
unlock_user(p, arg3, 0);
ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
}
- break;
+ return ret;
case TARGET_NR_rt_tgsigqueueinfo:
{
siginfo_t uinfo;
p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
if (!p) {
- goto efault;
+ return -TARGET_EFAULT;
}
target_to_host_siginfo(&uinfo, p);
unlock_user(p, arg4, 0);
ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
}
- break;
+ return ret;
#ifdef TARGET_NR_sigreturn
case TARGET_NR_sigreturn:
if (block_signals()) {
- ret = -TARGET_ERESTARTSYS;
- } else {
- ret = do_sigreturn(cpu_env);
+ return -TARGET_ERESTARTSYS;
}
- break;
+ return do_sigreturn(cpu_env);
#endif
case TARGET_NR_rt_sigreturn:
if (block_signals()) {
- ret = -TARGET_ERESTARTSYS;
- } else {
- ret = do_rt_sigreturn(cpu_env);
+ return -TARGET_ERESTARTSYS;
}
- break;
+ return do_rt_sigreturn(cpu_env);
case TARGET_NR_sethostname:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(sethostname(p, arg2));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#ifdef TARGET_NR_setrlimit
case TARGET_NR_setrlimit:
{
@@ -9377,13 +9268,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_rlimit *target_rlim;
struct rlimit rlim;
if (!lock_user_struct(VERIFY_READ, target_rlim, arg2, 1))
- goto efault;
+ return -TARGET_EFAULT;
rlim.rlim_cur = target_to_host_rlim(target_rlim->rlim_cur);
rlim.rlim_max = target_to_host_rlim(target_rlim->rlim_max);
unlock_user_struct(target_rlim, arg2, 0);
- ret = get_errno(setrlimit(resource, &rlim));
+ return get_errno(setrlimit(resource, &rlim));
}
- break;
#endif
#ifdef TARGET_NR_getrlimit
case TARGET_NR_getrlimit:
@@ -9395,13 +9285,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(getrlimit(resource, &rlim));
if (!is_error(ret)) {
if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
- goto efault;
+ return -TARGET_EFAULT;
target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
unlock_user_struct(target_rlim, arg2, 1);
}
}
- break;
+ return ret;
#endif
case TARGET_NR_getrusage:
{
@@ -9411,17 +9301,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = host_to_target_rusage(arg2, &rusage);
}
}
- break;
+ return ret;
case TARGET_NR_gettimeofday:
{
struct timeval tv;
ret = get_errno(gettimeofday(&tv, NULL));
if (!is_error(ret)) {
if (copy_to_user_timeval(arg1, &tv))
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
case TARGET_NR_settimeofday:
{
struct timeval tv, *ptv = NULL;
@@ -9429,21 +9319,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg1) {
if (copy_from_user_timeval(&tv, arg1)) {
- goto efault;
+ return -TARGET_EFAULT;
}
ptv = &tv;
}
if (arg2) {
if (copy_from_user_timezone(&tz, arg2)) {
- goto efault;
+ return -TARGET_EFAULT;
}
ptz = &tz;
}
- ret = get_errno(settimeofday(ptv, ptz));
+ return get_errno(settimeofday(ptv, ptz));
}
- break;
#if defined(TARGET_NR_select)
case TARGET_NR_select:
#if defined(TARGET_WANT_NI_OLD_SELECT)
@@ -9456,7 +9345,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#else
ret = do_select(arg1, arg2, arg3, arg4, arg5);
#endif
- break;
+ return ret;
#endif
#ifdef TARGET_NR_pselect6
case TARGET_NR_pselect6:
@@ -9487,15 +9376,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
if (ret) {
- goto fail;
+ return ret;
}
ret = copy_from_user_fdset_ptr(&wfds, &wfds_ptr, wfd_addr, n);
if (ret) {
- goto fail;
+ return ret;
}
ret = copy_from_user_fdset_ptr(&efds, &efds_ptr, efd_addr, n);
if (ret) {
- goto fail;
+ return ret;
}
/*
@@ -9504,7 +9393,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
*/
if (ts_addr) {
if (target_to_host_timespec(&ts, ts_addr)) {
- goto efault;
+ return -TARGET_EFAULT;
}
ts_ptr = &ts;
} else {
@@ -9518,7 +9407,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
if (!arg7) {
- goto efault;
+ return -TARGET_EFAULT;
}
arg_sigset = tswapal(arg7[0]);
arg_sigsize = tswapal(arg7[1]);
@@ -9528,13 +9417,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
sig.set = &set;
if (arg_sigsize != sizeof(*target_sigset)) {
/* Like the kernel, we enforce correct size sigsets */
- ret = -TARGET_EINVAL;
- goto fail;
+ return -TARGET_EINVAL;
}
target_sigset = lock_user(VERIFY_READ, arg_sigset,
sizeof(*target_sigset), 1);
if (!target_sigset) {
- goto efault;
+ return -TARGET_EFAULT;
}
target_to_host_sigset(&set, target_sigset);
unlock_user(target_sigset, arg_sigset, 0);
@@ -9550,17 +9438,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret)) {
if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
- goto efault;
+ return -TARGET_EFAULT;
if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
- goto efault;
+ return -TARGET_EFAULT;
if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
- goto efault;
+ return -TARGET_EFAULT;
if (ts_addr && host_to_target_timespec(ts_addr, &ts))
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_symlink
case TARGET_NR_symlink:
@@ -9575,7 +9463,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p2, arg2, 0);
unlock_user(p, arg1, 0);
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_symlinkat)
case TARGET_NR_symlinkat:
@@ -9590,11 +9478,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p2, arg3, 0);
unlock_user(p, arg1, 0);
}
- break;
-#endif
-#ifdef TARGET_NR_oldlstat
- case TARGET_NR_oldlstat:
- goto unimplemented;
+ return ret;
#endif
#ifdef TARGET_NR_readlink
case TARGET_NR_readlink:
@@ -9626,7 +9510,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p2, arg2, ret);
unlock_user(p, arg1, 0);
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_readlinkat)
case TARGET_NR_readlinkat:
@@ -9647,37 +9531,29 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p2, arg3, ret);
unlock_user(p, arg2, 0);
}
- break;
-#endif
-#ifdef TARGET_NR_uselib
- case TARGET_NR_uselib:
- goto unimplemented;
+ return ret;
#endif
#ifdef TARGET_NR_swapon
case TARGET_NR_swapon:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(swapon(p, arg2));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
case TARGET_NR_reboot:
if (arg3 == LINUX_REBOOT_CMD_RESTART2) {
/* arg4 must be ignored in all other cases */
p = lock_user_string(arg4);
if (!p) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(reboot(arg1, arg2, arg3, p));
unlock_user(p, arg4, 0);
} else {
ret = get_errno(reboot(arg1, arg2, arg3, NULL));
}
- break;
-#ifdef TARGET_NR_readdir
- case TARGET_NR_readdir:
- goto unimplemented;
-#endif
+ return ret;
#ifdef TARGET_NR_mmap
case TARGET_NR_mmap:
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
@@ -9688,7 +9564,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
abi_ulong *v;
abi_ulong v1, v2, v3, v4, v5, v6;
if (!(v = lock_user(VERIFY_READ, arg1, 6 * sizeof(abi_ulong), 1)))
- goto efault;
+ return -TARGET_EFAULT;
v1 = tswapal(v[0]);
v2 = tswapal(v[1]);
v3 = tswapal(v[2]);
@@ -9706,22 +9582,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg5,
arg6));
#endif
- break;
+ return ret;
#endif
#ifdef TARGET_NR_mmap2
case TARGET_NR_mmap2:
#ifndef MMAP_SHIFT
#define MMAP_SHIFT 12
#endif
- ret = get_errno(target_mmap(arg1, arg2, arg3,
- target_to_host_bitmask(arg4, mmap_flags_tbl),
- arg5,
- arg6 << MMAP_SHIFT));
- break;
+ ret = target_mmap(arg1, arg2, arg3,
+ target_to_host_bitmask(arg4, mmap_flags_tbl),
+ arg5, arg6 << MMAP_SHIFT);
+ return get_errno(ret);
#endif
case TARGET_NR_munmap:
- ret = get_errno(target_munmap(arg1, arg2));
- break;
+ return get_errno(target_munmap(arg1, arg2));
case TARGET_NR_mprotect:
{
TaskState *ts = cpu->opaque;
@@ -9734,62 +9608,53 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg1 = ts->info->stack_limit;
}
}
- ret = get_errno(target_mprotect(arg1, arg2, arg3));
- break;
+ return get_errno(target_mprotect(arg1, arg2, arg3));
#ifdef TARGET_NR_mremap
case TARGET_NR_mremap:
- ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
- break;
+ return get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
#endif
/* ??? msync/mlock/munlock are broken for softmmu. */
#ifdef TARGET_NR_msync
case TARGET_NR_msync:
- ret = get_errno(msync(g2h(arg1), arg2, arg3));
- break;
+ return get_errno(msync(g2h(arg1), arg2, arg3));
#endif
#ifdef TARGET_NR_mlock
case TARGET_NR_mlock:
- ret = get_errno(mlock(g2h(arg1), arg2));
- break;
+ return get_errno(mlock(g2h(arg1), arg2));
#endif
#ifdef TARGET_NR_munlock
case TARGET_NR_munlock:
- ret = get_errno(munlock(g2h(arg1), arg2));
- break;
+ return get_errno(munlock(g2h(arg1), arg2));
#endif
#ifdef TARGET_NR_mlockall
case TARGET_NR_mlockall:
- ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
- break;
+ return get_errno(mlockall(target_to_host_mlockall_arg(arg1)));
#endif
#ifdef TARGET_NR_munlockall
case TARGET_NR_munlockall:
- ret = get_errno(munlockall());
- break;
+ return get_errno(munlockall());
#endif
#ifdef TARGET_NR_truncate
case TARGET_NR_truncate:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(truncate(p, arg2));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_ftruncate
case TARGET_NR_ftruncate:
- ret = get_errno(ftruncate(arg1, arg2));
- break;
+ return get_errno(ftruncate(arg1, arg2));
#endif
case TARGET_NR_fchmod:
- ret = get_errno(fchmod(arg1, arg2));
- break;
+ return get_errno(fchmod(arg1, arg2));
#if defined(TARGET_NR_fchmodat)
case TARGET_NR_fchmodat:
if (!(p = lock_user_string(arg2)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(fchmodat(arg1, p, arg3, 0));
unlock_user(p, arg2, 0);
- break;
+ return ret;
#endif
case TARGET_NR_getpriority:
/* Note that negative values are valid for getpriority, so we must
@@ -9797,8 +9662,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
errno = 0;
ret = getpriority(arg1, arg2);
if (ret == -1 && errno != 0) {
- ret = -host_to_target_errno(errno);
- break;
+ return -host_to_target_errno(errno);
}
#ifdef TARGET_ALPHA
/* Return value is the unbiased priority. Signal no error. */
@@ -9807,18 +9671,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
/* Return value is a biased priority to avoid negative numbers. */
ret = 20 - ret;
#endif
- break;
+ return ret;
case TARGET_NR_setpriority:
- ret = get_errno(setpriority(arg1, arg2, arg3));
- break;
-#ifdef TARGET_NR_profil
- case TARGET_NR_profil:
- goto unimplemented;
-#endif
+ return get_errno(setpriority(arg1, arg2, arg3));
#ifdef TARGET_NR_statfs
case TARGET_NR_statfs:
- if (!(p = lock_user_string(arg1)))
- goto efault;
+ if (!(p = lock_user_string(arg1))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(statfs(path(p), &stfs));
unlock_user(p, arg1, 0);
convert_statfs:
@@ -9826,7 +9686,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_statfs *target_stfs;
if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg2, 0))
- goto efault;
+ return -TARGET_EFAULT;
__put_user(stfs.f_type, &target_stfs->f_type);
__put_user(stfs.f_bsize, &target_stfs->f_bsize);
__put_user(stfs.f_blocks, &target_stfs->f_blocks);
@@ -9846,7 +9706,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
unlock_user_struct(target_stfs, arg2, 1);
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_fstatfs
case TARGET_NR_fstatfs:
@@ -9855,8 +9715,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_statfs64
case TARGET_NR_statfs64:
- if (!(p = lock_user_string(arg1)))
- goto efault;
+ if (!(p = lock_user_string(arg1))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(statfs(path(p), &stfs));
unlock_user(p, arg1, 0);
convert_statfs64:
@@ -9864,7 +9725,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_statfs64 *target_stfs;
if (!lock_user_struct(VERIFY_WRITE, target_stfs, arg3, 0))
- goto efault;
+ return -TARGET_EFAULT;
__put_user(stfs.f_type, &target_stfs->f_type);
__put_user(stfs.f_bsize, &target_stfs->f_bsize);
__put_user(stfs.f_blocks, &target_stfs->f_blocks);
@@ -9879,127 +9740,102 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare));
unlock_user_struct(target_stfs, arg3, 1);
}
- break;
+ return ret;
case TARGET_NR_fstatfs64:
ret = get_errno(fstatfs(arg1, &stfs));
goto convert_statfs64;
#endif
-#ifdef TARGET_NR_ioperm
- case TARGET_NR_ioperm:
- goto unimplemented;
-#endif
#ifdef TARGET_NR_socketcall
case TARGET_NR_socketcall:
- ret = do_socketcall(arg1, arg2);
- break;
+ return do_socketcall(arg1, arg2);
#endif
#ifdef TARGET_NR_accept
case TARGET_NR_accept:
- ret = do_accept4(arg1, arg2, arg3, 0);
- break;
+ return do_accept4(arg1, arg2, arg3, 0);
#endif
#ifdef TARGET_NR_accept4
case TARGET_NR_accept4:
- ret = do_accept4(arg1, arg2, arg3, arg4);
- break;
+ return do_accept4(arg1, arg2, arg3, arg4);
#endif
#ifdef TARGET_NR_bind
case TARGET_NR_bind:
- ret = do_bind(arg1, arg2, arg3);
- break;
+ return do_bind(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_connect
case TARGET_NR_connect:
- ret = do_connect(arg1, arg2, arg3);
- break;
+ return do_connect(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_getpeername
case TARGET_NR_getpeername:
- ret = do_getpeername(arg1, arg2, arg3);
- break;
+ return do_getpeername(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_getsockname
case TARGET_NR_getsockname:
- ret = do_getsockname(arg1, arg2, arg3);
- break;
+ return do_getsockname(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_getsockopt
case TARGET_NR_getsockopt:
- ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
- break;
+ return do_getsockopt(arg1, arg2, arg3, arg4, arg5);
#endif
#ifdef TARGET_NR_listen
case TARGET_NR_listen:
- ret = get_errno(listen(arg1, arg2));
- break;
+ return get_errno(listen(arg1, arg2));
#endif
#ifdef TARGET_NR_recv
case TARGET_NR_recv:
- ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
- break;
+ return do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
#endif
#ifdef TARGET_NR_recvfrom
case TARGET_NR_recvfrom:
- ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
- break;
+ return do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
#endif
#ifdef TARGET_NR_recvmsg
case TARGET_NR_recvmsg:
- ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
- break;
+ return do_sendrecvmsg(arg1, arg2, arg3, 0);
#endif
#ifdef TARGET_NR_send
case TARGET_NR_send:
- ret = do_sendto(arg1, arg2, arg3, arg4, 0, 0);
- break;
+ return do_sendto(arg1, arg2, arg3, arg4, 0, 0);
#endif
#ifdef TARGET_NR_sendmsg
case TARGET_NR_sendmsg:
- ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
- break;
+ return do_sendrecvmsg(arg1, arg2, arg3, 1);
#endif
#ifdef TARGET_NR_sendmmsg
case TARGET_NR_sendmmsg:
- ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
- break;
+ return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1);
case TARGET_NR_recvmmsg:
- ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
- break;
+ return do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0);
#endif
#ifdef TARGET_NR_sendto
case TARGET_NR_sendto:
- ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
- break;
+ return do_sendto(arg1, arg2, arg3, arg4, arg5, arg6);
#endif
#ifdef TARGET_NR_shutdown
case TARGET_NR_shutdown:
- ret = get_errno(shutdown(arg1, arg2));
- break;
+ return get_errno(shutdown(arg1, arg2));
#endif
#if defined(TARGET_NR_getrandom) && defined(__NR_getrandom)
case TARGET_NR_getrandom:
p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
if (!p) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(getrandom(p, arg2, arg3));
unlock_user(p, arg1, ret);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_socket
case TARGET_NR_socket:
- ret = do_socket(arg1, arg2, arg3);
- break;
+ return do_socket(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_socketpair
case TARGET_NR_socketpair:
- ret = do_socketpair(arg1, arg2, arg3, arg4);
- break;
+ return do_socketpair(arg1, arg2, arg3, arg4);
#endif
#ifdef TARGET_NR_setsockopt
case TARGET_NR_setsockopt:
- ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
- break;
+ return do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
#endif
#if defined(TARGET_NR_syslog)
case TARGET_NR_syslog:
@@ -10015,34 +9851,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */
case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */
case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */
- {
- ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
- }
- break;
+ return get_errno(sys_syslog((int)arg1, NULL, (int)arg3));
case TARGET_SYSLOG_ACTION_READ: /* Read from log */
case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */
case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */
{
- ret = -TARGET_EINVAL;
if (len < 0) {
- goto fail;
+ return -TARGET_EINVAL;
}
- ret = 0;
if (len == 0) {
- break;
+ return 0;
}
p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
if (!p) {
- ret = -TARGET_EFAULT;
- goto fail;
+ return -TARGET_EFAULT;
}
ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
unlock_user(p, arg2, arg3);
}
- break;
+ return ret;
default:
- ret = -EINVAL;
- break;
+ return -TARGET_EINVAL;
}
}
break;
@@ -10056,7 +9885,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (copy_from_user_timeval(&pvalue->it_interval, arg2)
|| copy_from_user_timeval(&pvalue->it_value,
arg2 + sizeof(struct target_timeval)))
- goto efault;
+ return -TARGET_EFAULT;
} else {
pvalue = NULL;
}
@@ -10066,10 +9895,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
&ovalue.it_interval)
|| copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
&ovalue.it_value))
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
case TARGET_NR_getitimer:
{
struct itimerval value;
@@ -10080,22 +9909,24 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
&value.it_interval)
|| copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
&value.it_value))
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#ifdef TARGET_NR_stat
case TARGET_NR_stat:
- if (!(p = lock_user_string(arg1)))
- goto efault;
+ if (!(p = lock_user_string(arg1))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(stat(path(p), &st));
unlock_user(p, arg1, 0);
goto do_stat;
#endif
#ifdef TARGET_NR_lstat
case TARGET_NR_lstat:
- if (!(p = lock_user_string(arg1)))
- goto efault;
+ if (!(p = lock_user_string(arg1))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(lstat(path(p), &st));
unlock_user(p, arg1, 0);
goto do_stat;
@@ -10111,7 +9942,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct target_stat *target_st;
if (!lock_user_struct(VERIFY_WRITE, target_st, arg2, 0))
- goto efault;
+ return -TARGET_EFAULT;
memset(target_st, 0, sizeof(*target_st));
__put_user(st.st_dev, &target_st->st_dev);
__put_user(st.st_ino, &target_st->st_ino);
@@ -10129,28 +9960,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user_struct(target_st, arg2, 1);
}
}
- break;
-#endif
-#ifdef TARGET_NR_olduname
- case TARGET_NR_olduname:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_iopl
- case TARGET_NR_iopl:
- goto unimplemented;
+ return ret;
#endif
case TARGET_NR_vhangup:
- ret = get_errno(vhangup());
- break;
-#ifdef TARGET_NR_idle
- case TARGET_NR_idle:
- goto unimplemented;
-#endif
+ return get_errno(vhangup());
#ifdef TARGET_NR_syscall
case TARGET_NR_syscall:
- ret = do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
- arg6, arg7, arg8, 0);
- break;
+ return do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, 0);
#endif
case TARGET_NR_wait4:
{
@@ -10168,7 +9985,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (status_ptr && ret) {
status = host_to_target_waitstatus(status);
if (put_user_s32(status, status_ptr))
- goto efault;
+ return -TARGET_EFAULT;
}
if (target_rusage) {
rusage_err = host_to_target_rusage(target_rusage, &rusage);
@@ -10178,14 +9995,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
}
}
- break;
+ return ret;
#ifdef TARGET_NR_swapoff
case TARGET_NR_swapoff:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(swapoff(p));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
case TARGET_NR_sysinfo:
{
@@ -10195,7 +10012,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret) && arg1)
{
if (!lock_user_struct(VERIFY_WRITE, target_value, arg1, 0))
- goto efault;
+ return -TARGET_EFAULT;
__put_user(value.uptime, &target_value->uptime);
__put_user(value.loads[0], &target_value->loads[0]);
__put_user(value.loads[1], &target_value->loads[1]);
@@ -10213,70 +10030,57 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user_struct(target_value, arg1, 1);
}
}
- break;
+ return ret;
#ifdef TARGET_NR_ipc
case TARGET_NR_ipc:
- ret = do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
+ return do_ipc(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
#endif
#ifdef TARGET_NR_semget
case TARGET_NR_semget:
- ret = get_errno(semget(arg1, arg2, arg3));
- break;
+ return get_errno(semget(arg1, arg2, arg3));
#endif
#ifdef TARGET_NR_semop
case TARGET_NR_semop:
- ret = do_semop(arg1, arg2, arg3);
- break;
+ return do_semop(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_semctl
case TARGET_NR_semctl:
- ret = do_semctl(arg1, arg2, arg3, arg4);
- break;
+ return do_semctl(arg1, arg2, arg3, arg4);
#endif
#ifdef TARGET_NR_msgctl
case TARGET_NR_msgctl:
- ret = do_msgctl(arg1, arg2, arg3);
- break;
+ return do_msgctl(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_msgget
case TARGET_NR_msgget:
- ret = get_errno(msgget(arg1, arg2));
- break;
+ return get_errno(msgget(arg1, arg2));
#endif
#ifdef TARGET_NR_msgrcv
case TARGET_NR_msgrcv:
- ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
- break;
+ return do_msgrcv(arg1, arg2, arg3, arg4, arg5);
#endif
#ifdef TARGET_NR_msgsnd
case TARGET_NR_msgsnd:
- ret = do_msgsnd(arg1, arg2, arg3, arg4);
- break;
+ return do_msgsnd(arg1, arg2, arg3, arg4);
#endif
#ifdef TARGET_NR_shmget
case TARGET_NR_shmget:
- ret = get_errno(shmget(arg1, arg2, arg3));
- break;
+ return get_errno(shmget(arg1, arg2, arg3));
#endif
#ifdef TARGET_NR_shmctl
case TARGET_NR_shmctl:
- ret = do_shmctl(arg1, arg2, arg3);
- break;
+ return do_shmctl(arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_shmat
case TARGET_NR_shmat:
- ret = do_shmat(cpu_env, arg1, arg2, arg3);
- break;
+ return do_shmat(cpu_env, arg1, arg2, arg3);
#endif
#ifdef TARGET_NR_shmdt
case TARGET_NR_shmdt:
- ret = do_shmdt(arg1);
- break;
+ return do_shmdt(arg1);
#endif
case TARGET_NR_fsync:
- ret = get_errno(fsync(arg1));
- break;
+ return get_errno(fsync(arg1));
case TARGET_NR_clone:
/* Linux manages to have three different orderings for its
* arguments to clone(); the BACKWARDS and BACKWARDS2 defines
@@ -10293,27 +10097,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#else
ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
#endif
- break;
+ return ret;
#ifdef __NR_exit_group
/* new thread calls */
case TARGET_NR_exit_group:
preexit_cleanup(cpu_env, arg1);
- ret = get_errno(exit_group(arg1));
- break;
+ return get_errno(exit_group(arg1));
#endif
case TARGET_NR_setdomainname:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(setdomainname(p, arg2));
unlock_user(p, arg1, 0);
- break;
+ return ret;
case TARGET_NR_uname:
/* no need to transcode because we use the linux syscall */
{
struct new_utsname * buf;
if (!lock_user_struct(VERIFY_WRITE, buf, arg1, 0))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(sys_uname(buf));
if (!is_error(ret)) {
/* Overwrite the native machine name with whatever is being
@@ -10328,17 +10131,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
unlock_user_struct(buf, arg1, 1);
}
- break;
+ return ret;
#ifdef TARGET_I386
case TARGET_NR_modify_ldt:
- ret = do_modify_ldt(cpu_env, arg1, arg2, arg3);
- break;
+ return do_modify_ldt(cpu_env, arg1, arg2, arg3);
#if !defined(TARGET_X86_64)
- case TARGET_NR_vm86old:
- goto unimplemented;
case TARGET_NR_vm86:
- ret = do_vm86(cpu_env, arg1, arg2);
- break;
+ return do_vm86(cpu_env, arg1, arg2);
#endif
#endif
case TARGET_NR_adjtimex:
@@ -10346,65 +10145,39 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct timex host_buf;
if (target_to_host_timex(&host_buf, arg1) != 0) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(adjtimex(&host_buf));
if (!is_error(ret)) {
if (host_to_target_timex(arg1, &host_buf) != 0) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
}
- break;
+ return ret;
#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME)
case TARGET_NR_clock_adjtime:
{
struct timex htx, *phtx = &htx;
if (target_to_host_timex(phtx, arg2) != 0) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(clock_adjtime(arg1, phtx));
if (!is_error(ret) && phtx) {
if (host_to_target_timex(arg2, phtx) != 0) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
}
- break;
-#endif
-#ifdef TARGET_NR_create_module
- case TARGET_NR_create_module:
-#endif
- case TARGET_NR_init_module:
- case TARGET_NR_delete_module:
-#ifdef TARGET_NR_get_kernel_syms
- case TARGET_NR_get_kernel_syms:
+ return ret;
#endif
- goto unimplemented;
- case TARGET_NR_quotactl:
- goto unimplemented;
case TARGET_NR_getpgid:
- ret = get_errno(getpgid(arg1));
- break;
+ return get_errno(getpgid(arg1));
case TARGET_NR_fchdir:
- ret = get_errno(fchdir(arg1));
- break;
-#ifdef TARGET_NR_bdflush /* not on x86_64 */
- case TARGET_NR_bdflush:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_sysfs
- case TARGET_NR_sysfs:
- goto unimplemented;
-#endif
+ return get_errno(fchdir(arg1));
case TARGET_NR_personality:
- ret = get_errno(personality(arg1));
- break;
-#ifdef TARGET_NR_afs_syscall
- case TARGET_NR_afs_syscall:
- goto unimplemented;
-#endif
+ return get_errno(personality(arg1));
#ifdef TARGET_NR__llseek /* Not on alpha */
case TARGET_NR__llseek:
{
@@ -10420,10 +10193,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
#endif
if ((ret == 0) && put_user_s64(res, arg4)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_getdents
case TARGET_NR_getdents:
@@ -10436,8 +10209,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
dirp = g_try_malloc(count);
if (!dirp) {
- ret = -TARGET_ENOMEM;
- goto fail;
+ return -TARGET_ENOMEM;
}
ret = get_errno(sys_getdents(arg1, dirp, count));
@@ -10451,7 +10223,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
count1 = 0;
de = dirp;
if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
- goto efault;
+ return -TARGET_EFAULT;
tde = target_dirp;
while (len > 0) {
reclen = de->d_reclen;
@@ -10479,7 +10251,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
abi_long count = arg3;
if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(sys_getdents(arg1, dirp, count));
if (!is_error(ret)) {
struct linux_dirent *de;
@@ -10508,7 +10280,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
if (!dirp) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(sys_getdents64(arg1, dirp, count));
if (!is_error(ret)) {
@@ -10555,7 +10327,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(dirp, arg2, ret);
}
#endif
- break;
+ return ret;
#endif /* TARGET_NR_getdents */
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
case TARGET_NR_getdents64:
@@ -10563,7 +10335,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct linux_dirent64 *dirp;
abi_long count = arg3;
if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(sys_getdents64(arg1, dirp, count));
if (!is_error(ret)) {
struct linux_dirent64 *de;
@@ -10583,12 +10355,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
unlock_user(dirp, arg2, ret);
}
- break;
+ return ret;
#endif /* TARGET_NR_getdents64 */
#if defined(TARGET_NR__newselect)
case TARGET_NR__newselect:
- ret = do_select(arg1, arg2, arg3, arg4, arg5);
- break;
+ return do_select(arg1, arg2, arg3, arg4, arg5);
#endif
#if defined(TARGET_NR_poll) || defined(TARGET_NR_ppoll)
# ifdef TARGET_NR_poll
@@ -10607,14 +10378,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
target_pfd = NULL;
if (nfds) {
if (nfds > (INT_MAX / sizeof(struct target_pollfd))) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
target_pfd = lock_user(VERIFY_WRITE, arg1,
sizeof(struct target_pollfd) * nfds, 1);
if (!target_pfd) {
- goto efault;
+ return -TARGET_EFAULT;
}
pfd = alloca(sizeof(struct pollfd) * nfds);
@@ -10635,7 +10405,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg3) {
if (target_to_host_timespec(timeout_ts, arg3)) {
unlock_user(target_pfd, arg1, 0);
- goto efault;
+ return -TARGET_EFAULT;
}
} else {
timeout_ts = NULL;
@@ -10644,14 +10414,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg4) {
if (arg5 != sizeof(target_sigset_t)) {
unlock_user(target_pfd, arg1, 0);
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
target_set = lock_user(VERIFY_READ, arg4, sizeof(target_sigset_t), 1);
if (!target_set) {
unlock_user(target_pfd, arg1, 0);
- goto efault;
+ return -TARGET_EFAULT;
}
target_to_host_sigset(set, target_set);
} else {
@@ -10699,13 +10468,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
}
- break;
+ return ret;
#endif
case TARGET_NR_flock:
/* NOTE: the flock constant seems to be the same for every
Linux platform */
- ret = get_errno(safe_flock(arg1, arg2));
- break;
+ return get_errno(safe_flock(arg1, arg2));
case TARGET_NR_readv:
{
struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
@@ -10716,7 +10484,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = -host_to_target_errno(errno);
}
}
- break;
+ return ret;
case TARGET_NR_writev:
{
struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
@@ -10727,7 +10495,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = -host_to_target_errno(errno);
}
}
- break;
+ return ret;
#if defined(TARGET_NR_preadv)
case TARGET_NR_preadv:
{
@@ -10742,7 +10510,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = -host_to_target_errno(errno);
}
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_pwritev)
case TARGET_NR_pwritev:
@@ -10758,22 +10526,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = -host_to_target_errno(errno);
}
}
- break;
+ return ret;
#endif
case TARGET_NR_getsid:
- ret = get_errno(getsid(arg1));
- break;
+ return get_errno(getsid(arg1));
#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
case TARGET_NR_fdatasync:
- ret = get_errno(fdatasync(arg1));
- break;
+ return get_errno(fdatasync(arg1));
#endif
#ifdef TARGET_NR__sysctl
case TARGET_NR__sysctl:
/* We don't implement this, but ENOTDIR is always a safe
return value. */
- ret = -TARGET_ENOTDIR;
- break;
+ return -TARGET_ENOTDIR;
#endif
case TARGET_NR_sched_getaffinity:
{
@@ -10785,8 +10550,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
* care of mismatches between target ulong and host ulong sizes.
*/
if (arg2 & (sizeof(abi_ulong) - 1)) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
@@ -10805,18 +10569,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
*/
int numcpus = sysconf(_SC_NPROCESSORS_CONF);
if (numcpus > arg2 * 8) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
ret = arg2;
}
if (host_to_target_cpu_mask(mask, mask_size, arg3, ret)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
}
- break;
+ return ret;
case TARGET_NR_sched_setaffinity:
{
unsigned int mask_size;
@@ -10827,20 +10590,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
* care of mismatches between target ulong and host ulong sizes.
*/
if (arg2 & (sizeof(abi_ulong) - 1)) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
mask_size = (arg2 + (sizeof(*mask) - 1)) & ~(sizeof(*mask) - 1);
mask = alloca(mask_size);
ret = target_to_host_cpu_mask(mask, mask_size, arg3, arg2);
if (ret) {
- break;
+ return ret;
}
- ret = get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
+ return get_errno(sys_sched_setaffinity(arg1, mask_size, mask));
}
- break;
case TARGET_NR_getcpu:
{
unsigned cpu, node;
@@ -10848,16 +10609,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg2 ? &node : NULL,
NULL));
if (is_error(ret)) {
- goto fail;
+ return ret;
}
if (arg1 && put_user_u32(cpu, arg1)) {
- goto efault;
+ return -TARGET_EFAULT;
}
if (arg2 && put_user_u32(node, arg2)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
case TARGET_NR_sched_setparam:
{
struct sched_param *target_schp;
@@ -10867,12 +10628,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
return -TARGET_EINVAL;
}
if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1))
- goto efault;
+ return -TARGET_EFAULT;
schp.sched_priority = tswap32(target_schp->sched_priority);
unlock_user_struct(target_schp, arg2, 0);
- ret = get_errno(sched_setparam(arg1, &schp));
+ return get_errno(sched_setparam(arg1, &schp));
}
- break;
case TARGET_NR_sched_getparam:
{
struct sched_param *target_schp;
@@ -10884,12 +10644,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(sched_getparam(arg1, &schp));
if (!is_error(ret)) {
if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0))
- goto efault;
+ return -TARGET_EFAULT;
target_schp->sched_priority = tswap32(schp.sched_priority);
unlock_user_struct(target_schp, arg2, 1);
}
}
- break;
+ return ret;
case TARGET_NR_sched_setscheduler:
{
struct sched_param *target_schp;
@@ -10898,24 +10658,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
return -TARGET_EINVAL;
}
if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1))
- goto efault;
+ return -TARGET_EFAULT;
schp.sched_priority = tswap32(target_schp->sched_priority);
unlock_user_struct(target_schp, arg3, 0);
- ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
+ return get_errno(sched_setscheduler(arg1, arg2, &schp));
}
- break;
case TARGET_NR_sched_getscheduler:
- ret = get_errno(sched_getscheduler(arg1));
- break;
+ return get_errno(sched_getscheduler(arg1));
case TARGET_NR_sched_yield:
- ret = get_errno(sched_yield());
- break;
+ return get_errno(sched_yield());
case TARGET_NR_sched_get_priority_max:
- ret = get_errno(sched_get_priority_max(arg1));
- break;
+ return get_errno(sched_get_priority_max(arg1));
case TARGET_NR_sched_get_priority_min:
- ret = get_errno(sched_get_priority_min(arg1));
- break;
+ return get_errno(sched_get_priority_min(arg1));
case TARGET_NR_sched_rr_get_interval:
{
struct timespec ts;
@@ -10924,7 +10679,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = host_to_target_timespec(arg2, &ts);
}
}
- break;
+ return ret;
case TARGET_NR_nanosleep:
{
struct timespec req, rem;
@@ -10934,15 +10689,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
host_to_target_timespec(arg2, &rem);
}
}
- break;
-#ifdef TARGET_NR_query_module
- case TARGET_NR_query_module:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_nfsservctl
- case TARGET_NR_nfsservctl:
- goto unimplemented;
-#endif
+ return ret;
case TARGET_NR_prctl:
switch (arg1) {
case PR_GET_PDEATHSIG:
@@ -10951,32 +10698,32 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
if (!is_error(ret) && arg2
&& put_user_ual(deathsig, arg2)) {
- goto efault;
+ return -TARGET_EFAULT;
}
- break;
+ return ret;
}
#ifdef PR_GET_NAME
case PR_GET_NAME:
{
void *name = lock_user(VERIFY_WRITE, arg2, 16, 1);
if (!name) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(prctl(arg1, (unsigned long)name,
arg3, arg4, arg5));
unlock_user(name, arg2, 16);
- break;
+ return ret;
}
case PR_SET_NAME:
{
void *name = lock_user(VERIFY_READ, arg2, 16, 1);
if (!name) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(prctl(arg1, (unsigned long)name,
arg3, arg4, arg5));
unlock_user(name, arg2, 0);
- break;
+ return ret;
}
#endif
#ifdef TARGET_AARCH64
@@ -11004,34 +10751,31 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
env->vfp.zcr_el[1] = vq - 1;
ret = vq * 16;
}
- break;
+ return ret;
case TARGET_PR_SVE_GET_VL:
ret = -TARGET_EINVAL;
if (arm_feature(cpu_env, ARM_FEATURE_SVE)) {
CPUARMState *env = cpu_env;
ret = ((env->vfp.zcr_el[1] & 0xf) + 1) * 16;
}
- break;
+ return ret;
#endif /* AARCH64 */
case PR_GET_SECCOMP:
case PR_SET_SECCOMP:
/* Disable seccomp to prevent the target disabling syscalls we
* need. */
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
default:
/* Most prctl options have no pointer arguments */
- ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
- break;
+ return get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
}
break;
#ifdef TARGET_NR_arch_prctl
case TARGET_NR_arch_prctl:
#if defined(TARGET_I386) && !defined(TARGET_ABI32)
- ret = do_arch_prctl(cpu_env, arg1, arg2);
- break;
+ return do_arch_prctl(cpu_env, arg1, arg2);
#else
- goto unimplemented;
+#error unreachable
#endif
#endif
#ifdef TARGET_NR_pread64
@@ -11041,27 +10785,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg5 = arg6;
}
if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
unlock_user(p, arg2, ret);
- break;
+ return ret;
case TARGET_NR_pwrite64:
if (regpairs_aligned(cpu_env, num)) {
arg4 = arg5;
arg5 = arg6;
}
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
unlock_user(p, arg2, 0);
- break;
+ return ret;
#endif
case TARGET_NR_getcwd:
if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(sys_getcwd1(p, arg2));
unlock_user(p, arg1, ret);
- break;
+ return ret;
case TARGET_NR_capget:
case TARGET_NR_capset:
{
@@ -11074,7 +10818,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
int data_items = 1;
if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
- goto efault;
+ return -TARGET_EFAULT;
}
header.version = tswap32(target_header->version);
header.pid = tswap32(target_header->pid);
@@ -11094,7 +10838,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
if (!target_data) {
unlock_user_struct(target_header, arg1, 0);
- goto efault;
+ return -TARGET_EFAULT;
}
if (num == TARGET_NR_capset) {
@@ -11130,11 +10874,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(target_data, arg2, 0);
}
}
- break;
+ return ret;
}
case TARGET_NR_sigaltstack:
- ret = do_sigaltstack(arg1, arg2, get_sp_from_cpustate((CPUArchState *)cpu_env));
- break;
+ return do_sigaltstack(arg1, arg2,
+ get_sp_from_cpustate((CPUArchState *)cpu_env));
#ifdef CONFIG_SENDFILE
#ifdef TARGET_NR_sendfile
@@ -11145,7 +10889,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg3) {
ret = get_user_sal(off, arg3);
if (is_error(ret)) {
- break;
+ return ret;
}
offp = &off;
}
@@ -11156,7 +10900,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = ret2;
}
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_sendfile64
@@ -11167,7 +10911,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg3) {
ret = get_user_s64(off, arg3);
if (is_error(ret)) {
- break;
+ return ret;
}
offp = &off;
}
@@ -11178,31 +10922,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = ret2;
}
}
- break;
+ return ret;
}
#endif
-#else
- case TARGET_NR_sendfile:
-#ifdef TARGET_NR_sendfile64
- case TARGET_NR_sendfile64:
-#endif
- goto unimplemented;
-#endif
-
-#ifdef TARGET_NR_getpmsg
- case TARGET_NR_getpmsg:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_putpmsg
- case TARGET_NR_putpmsg:
- goto unimplemented;
#endif
#ifdef TARGET_NR_vfork
case TARGET_NR_vfork:
- ret = get_errno(do_fork(cpu_env,
- CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
- 0, 0, 0, 0));
- break;
+ return get_errno(do_fork(cpu_env,
+ CLONE_VFORK | CLONE_VM | TARGET_SIGCHLD,
+ 0, 0, 0, 0));
#endif
#ifdef TARGET_NR_ugetrlimit
case TARGET_NR_ugetrlimit:
@@ -11213,53 +10941,54 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret)) {
struct target_rlimit *target_rlim;
if (!lock_user_struct(VERIFY_WRITE, target_rlim, arg2, 0))
- goto efault;
+ return -TARGET_EFAULT;
target_rlim->rlim_cur = host_to_target_rlim(rlim.rlim_cur);
target_rlim->rlim_max = host_to_target_rlim(rlim.rlim_max);
unlock_user_struct(target_rlim, arg2, 1);
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_truncate64
case TARGET_NR_truncate64:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_ftruncate64
case TARGET_NR_ftruncate64:
- ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
- break;
+ return target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
#endif
#ifdef TARGET_NR_stat64
case TARGET_NR_stat64:
- if (!(p = lock_user_string(arg1)))
- goto efault;
+ if (!(p = lock_user_string(arg1))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(stat(path(p), &st));
unlock_user(p, arg1, 0);
if (!is_error(ret))
ret = host_to_target_stat64(cpu_env, arg2, &st);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_lstat64
case TARGET_NR_lstat64:
- if (!(p = lock_user_string(arg1)))
- goto efault;
+ if (!(p = lock_user_string(arg1))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(lstat(path(p), &st));
unlock_user(p, arg1, 0);
if (!is_error(ret))
ret = host_to_target_stat64(cpu_env, arg2, &st);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_fstat64
case TARGET_NR_fstat64:
ret = get_errno(fstat(arg1, &st));
if (!is_error(ret))
ret = host_to_target_stat64(cpu_env, arg2, &st);
- break;
+ return ret;
#endif
#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat))
#ifdef TARGET_NR_fstatat64
@@ -11268,47 +10997,43 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_newfstatat
case TARGET_NR_newfstatat:
#endif
- if (!(p = lock_user_string(arg2)))
- goto efault;
+ if (!(p = lock_user_string(arg2))) {
+ return -TARGET_EFAULT;
+ }
ret = get_errno(fstatat(arg1, path(p), &st, arg4));
+ unlock_user(p, arg2, 0);
if (!is_error(ret))
ret = host_to_target_stat64(cpu_env, arg3, &st);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_lchown
case TARGET_NR_lchown:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_getuid
case TARGET_NR_getuid:
- ret = get_errno(high2lowuid(getuid()));
- break;
+ return get_errno(high2lowuid(getuid()));
#endif
#ifdef TARGET_NR_getgid
case TARGET_NR_getgid:
- ret = get_errno(high2lowgid(getgid()));
- break;
+ return get_errno(high2lowgid(getgid()));
#endif
#ifdef TARGET_NR_geteuid
case TARGET_NR_geteuid:
- ret = get_errno(high2lowuid(geteuid()));
- break;
+ return get_errno(high2lowuid(geteuid()));
#endif
#ifdef TARGET_NR_getegid
case TARGET_NR_getegid:
- ret = get_errno(high2lowgid(getegid()));
- break;
+ return get_errno(high2lowgid(getegid()));
#endif
case TARGET_NR_setreuid:
- ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
- break;
+ return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
case TARGET_NR_setregid:
- ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
- break;
+ return get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
case TARGET_NR_getgroups:
{
int gidsetsize = arg1;
@@ -11319,17 +11044,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
grouplist = alloca(gidsetsize * sizeof(gid_t));
ret = get_errno(getgroups(gidsetsize, grouplist));
if (gidsetsize == 0)
- break;
+ return ret;
if (!is_error(ret)) {
target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
if (!target_grouplist)
- goto efault;
+ return -TARGET_EFAULT;
for(i = 0;i < ret; i++)
target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
}
}
- break;
+ return ret;
case TARGET_NR_setgroups:
{
int gidsetsize = arg1;
@@ -11340,35 +11065,31 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
grouplist = alloca(gidsetsize * sizeof(gid_t));
target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
if (!target_grouplist) {
- ret = -TARGET_EFAULT;
- goto fail;
+ return -TARGET_EFAULT;
}
for (i = 0; i < gidsetsize; i++) {
grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
}
unlock_user(target_grouplist, arg2, 0);
}
- ret = get_errno(setgroups(gidsetsize, grouplist));
+ return get_errno(setgroups(gidsetsize, grouplist));
}
- break;
case TARGET_NR_fchown:
- ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
- break;
+ return get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
#if defined(TARGET_NR_fchownat)
case TARGET_NR_fchownat:
if (!(p = lock_user_string(arg2)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(fchownat(arg1, p, low2highuid(arg3),
low2highgid(arg4), arg5));
unlock_user(p, arg2, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_setresuid
case TARGET_NR_setresuid:
- ret = get_errno(sys_setresuid(low2highuid(arg1),
- low2highuid(arg2),
- low2highuid(arg3)));
- break;
+ return get_errno(sys_setresuid(low2highuid(arg1),
+ low2highuid(arg2),
+ low2highuid(arg3)));
#endif
#ifdef TARGET_NR_getresuid
case TARGET_NR_getresuid:
@@ -11379,17 +11100,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (put_user_id(high2lowuid(ruid), arg1)
|| put_user_id(high2lowuid(euid), arg2)
|| put_user_id(high2lowuid(suid), arg3))
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_setresgid:
- ret = get_errno(sys_setresgid(low2highgid(arg1),
- low2highgid(arg2),
- low2highgid(arg3)));
- break;
+ return get_errno(sys_setresgid(low2highgid(arg1),
+ low2highgid(arg2),
+ low2highgid(arg3)));
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_getresgid:
@@ -11400,44 +11120,39 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (put_user_id(high2lowgid(rgid), arg1)
|| put_user_id(high2lowgid(egid), arg2)
|| put_user_id(high2lowgid(sgid), arg3))
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_chown
case TARGET_NR_chown:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
case TARGET_NR_setuid:
- ret = get_errno(sys_setuid(low2highuid(arg1)));
- break;
+ return get_errno(sys_setuid(low2highuid(arg1)));
case TARGET_NR_setgid:
- ret = get_errno(sys_setgid(low2highgid(arg1)));
- break;
+ return get_errno(sys_setgid(low2highgid(arg1)));
case TARGET_NR_setfsuid:
- ret = get_errno(setfsuid(arg1));
- break;
+ return get_errno(setfsuid(arg1));
case TARGET_NR_setfsgid:
- ret = get_errno(setfsgid(arg1));
- break;
+ return get_errno(setfsgid(arg1));
#ifdef TARGET_NR_lchown32
case TARGET_NR_lchown32:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(lchown(p, arg2, arg3));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_getuid32
case TARGET_NR_getuid32:
- ret = get_errno(getuid());
- break;
+ return get_errno(getuid());
#endif
#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
@@ -11448,8 +11163,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
euid=geteuid();
((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
}
- ret = get_errno(getuid());
- break;
+ return get_errno(getuid());
#endif
#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
/* Alpha specific */
@@ -11459,8 +11173,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
egid=getegid();
((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
}
- ret = get_errno(getgid());
- break;
+ return get_errno(getgid());
#endif
#if defined(TARGET_NR_osf_getsysinfo) && defined(TARGET_ALPHA)
/* Alpha specific */
@@ -11483,7 +11196,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
if (put_user_u64 (swcr, arg2))
- goto efault;
+ return -TARGET_EFAULT;
ret = 0;
}
break;
@@ -11498,7 +11211,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
-- Grabs a copy of the HWRPB; surely not used.
*/
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_osf_setsysinfo) && defined(TARGET_ALPHA)
/* Alpha specific */
@@ -11510,7 +11223,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
uint64_t swcr, fpcr, orig_fpcr;
if (get_user_u64 (swcr, arg2)) {
- goto efault;
+ return -TARGET_EFAULT;
}
orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
fpcr = orig_fpcr & FPCR_DYN_MASK;
@@ -11537,7 +11250,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
int si_code;
if (get_user_u64(exc, arg2)) {
- goto efault;
+ return -TARGET_EFAULT;
}
orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
@@ -11589,7 +11302,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
-- Not implemented in linux kernel
*/
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_osf_sigprocmask
/* Alpha specific. */
@@ -11610,8 +11323,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = SIG_SETMASK;
break;
default:
- ret = -TARGET_EINVAL;
- goto fail;
+ return -TARGET_EINVAL;
}
mask = arg2;
target_to_host_old_sigset(&set, &mask);
@@ -11621,33 +11333,28 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = mask;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_getgid32
case TARGET_NR_getgid32:
- ret = get_errno(getgid());
- break;
+ return get_errno(getgid());
#endif
#ifdef TARGET_NR_geteuid32
case TARGET_NR_geteuid32:
- ret = get_errno(geteuid());
- break;
+ return get_errno(geteuid());
#endif
#ifdef TARGET_NR_getegid32
case TARGET_NR_getegid32:
- ret = get_errno(getegid());
- break;
+ return get_errno(getegid());
#endif
#ifdef TARGET_NR_setreuid32
case TARGET_NR_setreuid32:
- ret = get_errno(setreuid(arg1, arg2));
- break;
+ return get_errno(setreuid(arg1, arg2));
#endif
#ifdef TARGET_NR_setregid32
case TARGET_NR_setregid32:
- ret = get_errno(setregid(arg1, arg2));
- break;
+ return get_errno(setregid(arg1, arg2));
#endif
#ifdef TARGET_NR_getgroups32
case TARGET_NR_getgroups32:
@@ -11660,19 +11367,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
grouplist = alloca(gidsetsize * sizeof(gid_t));
ret = get_errno(getgroups(gidsetsize, grouplist));
if (gidsetsize == 0)
- break;
+ return ret;
if (!is_error(ret)) {
target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
if (!target_grouplist) {
- ret = -TARGET_EFAULT;
- goto fail;
+ return -TARGET_EFAULT;
}
for(i = 0;i < ret; i++)
target_grouplist[i] = tswap32(grouplist[i]);
unlock_user(target_grouplist, arg2, gidsetsize * 4);
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_setgroups32
case TARGET_NR_setgroups32:
@@ -11685,25 +11391,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
grouplist = alloca(gidsetsize * sizeof(gid_t));
target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
if (!target_grouplist) {
- ret = -TARGET_EFAULT;
- goto fail;
+ return -TARGET_EFAULT;
}
for(i = 0;i < gidsetsize; i++)
grouplist[i] = tswap32(target_grouplist[i]);
unlock_user(target_grouplist, arg2, 0);
- ret = get_errno(setgroups(gidsetsize, grouplist));
+ return get_errno(setgroups(gidsetsize, grouplist));
}
- break;
#endif
#ifdef TARGET_NR_fchown32
case TARGET_NR_fchown32:
- ret = get_errno(fchown(arg1, arg2, arg3));
- break;
+ return get_errno(fchown(arg1, arg2, arg3));
#endif
#ifdef TARGET_NR_setresuid32
case TARGET_NR_setresuid32:
- ret = get_errno(sys_setresuid(arg1, arg2, arg3));
- break;
+ return get_errno(sys_setresuid(arg1, arg2, arg3));
#endif
#ifdef TARGET_NR_getresuid32
case TARGET_NR_getresuid32:
@@ -11714,15 +11416,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (put_user_u32(ruid, arg1)
|| put_user_u32(euid, arg2)
|| put_user_u32(suid, arg3))
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_setresgid32
case TARGET_NR_setresgid32:
- ret = get_errno(sys_setresgid(arg1, arg2, arg3));
- break;
+ return get_errno(sys_setresgid(arg1, arg2, arg3));
#endif
#ifdef TARGET_NR_getresgid32
case TARGET_NR_getresgid32:
@@ -11733,62 +11434,52 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (put_user_u32(rgid, arg1)
|| put_user_u32(egid, arg2)
|| put_user_u32(sgid, arg3))
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_chown32
case TARGET_NR_chown32:
if (!(p = lock_user_string(arg1)))
- goto efault;
+ return -TARGET_EFAULT;
ret = get_errno(chown(p, arg2, arg3));
unlock_user(p, arg1, 0);
- break;
+ return ret;
#endif
#ifdef TARGET_NR_setuid32
case TARGET_NR_setuid32:
- ret = get_errno(sys_setuid(arg1));
- break;
+ return get_errno(sys_setuid(arg1));
#endif
#ifdef TARGET_NR_setgid32
case TARGET_NR_setgid32:
- ret = get_errno(sys_setgid(arg1));
- break;
+ return get_errno(sys_setgid(arg1));
#endif
#ifdef TARGET_NR_setfsuid32
case TARGET_NR_setfsuid32:
- ret = get_errno(setfsuid(arg1));
- break;
+ return get_errno(setfsuid(arg1));
#endif
#ifdef TARGET_NR_setfsgid32
case TARGET_NR_setfsgid32:
- ret = get_errno(setfsgid(arg1));
- break;
+ return get_errno(setfsgid(arg1));
#endif
-
- case TARGET_NR_pivot_root:
- goto unimplemented;
#ifdef TARGET_NR_mincore
case TARGET_NR_mincore:
{
- void *a;
- ret = -TARGET_ENOMEM;
- a = lock_user(VERIFY_READ, arg1, arg2, 0);
+ void *a = lock_user(VERIFY_READ, arg1, arg2, 0);
if (!a) {
- goto fail;
+ return -TARGET_ENOMEM;
}
- ret = -TARGET_EFAULT;
p = lock_user_string(arg3);
if (!p) {
- goto mincore_fail;
+ ret = -TARGET_EFAULT;
+ } else {
+ ret = get_errno(mincore(a, arg2, p));
+ unlock_user(p, arg3, ret);
}
- ret = get_errno(mincore(a, arg2, p));
- unlock_user(p, arg3, ret);
- mincore_fail:
unlock_user(a, arg1, 0);
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_arm_fadvise64_64
case TARGET_NR_arm_fadvise64_64:
@@ -11800,8 +11491,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
*/
ret = posix_fadvise(arg1, target_offset64(arg3, arg4),
target_offset64(arg5, arg6), arg2);
- ret = -host_to_target_errno(ret);
- break;
+ return -host_to_target_errno(ret);
#endif
#if TARGET_ABI_BITS == 32
@@ -11827,11 +11517,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg6 = arg7;
}
#endif
- ret = -host_to_target_errno(posix_fadvise(arg1,
- target_offset64(arg2, arg3),
- target_offset64(arg4, arg5),
- arg6));
- break;
+ ret = posix_fadvise(arg1, target_offset64(arg2, arg3),
+ target_offset64(arg4, arg5), arg6);
+ return -host_to_target_errno(ret);
#endif
#ifdef TARGET_NR_fadvise64
@@ -11844,10 +11532,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg4 = arg5;
arg5 = arg6;
}
- ret = -host_to_target_errno(posix_fadvise(arg1,
- target_offset64(arg2, arg3),
- arg4, arg5));
- break;
+ ret = posix_fadvise(arg1, target_offset64(arg2, arg3), arg4, arg5);
+ return -host_to_target_errno(ret);
#endif
#else /* not a 32-bit ABI */
@@ -11867,8 +11553,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
default: break;
}
#endif
- ret = -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
- break;
+ return -host_to_target_errno(posix_fadvise(arg1, arg2, arg3, arg4));
#endif
#endif /* end of 64-bit ABI fadvise handling */
@@ -11878,8 +11563,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
turns private file-backed mappings into anonymous mappings.
This will break MADV_DONTNEED.
This is a hint, so ignoring and returning success is ok. */
- ret = get_errno(0);
- break;
+ return 0;
#endif
#if TARGET_ABI_BITS == 32
case TARGET_NR_fcntl64:
@@ -11898,8 +11582,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
cmd = target_to_host_fcntl_cmd(arg2);
if (cmd == -TARGET_EINVAL) {
- ret = cmd;
- break;
+ return cmd;
}
switch(arg2) {
@@ -11926,27 +11609,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = do_fcntl(arg1, arg2, arg3);
break;
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_cacheflush
case TARGET_NR_cacheflush:
/* self-modifying code is handled automatically, so nothing needed */
- ret = 0;
- break;
-#endif
-#ifdef TARGET_NR_security
- case TARGET_NR_security:
- goto unimplemented;
+ return 0;
#endif
#ifdef TARGET_NR_getpagesize
case TARGET_NR_getpagesize:
- ret = TARGET_PAGE_SIZE;
- break;
+ return TARGET_PAGE_SIZE;
#endif
case TARGET_NR_gettid:
- ret = get_errno(gettid());
- break;
+ return get_errno(gettid());
#ifdef TARGET_NR_readahead
case TARGET_NR_readahead:
#if TARGET_ABI_BITS == 32
@@ -11959,7 +11635,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#else
ret = get_errno(readahead(arg1, arg2, arg3));
#endif
- break;
+ return ret;
#endif
#ifdef CONFIG_ATTR
#ifdef TARGET_NR_setxattr
@@ -11970,8 +11646,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg2) {
b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
if (!b) {
- ret = -TARGET_EFAULT;
- break;
+ return -TARGET_EFAULT;
}
}
p = lock_user_string(arg1);
@@ -11986,7 +11661,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
unlock_user(p, arg1, 0);
unlock_user(b, arg2, arg3);
- break;
+ return ret;
}
case TARGET_NR_flistxattr:
{
@@ -11994,13 +11669,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg2) {
b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
if (!b) {
- ret = -TARGET_EFAULT;
- break;
+ return -TARGET_EFAULT;
}
}
ret = get_errno(flistxattr(arg1, b, arg3));
unlock_user(b, arg2, arg3);
- break;
+ return ret;
}
case TARGET_NR_setxattr:
case TARGET_NR_lsetxattr:
@@ -12009,8 +11683,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg3) {
v = lock_user(VERIFY_READ, arg3, arg4, 1);
if (!v) {
- ret = -TARGET_EFAULT;
- break;
+ return -TARGET_EFAULT;
}
}
p = lock_user_string(arg1);
@@ -12028,15 +11701,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(n, arg2, 0);
unlock_user(v, arg3, 0);
}
- break;
+ return ret;
case TARGET_NR_fsetxattr:
{
void *n, *v = 0;
if (arg3) {
v = lock_user(VERIFY_READ, arg3, arg4, 1);
if (!v) {
- ret = -TARGET_EFAULT;
- break;
+ return -TARGET_EFAULT;
}
}
n = lock_user_string(arg2);
@@ -12048,7 +11720,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(n, arg2, 0);
unlock_user(v, arg3, 0);
}
- break;
+ return ret;
case TARGET_NR_getxattr:
case TARGET_NR_lgetxattr:
{
@@ -12056,8 +11728,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg3) {
v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
if (!v) {
- ret = -TARGET_EFAULT;
- break;
+ return -TARGET_EFAULT;
}
}
p = lock_user_string(arg1);
@@ -12075,15 +11746,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(n, arg2, 0);
unlock_user(v, arg3, arg4);
}
- break;
+ return ret;
case TARGET_NR_fgetxattr:
{
void *n, *v = 0;
if (arg3) {
v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
if (!v) {
- ret = -TARGET_EFAULT;
- break;
+ return -TARGET_EFAULT;
}
}
n = lock_user_string(arg2);
@@ -12095,7 +11765,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(n, arg2, 0);
unlock_user(v, arg3, arg4);
}
- break;
+ return ret;
case TARGET_NR_removexattr:
case TARGET_NR_lremovexattr:
{
@@ -12114,7 +11784,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
unlock_user(n, arg2, 0);
}
- break;
+ return ret;
case TARGET_NR_fremovexattr:
{
void *n;
@@ -12126,15 +11796,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
unlock_user(n, arg2, 0);
}
- break;
+ return ret;
#endif
#endif /* CONFIG_ATTR */
#ifdef TARGET_NR_set_thread_area
case TARGET_NR_set_thread_area:
#if defined(TARGET_MIPS)
((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
- ret = 0;
- break;
+ return 0;
#elif defined(TARGET_CRIS)
if (arg1 & 0xff)
ret = -TARGET_EINVAL;
@@ -12142,39 +11811,35 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
ret = 0;
}
- break;
+ return ret;
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
- ret = do_set_thread_area(cpu_env, arg1);
- break;
+ return do_set_thread_area(cpu_env, arg1);
#elif defined(TARGET_M68K)
{
TaskState *ts = cpu->opaque;
ts->tp_value = arg1;
- ret = 0;
- break;
+ return 0;
}
#else
- goto unimplemented_nowarn;
+ return -TARGET_ENOSYS;
#endif
#endif
#ifdef TARGET_NR_get_thread_area
case TARGET_NR_get_thread_area:
#if defined(TARGET_I386) && defined(TARGET_ABI32)
- ret = do_get_thread_area(cpu_env, arg1);
- break;
+ return do_get_thread_area(cpu_env, arg1);
#elif defined(TARGET_M68K)
{
TaskState *ts = cpu->opaque;
- ret = ts->tp_value;
- break;
+ return ts->tp_value;
}
#else
- goto unimplemented_nowarn;
+ return -TARGET_ENOSYS;
#endif
#endif
#ifdef TARGET_NR_getdomainname
case TARGET_NR_getdomainname:
- goto unimplemented_nowarn;
+ return -TARGET_ENOSYS;
#endif
#ifdef TARGET_NR_clock_settime
@@ -12186,7 +11851,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret)) {
ret = get_errno(clock_settime(arg1, &ts));
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_clock_gettime
@@ -12197,7 +11862,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret)) {
ret = host_to_target_timespec(arg2, &ts);
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_clock_getres
@@ -12208,7 +11873,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!is_error(ret)) {
host_to_target_timespec(arg2, &ts);
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_clock_nanosleep
@@ -12228,24 +11893,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
((CPUPPCState *)cpu_env)->crf[0] |= 1;
}
#endif
- break;
+ return ret;
}
#endif
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
case TARGET_NR_set_tid_address:
- ret = get_errno(set_tid_address((int *)g2h(arg1)));
- break;
+ return get_errno(set_tid_address((int *)g2h(arg1)));
#endif
case TARGET_NR_tkill:
- ret = get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
- break;
+ return get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
case TARGET_NR_tgkill:
- ret = get_errno(safe_tgkill((int)arg1, (int)arg2,
- target_to_host_signal(arg3)));
- break;
+ return get_errno(safe_tgkill((int)arg1, (int)arg2,
+ target_to_host_signal(arg3)));
#ifdef TARGET_NR_set_robust_list
case TARGET_NR_set_robust_list:
@@ -12262,7 +11924,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
* holding a mutex that is shared with another process via
* shared memory).
*/
- goto unimplemented_nowarn;
+ return -TARGET_ENOSYS;
#endif
#if defined(TARGET_NR_utimensat)
@@ -12280,25 +11942,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
else {
if (!(p = lock_user_string(arg2))) {
- ret = -TARGET_EFAULT;
- goto fail;
+ return -TARGET_EFAULT;
}
ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
unlock_user(p, arg2, 0);
}
}
- break;
+ return ret;
#endif
case TARGET_NR_futex:
- ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
- break;
+ return do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
case TARGET_NR_inotify_init:
ret = get_errno(sys_inotify_init());
if (ret >= 0) {
fd_trans_register(ret, &target_inotify_trans);
}
- break;
+ return ret;
#endif
#ifdef CONFIG_INOTIFY1
#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
@@ -12308,7 +11968,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (ret >= 0) {
fd_trans_register(ret, &target_inotify_trans);
}
- break;
+ return ret;
#endif
#endif
#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
@@ -12316,12 +11976,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
p = lock_user_string(arg2);
ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
unlock_user(p, arg2, 0);
- break;
+ return ret;
#endif
#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
case TARGET_NR_inotify_rm_watch:
- ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
- break;
+ return get_errno(sys_inotify_rm_watch(arg1, arg2));
#endif
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
@@ -12335,28 +11994,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
pposix_mq_attr = NULL;
if (arg4) {
if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
- goto efault;
+ return -TARGET_EFAULT;
}
pposix_mq_attr = &posix_mq_attr;
}
p = lock_user_string(arg1 - 1);
if (!p) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
unlock_user (p, arg1, 0);
}
- break;
+ return ret;
case TARGET_NR_mq_unlink:
p = lock_user_string(arg1 - 1);
if (!p) {
- ret = -TARGET_EFAULT;
- break;
+ return -TARGET_EFAULT;
}
ret = get_errno(mq_unlink(p));
unlock_user (p, arg1, 0);
- break;
+ return ret;
case TARGET_NR_mq_timedsend:
{
@@ -12372,7 +12030,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
unlock_user (p, arg2, arg3);
}
- break;
+ return ret;
case TARGET_NR_mq_timedreceive:
{
@@ -12393,7 +12051,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg4 != 0)
put_user_u32(prio, arg4);
}
- break;
+ return ret;
/* Not implemented for now... */
/* case TARGET_NR_mq_notify: */
@@ -12414,7 +12072,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
}
}
- break;
+ return ret;
#endif
#ifdef CONFIG_SPLICE
@@ -12423,7 +12081,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
ret = get_errno(tee(arg1,arg2,arg3,arg4));
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_splice
case TARGET_NR_splice:
@@ -12432,29 +12090,29 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
loff_t *ploff_in = NULL, *ploff_out = NULL;
if (arg2) {
if (get_user_u64(loff_in, arg2)) {
- goto efault;
+ return -TARGET_EFAULT;
}
ploff_in = &loff_in;
}
if (arg4) {
if (get_user_u64(loff_out, arg4)) {
- goto efault;
+ return -TARGET_EFAULT;
}
ploff_out = &loff_out;
}
ret = get_errno(splice(arg1, ploff_in, arg3, ploff_out, arg5, arg6));
if (arg2) {
if (put_user_u64(loff_in, arg2)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
if (arg4) {
if (put_user_u64(loff_out, arg4)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
}
- break;
+ return ret;
#endif
#ifdef TARGET_NR_vmsplice
case TARGET_NR_vmsplice:
@@ -12467,7 +12125,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = -host_to_target_errno(errno);
}
}
- break;
+ return ret;
#endif
#endif /* CONFIG_SPLICE */
#ifdef CONFIG_EVENTFD
@@ -12477,7 +12135,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (ret >= 0) {
fd_trans_register(ret, &target_eventfd_trans);
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_eventfd2)
case TARGET_NR_eventfd2:
@@ -12493,7 +12151,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (ret >= 0) {
fd_trans_register(ret, &target_eventfd_trans);
}
- break;
+ return ret;
}
#endif
#endif /* CONFIG_EVENTFD */
@@ -12505,7 +12163,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#else
ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
#endif
- break;
+ return ret;
#endif
#if defined(CONFIG_SYNC_FILE_RANGE)
#if defined(TARGET_NR_sync_file_range)
@@ -12521,7 +12179,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#else
ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
#endif
- break;
+ return ret;
#endif
#if defined(TARGET_NR_sync_file_range2)
case TARGET_NR_sync_file_range2:
@@ -12532,29 +12190,25 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#else
ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
#endif
- break;
+ return ret;
#endif
#endif
#if defined(TARGET_NR_signalfd4)
case TARGET_NR_signalfd4:
- ret = do_signalfd4(arg1, arg2, arg4);
- break;
+ return do_signalfd4(arg1, arg2, arg4);
#endif
#if defined(TARGET_NR_signalfd)
case TARGET_NR_signalfd:
- ret = do_signalfd4(arg1, arg2, 0);
- break;
+ return do_signalfd4(arg1, arg2, 0);
#endif
#if defined(CONFIG_EPOLL)
#if defined(TARGET_NR_epoll_create)
case TARGET_NR_epoll_create:
- ret = get_errno(epoll_create(arg1));
- break;
+ return get_errno(epoll_create(arg1));
#endif
#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
case TARGET_NR_epoll_create1:
- ret = get_errno(epoll_create1(arg1));
- break;
+ return get_errno(epoll_create1(arg1));
#endif
#if defined(TARGET_NR_epoll_ctl)
case TARGET_NR_epoll_ctl:
@@ -12564,7 +12218,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg4) {
struct target_epoll_event *target_ep;
if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
- goto efault;
+ return -TARGET_EFAULT;
}
ep.events = tswap32(target_ep->events);
/* The epoll_data_t union is just opaque data to the kernel,
@@ -12575,8 +12229,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user_struct(target_ep, arg4, 0);
epp = &ep;
}
- ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
- break;
+ return get_errno(epoll_ctl(arg1, arg2, arg3, epp));
}
#endif
@@ -12595,21 +12248,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
int timeout = arg4;
if (maxevents <= 0 || maxevents > TARGET_EP_MAX_EVENTS) {
- ret = -TARGET_EINVAL;
- break;
+ return -TARGET_EINVAL;
}
target_ep = lock_user(VERIFY_WRITE, arg2,
maxevents * sizeof(struct target_epoll_event), 1);
if (!target_ep) {
- goto efault;
+ return -TARGET_EFAULT;
}
ep = g_try_new(struct epoll_event, maxevents);
if (!ep) {
unlock_user(target_ep, arg2, 0);
- ret = -TARGET_ENOMEM;
- break;
+ return -TARGET_ENOMEM;
}
switch (num) {
@@ -12663,7 +12314,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(target_ep, arg2, 0);
}
g_free(ep);
- break;
+ return ret;
}
#endif
#endif
@@ -12676,7 +12327,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
int resource = target_to_host_resource(arg2);
if (arg3) {
if (!lock_user_struct(VERIFY_READ, target_rnew, arg3, 1)) {
- goto efault;
+ return -TARGET_EFAULT;
}
rnew.rlim_cur = tswap64(target_rnew->rlim_cur);
rnew.rlim_max = tswap64(target_rnew->rlim_max);
@@ -12687,13 +12338,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(sys_prlimit64(arg1, resource, rnewp, arg4 ? &rold : 0));
if (!is_error(ret) && arg4) {
if (!lock_user_struct(VERIFY_WRITE, target_rold, arg4, 1)) {
- goto efault;
+ return -TARGET_EFAULT;
}
target_rold->rlim_cur = tswap64(rold.rlim_cur);
target_rold->rlim_max = tswap64(rold.rlim_max);
unlock_user_struct(target_rold, arg4, 1);
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_gethostname
@@ -12706,7 +12357,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
} else {
ret = -TARGET_EFAULT;
}
- break;
+ return ret;
}
#endif
#ifdef TARGET_NR_atomic_cmpxchg_32
@@ -12727,17 +12378,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
if (mem_value == arg2)
put_user_u32(arg1, arg6);
- ret = mem_value;
- break;
+ return mem_value;
}
#endif
#ifdef TARGET_NR_atomic_barrier
case TARGET_NR_atomic_barrier:
- {
- /* Like the kernel implementation and the qemu arm barrier, no-op this? */
- ret = 0;
- break;
- }
+ /* Like the kernel implementation and the
+ qemu arm barrier, no-op this? */
+ return 0;
#endif
#ifdef TARGET_NR_timer_create
@@ -12759,7 +12407,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
phost_sevp = &host_sevp;
ret = target_to_host_sigevent(phost_sevp, arg2);
if (ret != 0) {
- break;
+ return ret;
}
}
@@ -12768,11 +12416,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
phtimer = NULL;
} else {
if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
}
- break;
+ return ret;
}
#endif
@@ -12792,15 +12440,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
if (target_to_host_itimerspec(&hspec_new, arg3)) {
- goto efault;
+ return -TARGET_EFAULT;
}
ret = get_errno(
timer_settime(htimer, arg2, &hspec_new, &hspec_old));
if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
}
#endif
@@ -12823,7 +12471,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = -TARGET_EFAULT;
}
}
- break;
+ return ret;
}
#endif
@@ -12840,7 +12488,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(timer_getoverrun(htimer));
}
fd_trans_unregister(ret);
- break;
+ return ret;
}
#endif
@@ -12857,15 +12505,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(timer_delete(htimer));
g_posix_timers[timerid] = 0;
}
- break;
+ return ret;
}
#endif
#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD)
case TARGET_NR_timerfd_create:
- ret = get_errno(timerfd_create(arg1,
- target_to_host_bitmask(arg2, fcntl_flags_tbl)));
- break;
+ return get_errno(timerfd_create(arg1,
+ target_to_host_bitmask(arg2, fcntl_flags_tbl)));
#endif
#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD)
@@ -12876,10 +12523,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(timerfd_gettime(arg1, &its_curr));
if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD)
@@ -12889,7 +12536,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (arg3) {
if (target_to_host_itimerspec(&its_new, arg3)) {
- goto efault;
+ return -TARGET_EFAULT;
}
p_new = &its_new;
} else {
@@ -12899,64 +12546,82 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old));
if (arg4 && host_to_target_itimerspec(arg4, &its_old)) {
- goto efault;
+ return -TARGET_EFAULT;
}
}
- break;
+ return ret;
#endif
#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get)
case TARGET_NR_ioprio_get:
- ret = get_errno(ioprio_get(arg1, arg2));
- break;
+ return get_errno(ioprio_get(arg1, arg2));
#endif
#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set)
case TARGET_NR_ioprio_set:
- ret = get_errno(ioprio_set(arg1, arg2, arg3));
- break;
+ return get_errno(ioprio_set(arg1, arg2, arg3));
#endif
#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS)
case TARGET_NR_setns:
- ret = get_errno(setns(arg1, arg2));
- break;
+ return get_errno(setns(arg1, arg2));
#endif
#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS)
case TARGET_NR_unshare:
- ret = get_errno(unshare(arg1));
- break;
+ return get_errno(unshare(arg1));
#endif
#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp)
case TARGET_NR_kcmp:
- ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
- break;
+ return get_errno(kcmp(arg1, arg2, arg3, arg4, arg5));
#endif
#ifdef TARGET_NR_swapcontext
case TARGET_NR_swapcontext:
/* PowerPC specific. */
- ret = do_swapcontext(cpu_env, arg1, arg2, arg3);
- break;
+ return do_swapcontext(cpu_env, arg1, arg2, arg3);
#endif
default:
- unimplemented:
qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
-#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
- unimplemented_nowarn:
-#endif
- ret = -TARGET_ENOSYS;
- break;
+ return -TARGET_ENOSYS;
+ }
+ return ret;
+}
+
+abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
+ abi_long arg2, abi_long arg3, abi_long arg4,
+ abi_long arg5, abi_long arg6, abi_long arg7,
+ abi_long arg8)
+{
+ CPUState *cpu = ENV_GET_CPU(cpu_env);
+ abi_long ret;
+
+#ifdef DEBUG_ERESTARTSYS
+ /* Debug-only code for exercising the syscall-restart code paths
+ * in the per-architecture cpu main loops: restart every syscall
+ * the guest makes once before letting it through.
+ */
+ {
+ static bool flag;
+ flag = !flag;
+ if (flag) {
+ return -TARGET_ERESTARTSYS;
+ }
}
-fail:
-#ifdef DEBUG
- gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
#endif
- if(do_strace)
+
+ trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8);
+
+ if (unlikely(do_strace)) {
+ print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+ ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8);
print_syscall_ret(num, ret);
+ } else {
+ ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8);
+ }
+
trace_guest_user_syscall_ret(cpu, num, ret);
return ret;
-efault:
- ret = -TARGET_EFAULT;
- goto fail;
}
diff --git a/monitor.c b/monitor.c
index a1999e396c..94f673511b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1454,6 +1454,17 @@ static void hmp_info_opcount(Monitor *mon, const QDict *qdict)
}
#endif
+static void hmp_info_sync_profile(Monitor *mon, const QDict *qdict)
+{
+ int64_t max = qdict_get_try_int(qdict, "max", 10);
+ bool mean = qdict_get_try_bool(qdict, "mean", false);
+ bool coalesce = !qdict_get_try_bool(qdict, "no_coalesce", false);
+ enum QSPSortBy sort_by;
+
+ sort_by = mean ? QSP_SORT_BY_AVG_WAIT_TIME : QSP_SORT_BY_TOTAL_WAIT_TIME;
+ qsp_report((FILE *)mon, monitor_fprintf, max, sort_by, coalesce);
+}
+
static void hmp_info_history(Monitor *mon, const QDict *qdict)
{
int i;
diff --git a/pc-bios/optionrom/linuxboot_dma.c b/pc-bios/optionrom/linuxboot_dma.c
index 4754282ad7..d856d41b55 100644
--- a/pc-bios/optionrom/linuxboot_dma.c
+++ b/pc-bios/optionrom/linuxboot_dma.c
@@ -58,8 +58,6 @@ asm(
" jmp load_kernel\n"
);
-#include "../../include/hw/nvram/fw_cfg_keys.h"
-
/* QEMU_CFG_DMA_CONTROL bits */
#define BIOS_CFG_DMA_CTL_ERROR 0x01
#define BIOS_CFG_DMA_CTL_READ 0x02
@@ -73,6 +71,8 @@ asm(
#define uint32_t unsigned int
#define uint16_t unsigned short
+#include "../../include/standard-headers/linux/qemu_fw_cfg.h"
+
#define barrier() asm("" : : : "memory")
typedef struct FWCfgDmaAccess {
diff --git a/pc-bios/optionrom/optionrom.h b/pc-bios/optionrom/optionrom.h
index 6c4c2c82f4..a2b612f1a7 100644
--- a/pc-bios/optionrom/optionrom.h
+++ b/pc-bios/optionrom/optionrom.h
@@ -19,7 +19,20 @@
*/
-#include "../../include/hw/nvram/fw_cfg_keys.h"
+#define FW_CFG_KERNEL_ADDR 0x07
+#define FW_CFG_KERNEL_SIZE 0x08
+#define FW_CFG_KERNEL_CMDLINE 0x09
+#define FW_CFG_INITRD_ADDR 0x0a
+#define FW_CFG_INITRD_SIZE 0x0b
+#define FW_CFG_KERNEL_ENTRY 0x10
+#define FW_CFG_KERNEL_DATA 0x11
+#define FW_CFG_INITRD_DATA 0x12
+#define FW_CFG_CMDLINE_ADDR 0x13
+#define FW_CFG_CMDLINE_SIZE 0x14
+#define FW_CFG_CMDLINE_DATA 0x15
+#define FW_CFG_SETUP_ADDR 0x16
+#define FW_CFG_SETUP_SIZE 0x17
+#define FW_CFG_SETUP_DATA 0x18
#define BIOS_CFG_IOPORT_CFG 0x510
#define BIOS_CFG_IOPORT_DATA 0x511
diff --git a/qemu-options.hx b/qemu-options.hx
index 5515dfaba5..d66ab1bddb 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3953,6 +3953,16 @@ Dump json-encoded vmstate information for current machine type to file
in @var{file}
ETEXI
+DEF("enable-sync-profile", 0, QEMU_OPTION_enable_sync_profile,
+ "-enable-sync-profile\n"
+ " enable synchronization profiling\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -enable-sync-profile
+@findex -enable-sync-profile
+Enable synchronization profiling.
+ETEXI
+
STEXI
@end table
ETEXI
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 42e1c50dd8..3765b0e35e 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1367,10 +1367,10 @@ sub process {
# extract the filename as it passes
if ($line =~ /^diff --git.*?(\S+)$/) {
$realfile = $1;
- $realfile =~ s@^([^/]*)/@@;
+ $realfile =~ s@^([^/]*)/@@ if (!$file);
} elsif ($line =~ /^\+\+\+\s+(\S+)/) {
$realfile = $1;
- $realfile =~ s@^([^/]*)/@@;
+ $realfile =~ s@^([^/]*)/@@ if (!$file);
$p1_prefix = $1;
if (!$file && $tree && $p1_prefix ne '' &&
@@ -1929,9 +1929,8 @@ sub process {
my ($where, $prefix) = ($-[1], $1);
if ($prefix !~ /$Type\s+$/ &&
($where != 0 || $prefix !~ /^.\s+$/) &&
- $prefix !~ /{\s+$/ &&
$prefix !~ /\#\s*define[^(]*\([^)]*\)\s+$/ &&
- $prefix !~ /,\s+$/) {
+ $prefix !~ /[,{:]\s+$/) {
ERROR("space prohibited before open square bracket '['\n" . $herecurr);
}
}
diff --git a/scripts/qemu-guest-agent/fsfreeze-hook b/scripts/qemu-guest-agent/fsfreeze-hook
index c27b29f282..13aafd4845 100755
--- a/scripts/qemu-guest-agent/fsfreeze-hook
+++ b/scripts/qemu-guest-agent/fsfreeze-hook
@@ -13,7 +13,7 @@ FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d
# Check whether file $1 is a backup or rpm-generated file and should be ignored
is_ignored_file() {
case "$1" in
- *~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave | *.sample)
+ *~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave | *.sample | *.dpkg-old | *.dpkg-new | *.dpkg-tmp | *.dpkg-dist | *.dpkg-bak | *.dpkg-backup | *.dpkg-remove)
return 0 ;;
esac
return 1
diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh
index feb75390aa..0a964fe240 100755
--- a/scripts/update-linux-headers.sh
+++ b/scripts/update-linux-headers.sh
@@ -165,7 +165,9 @@ EOF
rm -rf "$output/include/standard-headers/linux"
mkdir -p "$output/include/standard-headers/linux"
-for i in "$tmpdir"/include/linux/*virtio*.h "$tmpdir/include/linux/input.h" \
+for i in "$tmpdir"/include/linux/*virtio*.h \
+ "$tmpdir/include/linux/qemu_fw_cfg.h" \
+ "$tmpdir/include/linux/input.h" \
"$tmpdir/include/linux/input-event-codes.h" \
"$tmpdir/include/linux/pci_regs.h" \
"$tmpdir/include/linux/ethtool.h" "$tmpdir/include/linux/kernel.h" \
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
index 1528a712a0..ed037aabee 100644
--- a/scsi/qemu-pr-helper.c
+++ b/scsi/qemu-pr-helper.c
@@ -301,7 +301,11 @@ void put_multipath_config(struct config *conf)
static void multipath_pr_init(void)
{
udev = udev_new();
+#ifdef CONFIG_MPATH_NEW_API
multipath_conf = mpath_lib_init();
+#else
+ mpath_lib_init(udev);
+#endif
}
static int is_mpath(int fd)
diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c
index 9b6db2e740..eb745d7d6a 100644
--- a/stubs/iothread-lock.c
+++ b/stubs/iothread-lock.c
@@ -7,7 +7,7 @@ bool qemu_mutex_iothread_locked(void)
return true;
}
-void qemu_mutex_lock_iothread(void)
+void qemu_mutex_lock_iothread_impl(const char *file, int line)
{
}
diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c
index 7cac8734c7..b2b22d231e 100644
--- a/target/arm/arm-semi.c
+++ b/target/arm/arm-semi.c
@@ -136,7 +136,7 @@ static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
#ifdef CONFIG_USER_ONLY
ts->swi_errno = err;
#else
- syscall_err = err;
+ syscall_err = err;
#endif
reg0 = ret;
} else {
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 62c36b4150..65c0fa0a65 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1320,14 +1320,14 @@ enum arm_cpu_mode {
#define ARM_VFP_FPINST2 10
/* iwMMXt coprocessor control registers. */
-#define ARM_IWMMXT_wCID 0
-#define ARM_IWMMXT_wCon 1
-#define ARM_IWMMXT_wCSSF 2
-#define ARM_IWMMXT_wCASF 3
-#define ARM_IWMMXT_wCGR0 8
-#define ARM_IWMMXT_wCGR1 9
-#define ARM_IWMMXT_wCGR2 10
-#define ARM_IWMMXT_wCGR3 11
+#define ARM_IWMMXT_wCID 0
+#define ARM_IWMMXT_wCon 1
+#define ARM_IWMMXT_wCSSF 2
+#define ARM_IWMMXT_wCASF 3
+#define ARM_IWMMXT_wCGR0 8
+#define ARM_IWMMXT_wCGR1 9
+#define ARM_IWMMXT_wCGR2 10
+#define ARM_IWMMXT_wCGR3 11
/* V7M CCR bits */
FIELD(V7M_CCR, NONBASETHRDENA, 0, 1)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c9bce1efcb..088f452716 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3754,11 +3754,11 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0,
.access = PL2_RW,
.readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore },
- { .name = "HCR_EL2", .state = ARM_CP_STATE_AA64,
+ { .name = "HCR_EL2", .state = ARM_CP_STATE_BOTH,
.type = ARM_CP_NO_RAW,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
.access = PL2_RW,
- .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore },
+ .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0,
.access = PL2_RW,
@@ -3857,6 +3857,15 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
REGINFO_SENTINEL
};
+/* Ditto, but for registers which exist in ARMv8 but not v7 */
+static const ARMCPRegInfo el3_no_el2_v8_cp_reginfo[] = {
+ { .name = "HCR2", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4,
+ .access = PL2_RW,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
+ REGINFO_SENTINEL
+};
+
static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
@@ -3883,10 +3892,26 @@ static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
* HCR_PTW forbids certain page-table setups
* HCR_DC Disables stage1 and enables stage2 translation
*/
- if ((raw_read(env, ri) ^ value) & (HCR_VM | HCR_PTW | HCR_DC)) {
+ if ((env->cp15.hcr_el2 ^ value) & (HCR_VM | HCR_PTW | HCR_DC)) {
tlb_flush(CPU(cpu));
}
- raw_write(env, ri, value);
+ env->cp15.hcr_el2 = value;
+}
+
+static void hcr_writehigh(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /* Handle HCR2 write, i.e. write to high half of HCR_EL2 */
+ value = deposit64(env->cp15.hcr_el2, 32, 32, value);
+ hcr_write(env, NULL, value);
+}
+
+static void hcr_writelow(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ /* Handle HCR write, i.e. write to low half of HCR_EL2 */
+ value = deposit64(env->cp15.hcr_el2, 0, 32, value);
+ hcr_write(env, NULL, value);
}
static const ARMCPRegInfo el2_cp_reginfo[] = {
@@ -3894,6 +3919,11 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
.writefn = hcr_write },
+ { .name = "HCR", .state = ARM_CP_STATE_AA32,
+ .type = ARM_CP_ALIAS,
+ .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
+ .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
+ .writefn = hcr_writelow },
{ .name = "ELR_EL2", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
@@ -4128,6 +4158,16 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
REGINFO_SENTINEL
};
+static const ARMCPRegInfo el2_v8_cp_reginfo[] = {
+ { .name = "HCR2", .state = ARM_CP_STATE_AA32,
+ .type = ARM_CP_ALIAS,
+ .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4,
+ .access = PL2_RW,
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.hcr_el2),
+ .writefn = hcr_writehigh },
+ REGINFO_SENTINEL
+};
+
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
@@ -5179,6 +5219,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
};
define_arm_cp_regs(cpu, vpidr_regs);
define_arm_cp_regs(cpu, el2_cp_reginfo);
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ define_arm_cp_regs(cpu, el2_v8_cp_reginfo);
+ }
/* RVBAR_EL2 is only implemented if EL2 is the highest EL */
if (!arm_feature(env, ARM_FEATURE_EL3)) {
ARMCPRegInfo rvbar = {
@@ -5211,6 +5254,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
};
define_arm_cp_regs(cpu, vpidr_regs);
define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo);
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ define_arm_cp_regs(cpu, el3_no_el2_v8_cp_reginfo);
+ }
}
}
if (arm_feature(env, ARM_FEATURE_EL3)) {
@@ -5459,6 +5505,16 @@ void register_cp_regs_for_features(ARMCPU *cpu)
REGINFO_SENTINEL
};
define_arm_cp_regs(cpu, auxcr_reginfo);
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ /* HACTLR2 maps to ACTLR_EL2[63:32] and is not in ARMv7 */
+ ARMCPRegInfo hactlr2_reginfo = {
+ .name = "HACTLR2", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 3,
+ .access = PL2_RW, .type = ARM_CP_CONST,
+ .resetvalue = 0
+ };
+ define_one_arm_cp_reg(cpu, &hactlr2_reginfo);
+ }
}
if (arm_feature(env, ARM_FEATURE_CBAR)) {
@@ -7977,6 +8033,125 @@ void aarch64_sync_64_to_32(CPUARMState *env)
env->regs[15] = env->pc;
}
+static void take_aarch32_exception(CPUARMState *env, int new_mode,
+ uint32_t mask, uint32_t offset,
+ uint32_t newpc)
+{
+ /* Change the CPU state so as to actually take the exception. */
+ switch_mode(env, new_mode);
+ /*
+ * For exceptions taken to AArch32 we must clear the SS bit in both
+ * PSTATE and in the old-state value we save to SPSR_<mode>, so zero it now.
+ */
+ env->uncached_cpsr &= ~PSTATE_SS;
+ env->spsr = cpsr_read(env);
+ /* Clear IT bits. */
+ env->condexec_bits = 0;
+ /* Switch to the new mode, and to the correct instruction set. */
+ env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
+ /* Set new mode endianness */
+ env->uncached_cpsr &= ~CPSR_E;
+ if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
+ env->uncached_cpsr |= CPSR_E;
+ }
+ /* J and IL must always be cleared for exception entry */
+ env->uncached_cpsr &= ~(CPSR_IL | CPSR_J);
+ env->daif |= mask;
+
+ if (new_mode == ARM_CPU_MODE_HYP) {
+ env->thumb = (env->cp15.sctlr_el[2] & SCTLR_TE) != 0;
+ env->elr_el[2] = env->regs[15];
+ } else {
+ /*
+ * this is a lie, as there was no c1_sys on V4T/V5, but who cares
+ * and we should just guard the thumb mode on V4
+ */
+ if (arm_feature(env, ARM_FEATURE_V4T)) {
+ env->thumb =
+ (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0;
+ }
+ env->regs[14] = env->regs[15] + offset;
+ }
+ env->regs[15] = newpc;
+}
+
+static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
+{
+ /*
+ * Handle exception entry to Hyp mode; this is sufficiently
+ * different to entry to other AArch32 modes that we handle it
+ * separately here.
+ *
+ * The vector table entry used is always the 0x14 Hyp mode entry point,
+ * unless this is an UNDEF/HVC/abort taken from Hyp to Hyp.
+ * The offset applied to the preferred return address is always zero
+ * (see DDI0487C.a section G1.12.3).
+ * PSTATE A/I/F masks are set based only on the SCR.EA/IRQ/FIQ values.
+ */
+ uint32_t addr, mask;
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ switch (cs->exception_index) {
+ case EXCP_UDEF:
+ addr = 0x04;
+ break;
+ case EXCP_SWI:
+ addr = 0x14;
+ break;
+ case EXCP_BKPT:
+ /* Fall through to prefetch abort. */
+ case EXCP_PREFETCH_ABORT:
+ env->cp15.ifar_s = env->exception.vaddress;
+ qemu_log_mask(CPU_LOG_INT, "...with HIFAR 0x%x\n",
+ (uint32_t)env->exception.vaddress);
+ addr = 0x0c;
+ break;
+ case EXCP_DATA_ABORT:
+ env->cp15.dfar_s = env->exception.vaddress;
+ qemu_log_mask(CPU_LOG_INT, "...with HDFAR 0x%x\n",
+ (uint32_t)env->exception.vaddress);
+ addr = 0x10;
+ break;
+ case EXCP_IRQ:
+ addr = 0x18;
+ break;
+ case EXCP_FIQ:
+ addr = 0x1c;
+ break;
+ case EXCP_HVC:
+ addr = 0x08;
+ break;
+ case EXCP_HYP_TRAP:
+ addr = 0x14;
+ default:
+ cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
+ }
+
+ if (cs->exception_index != EXCP_IRQ && cs->exception_index != EXCP_FIQ) {
+ env->cp15.esr_el[2] = env->exception.syndrome;
+ }
+
+ if (arm_current_el(env) != 2 && addr < 0x14) {
+ addr = 0x14;
+ }
+
+ mask = 0;
+ if (!(env->cp15.scr_el3 & SCR_EA)) {
+ mask |= CPSR_A;
+ }
+ if (!(env->cp15.scr_el3 & SCR_IRQ)) {
+ mask |= CPSR_I;
+ }
+ if (!(env->cp15.scr_el3 & SCR_FIQ)) {
+ mask |= CPSR_F;
+ }
+
+ addr += env->cp15.hvbar;
+
+ take_aarch32_exception(env, ARM_CPU_MODE_HYP, mask, 0, addr);
+}
+
static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
@@ -8012,6 +8187,11 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
env->cp15.mdscr_el1 = deposit64(env->cp15.mdscr_el1, 2, 4, moe);
}
+ if (env->exception.target_el == 2) {
+ arm_cpu_do_interrupt_aarch32_hyp(cs);
+ return;
+ }
+
/* TODO: Vectored interrupt controller. */
switch (cs->exception_index) {
case EXCP_UDEF:
@@ -8119,29 +8299,7 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
env->cp15.scr_el3 &= ~SCR_NS;
}
- switch_mode (env, new_mode);
- /* For exceptions taken to AArch32 we must clear the SS bit in both
- * PSTATE and in the old-state value we save to SPSR_<mode>, so zero it now.
- */
- env->uncached_cpsr &= ~PSTATE_SS;
- env->spsr = cpsr_read(env);
- /* Clear IT bits. */
- env->condexec_bits = 0;
- /* Switch to the new mode, and to the correct instruction set. */
- env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
- /* Set new mode endianness */
- env->uncached_cpsr &= ~CPSR_E;
- if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
- env->uncached_cpsr |= CPSR_E;
- }
- env->daif |= mask;
- /* this is a lie, as the was no c1_sys on V4T/V5, but who cares
- * and we should just guard the thumb mode on V4 */
- if (arm_feature(env, ARM_FEATURE_V4T)) {
- env->thumb = (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0;
- }
- env->regs[14] = env->regs[15] + offset;
- env->regs[15] = addr;
+ take_aarch32_exception(env, new_mode, mask, offset, addr);
}
/* Handle exception entry to a target EL which is using AArch64 */
@@ -11564,45 +11722,30 @@ float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env)
#define VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
float##fsz HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \
void *fpstp) \
-{ \
- float_status *fpst = fpstp; \
- float##fsz tmp; \
- tmp = itype##_to_##float##fsz(x, fpst); \
- return float##fsz##_scalbn(tmp, -(int)shift, fpst); \
-}
+{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); }
-/* Notice that we want only input-denormal exception flags from the
- * scalbn operation: the other possible flags (overflow+inexact if
- * we overflow to infinity, output-denormal) aren't correct for the
- * complete scale-and-convert operation.
- */
-#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, round) \
-uint##isz##_t HELPER(vfp_to##name##p##round)(float##fsz x, \
- uint32_t shift, \
- void *fpstp) \
-{ \
- float_status *fpst = fpstp; \
- int old_exc_flags = get_float_exception_flags(fpst); \
- float##fsz tmp; \
- if (float##fsz##_is_any_nan(x)) { \
- float_raise(float_flag_invalid, fpst); \
- return 0; \
- } \
- tmp = float##fsz##_scalbn(x, shift, fpst); \
- old_exc_flags |= get_float_exception_flags(fpst) \
- & float_flag_input_denormal; \
- set_float_exception_flags(old_exc_flags, fpst); \
- return float##fsz##_to_##itype##round(tmp, fpst); \
+#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, ROUND, suff) \
+uint##isz##_t HELPER(vfp_to##name##p##suff)(float##fsz x, uint32_t shift, \
+ void *fpst) \
+{ \
+ if (unlikely(float##fsz##_is_any_nan(x))) { \
+ float_raise(float_flag_invalid, fpst); \
+ return 0; \
+ } \
+ return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \
}
#define VFP_CONV_FIX(name, p, fsz, isz, itype) \
VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, _round_to_zero) \
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, )
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
+ float_round_to_zero, _round_to_zero) \
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
+ get_float_rounding_mode(fpst), )
#define VFP_CONV_FIX_A64(name, p, fsz, isz, itype) \
VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, )
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
+ get_float_rounding_mode(fpst), )
VFP_CONV_FIX(sh, d, 64, 64, int16)
VFP_CONV_FIX(sl, d, 64, 64, int32)
@@ -11622,87 +11765,84 @@ VFP_CONV_FIX_A64(uq, s, 32, 64, uint64)
#undef VFP_CONV_FLOAT_FIX_ROUND
#undef VFP_CONV_FIX_A64
-/* Conversion to/from f16 can overflow to infinity before/after scaling.
- * Therefore we convert to f64, scale, and then convert f64 to f16; or
- * vice versa for conversion to integer.
- *
- * For 16- and 32-bit integers, the conversion to f64 never rounds.
- * For 64-bit integers, any integer that would cause rounding will also
- * overflow to f16 infinity, so there is no double rounding problem.
- */
-
-static float16 do_postscale_fp16(float64 f, int shift, float_status *fpst)
-{
- return float64_to_float16(float64_scalbn(f, -shift, fpst), true, fpst);
-}
-
uint32_t HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst)
{
- return do_postscale_fp16(int32_to_float64(x, fpst), shift, fpst);
+ return int32_to_float16_scalbn(x, -shift, fpst);
}
uint32_t HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst)
{
- return do_postscale_fp16(uint32_to_float64(x, fpst), shift, fpst);
+ return uint32_to_float16_scalbn(x, -shift, fpst);
}
uint32_t HELPER(vfp_sqtoh)(uint64_t x, uint32_t shift, void *fpst)
{
- return do_postscale_fp16(int64_to_float64(x, fpst), shift, fpst);
+ return int64_to_float16_scalbn(x, -shift, fpst);
}
uint32_t HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst)
{
- return do_postscale_fp16(uint64_to_float64(x, fpst), shift, fpst);
+ return uint64_to_float16_scalbn(x, -shift, fpst);
}
-static float64 do_prescale_fp16(float16 f, int shift, float_status *fpst)
+uint32_t HELPER(vfp_toshh)(uint32_t x, uint32_t shift, void *fpst)
{
- if (unlikely(float16_is_any_nan(f))) {
+ if (unlikely(float16_is_any_nan(x))) {
float_raise(float_flag_invalid, fpst);
return 0;
- } else {
- int old_exc_flags = get_float_exception_flags(fpst);
- float64 ret;
-
- ret = float16_to_float64(f, true, fpst);
- ret = float64_scalbn(ret, shift, fpst);
- old_exc_flags |= get_float_exception_flags(fpst)
- & float_flag_input_denormal;
- set_float_exception_flags(old_exc_flags, fpst);
-
- return ret;
}
-}
-
-uint32_t HELPER(vfp_toshh)(uint32_t x, uint32_t shift, void *fpst)
-{
- return float64_to_int16(do_prescale_fp16(x, shift, fpst), fpst);
+ return float16_to_int16_scalbn(x, get_float_rounding_mode(fpst),
+ shift, fpst);
}
uint32_t HELPER(vfp_touhh)(uint32_t x, uint32_t shift, void *fpst)
{
- return float64_to_uint16(do_prescale_fp16(x, shift, fpst), fpst);
+ if (unlikely(float16_is_any_nan(x))) {
+ float_raise(float_flag_invalid, fpst);
+ return 0;
+ }
+ return float16_to_uint16_scalbn(x, get_float_rounding_mode(fpst),
+ shift, fpst);
}
uint32_t HELPER(vfp_toslh)(uint32_t x, uint32_t shift, void *fpst)
{
- return float64_to_int32(do_prescale_fp16(x, shift, fpst), fpst);
+ if (unlikely(float16_is_any_nan(x))) {
+ float_raise(float_flag_invalid, fpst);
+ return 0;
+ }
+ return float16_to_int32_scalbn(x, get_float_rounding_mode(fpst),
+ shift, fpst);
}
uint32_t HELPER(vfp_toulh)(uint32_t x, uint32_t shift, void *fpst)
{
- return float64_to_uint32(do_prescale_fp16(x, shift, fpst), fpst);
+ if (unlikely(float16_is_any_nan(x))) {
+ float_raise(float_flag_invalid, fpst);
+ return 0;
+ }
+ return float16_to_uint32_scalbn(x, get_float_rounding_mode(fpst),
+ shift, fpst);
}
uint64_t HELPER(vfp_tosqh)(uint32_t x, uint32_t shift, void *fpst)
{
- return float64_to_int64(do_prescale_fp16(x, shift, fpst), fpst);
+ if (unlikely(float16_is_any_nan(x))) {
+ float_raise(float_flag_invalid, fpst);
+ return 0;
+ }
+ return float16_to_int64_scalbn(x, get_float_rounding_mode(fpst),
+ shift, fpst);
}
uint64_t HELPER(vfp_touqh)(uint32_t x, uint32_t shift, void *fpst)
{
- return float64_to_uint64(do_prescale_fp16(x, shift, fpst), fpst);
+ if (unlikely(float16_is_any_nan(x))) {
+ float_raise(float_flag_invalid, fpst);
+ return 0;
+ }
+ return float16_to_uint64_scalbn(x, get_float_rounding_mode(fpst),
+ shift, fpst);
}
/* Set the current fp rounding mode and return the old one.
@@ -12331,6 +12471,7 @@ int arm_rmode_to_sf(int rmode)
/* FIXME: add support for TIEAWAY and ODD */
qemu_log_mask(LOG_UNIMP, "arm: unimplemented rounding mode: %d\n",
rmode);
+ /* fall through for now */
case FPROUNDING_TIEEVEN:
default:
rmode = float_round_nearest_even;
diff --git a/target/arm/iwmmxt_helper.c b/target/arm/iwmmxt_helper.c
index f6a4fc5b7f..24244d012c 100644
--- a/target/arm/iwmmxt_helper.c
+++ b/target/arm/iwmmxt_helper.c
@@ -27,30 +27,30 @@
/* iwMMXt macros extracted from GNU gdb. */
/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */
-#define SIMD8_SET( v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n)))
-#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n)))
-#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n)))
-#define SIMD64_SET(v, n) ((v != 0) << (32 + (n)))
+#define SIMD8_SET(v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n)))
+#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n)))
+#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n)))
+#define SIMD64_SET(v, n) ((v != 0) << (32 + (n)))
/* Flags to pass as "n" above. */
-#define SIMD_NBIT -1
-#define SIMD_ZBIT -2
-#define SIMD_CBIT -3
-#define SIMD_VBIT -4
+#define SIMD_NBIT -1
+#define SIMD_ZBIT -2
+#define SIMD_CBIT -3
+#define SIMD_VBIT -4
/* Various status bit macros. */
-#define NBIT8(x) ((x) & 0x80)
-#define NBIT16(x) ((x) & 0x8000)
-#define NBIT32(x) ((x) & 0x80000000)
-#define NBIT64(x) ((x) & 0x8000000000000000ULL)
-#define ZBIT8(x) (((x) & 0xff) == 0)
-#define ZBIT16(x) (((x) & 0xffff) == 0)
-#define ZBIT32(x) (((x) & 0xffffffff) == 0)
-#define ZBIT64(x) (x == 0)
+#define NBIT8(x) ((x) & 0x80)
+#define NBIT16(x) ((x) & 0x8000)
+#define NBIT32(x) ((x) & 0x80000000)
+#define NBIT64(x) ((x) & 0x8000000000000000ULL)
+#define ZBIT8(x) (((x) & 0xff) == 0)
+#define ZBIT16(x) (((x) & 0xffff) == 0)
+#define ZBIT32(x) (((x) & 0xffffffff) == 0)
+#define ZBIT64(x) (x == 0)
/* Sign extension macros. */
-#define EXTEND8H(a) ((uint16_t) (int8_t) (a))
-#define EXTEND8(a) ((uint32_t) (int8_t) (a))
-#define EXTEND16(a) ((uint32_t) (int16_t) (a))
-#define EXTEND16S(a) ((int32_t) (int16_t) (a))
-#define EXTEND32(a) ((uint64_t) (int32_t) (a))
+#define EXTEND8H(a) ((uint16_t) (int8_t) (a))
+#define EXTEND8(a) ((uint32_t) (int8_t) (a))
+#define EXTEND16(a) ((uint32_t) (int16_t) (a))
+#define EXTEND16S(a) ((int32_t) (int16_t) (a))
+#define EXTEND32(a) ((uint64_t) (int32_t) (a))
uint64_t HELPER(iwmmxt_maddsq)(uint64_t a, uint64_t b)
{
@@ -159,141 +159,141 @@ uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b)
#define NZBIT64(x) \
SIMD64_SET(NBIT64(x), SIMD_NBIT) | \
SIMD64_SET(ZBIT64(x), SIMD_ZBIT)
-#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \
+#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
-{ \
- a = \
- (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) | \
- (((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) | \
- (((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) | \
- (((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \
- NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \
- NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \
- NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \
+{ \
+ a = \
+ (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) | \
+ (((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) | \
+ (((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) | \
+ (((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \
+ NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \
+ NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \
+ NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \
return a; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
-{ \
- a = \
- (((a >> SH0) & 0xffff) << 0) | \
- (((b >> SH0) & 0xffff) << 16) | \
- (((a >> SH2) & 0xffff) << 32) | \
- (((b >> SH2) & 0xffff) << 48); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) | \
- NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3); \
+{ \
+ a = \
+ (((a >> SH0) & 0xffff) << 0) | \
+ (((b >> SH0) & 0xffff) << 16) | \
+ (((a >> SH2) & 0xffff) << 32) | \
+ (((b >> SH2) & 0xffff) << 48); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) | \
+ NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3); \
return a; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
-{ \
- a = \
- (((a >> SH0) & 0xffffffff) << 0) | \
- (((b >> SH0) & 0xffffffff) << 32); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \
+{ \
+ a = \
+ (((a >> SH0) & 0xffffffff) << 0) | \
+ (((b >> SH0) & 0xffffffff) << 32); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \
return a; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUARMState *env, \
uint64_t x) \
-{ \
- x = \
- (((x >> SH0) & 0xff) << 0) | \
- (((x >> SH1) & 0xff) << 16) | \
- (((x >> SH2) & 0xff) << 32) | \
- (((x >> SH3) & 0xff) << 48); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \
- NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \
+{ \
+ x = \
+ (((x >> SH0) & 0xff) << 0) | \
+ (((x >> SH1) & 0xff) << 16) | \
+ (((x >> SH2) & 0xff) << 32) | \
+ (((x >> SH3) & 0xff) << 48); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \
+ NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \
return x; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUARMState *env, \
uint64_t x) \
-{ \
- x = \
- (((x >> SH0) & 0xffff) << 0) | \
- (((x >> SH2) & 0xffff) << 32); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \
+{ \
+ x = \
+ (((x >> SH0) & 0xffff) << 0) | \
+ (((x >> SH2) & 0xffff) << 32); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \
return x; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUARMState *env, \
uint64_t x) \
-{ \
- x = (((x >> SH0) & 0xffffffff) << 0); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \
+{ \
+ x = (((x >> SH0) & 0xffffffff) << 0); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \
return x; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUARMState *env, \
uint64_t x) \
-{ \
- x = \
- ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) | \
- ((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) | \
- ((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) | \
- ((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \
- NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \
+{ \
+ x = \
+ ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) | \
+ ((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) | \
+ ((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) | \
+ ((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \
+ NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \
return x; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUARMState *env, \
uint64_t x) \
-{ \
- x = \
- ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) | \
- ((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \
+{ \
+ x = \
+ ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) | \
+ ((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \
return x; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUARMState *env, \
uint64_t x) \
-{ \
- x = EXTEND32((x >> SH0) & 0xffffffff); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \
+{ \
+ x = EXTEND32((x >> SH0) & 0xffffffff); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \
return x; \
}
IWMMXT_OP_UNPACK(l, 0, 8, 16, 24)
IWMMXT_OP_UNPACK(h, 32, 40, 48, 56)
-#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \
+#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
-{ \
- a = \
- CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \
- CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \
- CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \
- CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \
- NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \
- NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \
- NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \
+{ \
+ a = \
+ CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \
+ CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \
+ CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \
+ CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \
+ NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \
+ NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \
+ NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \
return a; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
-{ \
- a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \
- CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | \
- NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); \
+{ \
+ a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \
+ CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | \
+ NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); \
return a; \
-} \
+} \
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUARMState *env, \
uint64_t a, uint64_t b) \
-{ \
- a = CMP(0, Tl, O, 0xffffffff) | \
- CMP(32, Tl, O, 0xffffffff); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \
+{ \
+ a = CMP(0, Tl, O, 0xffffffff) | \
+ CMP(32, Tl, O, 0xffffffff); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \
return a; \
}
#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \
diff --git a/target/arm/translate.c b/target/arm/translate.c
index bcfc29c5a6..c6a5d2ac44 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -1627,7 +1627,7 @@ static inline void gen_mov_vreg_F0(int dp, int reg)
tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
}
-#define ARM_CP_RW_BIT (1 << 20)
+#define ARM_CP_RW_BIT (1 << 20)
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
{
@@ -1861,12 +1861,12 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
wrd = insn & 0xf;
rdlo = (insn >> 12) & 0xf;
rdhi = (insn >> 16) & 0xf;
- if (insn & ARM_CP_RW_BIT) { /* TMRRC */
+ if (insn & ARM_CP_RW_BIT) { /* TMRRC */
iwmmxt_load_reg(cpu_V0, wrd);
tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
tcg_gen_extrl_i64_i32(cpu_R[rdhi], cpu_V0);
- } else { /* TMCRR */
+ } else { /* TMCRR */
tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
iwmmxt_store_reg(cpu_V0, wrd);
gen_op_iwmmxt_set_mup();
@@ -1881,25 +1881,25 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
return 1;
}
if (insn & ARM_CP_RW_BIT) {
- if ((insn >> 28) == 0xf) { /* WLDRW wCx */
+ if ((insn >> 28) == 0xf) { /* WLDRW wCx */
tmp = tcg_temp_new_i32();
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
iwmmxt_store_creg(wrd, tmp);
} else {
i = 1;
if (insn & (1 << 8)) {
- if (insn & (1 << 22)) { /* WLDRD */
+ if (insn & (1 << 22)) { /* WLDRD */
gen_aa32_ld64(s, cpu_M0, addr, get_mem_index(s));
i = 0;
- } else { /* WLDRW wRd */
+ } else { /* WLDRW wRd */
tmp = tcg_temp_new_i32();
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
}
} else {
tmp = tcg_temp_new_i32();
- if (insn & (1 << 22)) { /* WLDRH */
+ if (insn & (1 << 22)) { /* WLDRH */
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
- } else { /* WLDRB */
+ } else { /* WLDRB */
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
}
}
@@ -1910,24 +1910,24 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
}
} else {
- if ((insn >> 28) == 0xf) { /* WSTRW wCx */
+ if ((insn >> 28) == 0xf) { /* WSTRW wCx */
tmp = iwmmxt_load_creg(wrd);
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
} else {
gen_op_iwmmxt_movq_M0_wRn(wrd);
tmp = tcg_temp_new_i32();
if (insn & (1 << 8)) {
- if (insn & (1 << 22)) { /* WSTRD */
+ if (insn & (1 << 22)) { /* WSTRD */
gen_aa32_st64(s, cpu_M0, addr, get_mem_index(s));
- } else { /* WSTRW wRd */
+ } else { /* WSTRW wRd */
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
}
} else {
- if (insn & (1 << 22)) { /* WSTRH */
+ if (insn & (1 << 22)) { /* WSTRH */
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
- } else { /* WSTRB */
+ } else { /* WSTRB */
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
}
@@ -1943,7 +1943,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
return 1;
switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
- case 0x000: /* WOR */
+ case 0x000: /* WOR */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 0) & 0xf;
rd1 = (insn >> 16) & 0xf;
@@ -1954,7 +1954,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x011: /* TMCR */
+ case 0x011: /* TMCR */
if (insn & 0xf)
return 1;
rd = (insn >> 12) & 0xf;
@@ -1985,7 +1985,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
return 1;
}
break;
- case 0x100: /* WXOR */
+ case 0x100: /* WXOR */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 0) & 0xf;
rd1 = (insn >> 16) & 0xf;
@@ -1996,7 +1996,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x111: /* TMRC */
+ case 0x111: /* TMRC */
if (insn & 0xf)
return 1;
rd = (insn >> 12) & 0xf;
@@ -2004,7 +2004,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
tmp = iwmmxt_load_creg(wrd);
store_reg(s, rd, tmp);
break;
- case 0x300: /* WANDN */
+ case 0x300: /* WANDN */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 0) & 0xf;
rd1 = (insn >> 16) & 0xf;
@@ -2016,7 +2016,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x200: /* WAND */
+ case 0x200: /* WAND */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 0) & 0xf;
rd1 = (insn >> 16) & 0xf;
@@ -2027,7 +2027,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x810: case 0xa10: /* WMADD */
+ case 0x810: case 0xa10: /* WMADD */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 0) & 0xf;
rd1 = (insn >> 16) & 0xf;
@@ -2039,7 +2039,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */
+ case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
rd1 = (insn >> 0) & 0xf;
@@ -2061,7 +2061,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */
+ case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
rd1 = (insn >> 0) & 0xf;
@@ -2083,7 +2083,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */
+ case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
rd1 = (insn >> 0) & 0xf;
@@ -2097,7 +2097,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */
+ case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
rd1 = (insn >> 0) & 0xf;
@@ -2116,7 +2116,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */
+ case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
rd1 = (insn >> 0) & 0xf;
@@ -2132,7 +2132,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */
+ case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
rd1 = (insn >> 0) & 0xf;
@@ -2154,7 +2154,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */
+ case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
rd1 = (insn >> 0) & 0xf;
@@ -2174,7 +2174,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */
+ case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
rd1 = (insn >> 0) & 0xf;
@@ -2187,7 +2187,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */
+ case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */
if (((insn >> 6) & 3) == 3)
return 1;
rd = (insn >> 12) & 0xf;
@@ -2218,7 +2218,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */
+ case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */
rd = (insn >> 12) & 0xf;
wrd = (insn >> 16) & 0xf;
if (rd == 15 || ((insn >> 22) & 3) == 3)
@@ -2251,7 +2251,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
}
store_reg(s, rd, tmp);
break;
- case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
+ case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
return 1;
tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
@@ -2270,7 +2270,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_set_nzcv(tmp);
tcg_temp_free_i32(tmp);
break;
- case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */
+ case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */
if (((insn >> 6) & 3) == 3)
return 1;
rd = (insn >> 12) & 0xf;
@@ -2291,7 +2291,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */
+ case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */
if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
return 1;
tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
@@ -2319,7 +2319,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp);
break;
- case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */
+ case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
gen_op_iwmmxt_movq_M0_wRn(rd0);
@@ -2339,7 +2339,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */
+ case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */
if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
return 1;
tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
@@ -2367,7 +2367,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp);
break;
- case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */
+ case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */
rd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
@@ -2387,7 +2387,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
}
store_reg(s, rd, tmp);
break;
- case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */
+ case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */
case 0x906: case 0xb06: case 0xd06: case 0xf06:
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
@@ -2419,7 +2419,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */
+ case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */
case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
@@ -2450,7 +2450,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */
+ case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */
case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
@@ -2481,7 +2481,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */
+ case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */
case 0x214: case 0x614: case 0xa14: case 0xe14:
if (((insn >> 22) & 3) == 0)
return 1;
@@ -2509,7 +2509,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */
+ case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */
case 0x014: case 0x414: case 0x814: case 0xc14:
if (((insn >> 22) & 3) == 0)
return 1;
@@ -2537,7 +2537,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */
+ case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */
case 0x114: case 0x514: case 0x914: case 0xd14:
if (((insn >> 22) & 3) == 0)
return 1;
@@ -2565,7 +2565,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */
+ case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */
case 0x314: case 0x714: case 0xb14: case 0xf14:
if (((insn >> 22) & 3) == 0)
return 1;
@@ -2601,7 +2601,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */
+ case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */
case 0x916: case 0xb16: case 0xd16: case 0xf16:
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
@@ -2632,7 +2632,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */
+ case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */
case 0x816: case 0xa16: case 0xc16: case 0xe16:
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
@@ -2663,7 +2663,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */
+ case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */
case 0x402: case 0x502: case 0x602: case 0x702:
wrd = (insn >> 12) & 0xf;
rd0 = (insn >> 16) & 0xf;
@@ -2676,7 +2676,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_movq_wRn_M0(wrd);
gen_op_iwmmxt_set_mup();
break;
- case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */
+ case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */
case 0x41a: case 0x51a: case 0x61a: case 0x71a:
case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
@@ -2719,7 +2719,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */
+ case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */
case 0x41e: case 0x51e: case 0x61e: case 0x71e:
case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
@@ -2733,7 +2733,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */
+ case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */
case 0x418: case 0x518: case 0x618: case 0x718:
case 0x818: case 0x918: case 0xa18: case 0xb18:
case 0xc18: case 0xd18: case 0xe18: case 0xf18:
@@ -2776,7 +2776,7 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
gen_op_iwmmxt_set_mup();
gen_op_iwmmxt_set_cup();
break;
- case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */
+ case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */
case 0x408: case 0x508: case 0x608: case 0x708:
case 0x808: case 0x908: case 0xa08: case 0xb08:
case 0xc08: case 0xd08: case 0xe08: case 0xf08:
@@ -2823,13 +2823,13 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
tmp = load_reg(s, rd0);
tmp2 = load_reg(s, rd1);
switch ((insn >> 16) & 0xf) {
- case 0x0: /* TMIA */
+ case 0x0: /* TMIA */
gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
break;
- case 0x8: /* TMIAPH */
+ case 0x8: /* TMIAPH */
gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
break;
- case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
+ case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
if (insn & (1 << 16))
tcg_gen_shri_i32(tmp, tmp, 16);
if (insn & (1 << 17))
@@ -2872,16 +2872,16 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn)
tmp = load_reg(s, rd0);
tmp2 = load_reg(s, rd1);
switch ((insn >> 16) & 0xf) {
- case 0x0: /* MIA */
+ case 0x0: /* MIA */
gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
break;
- case 0x8: /* MIAPH */
+ case 0x8: /* MIAPH */
gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
break;
- case 0xc: /* MIABB */
- case 0xd: /* MIABT */
- case 0xe: /* MIATB */
- case 0xf: /* MIATT */
+ case 0xc: /* MIABB */
+ case 0xd: /* MIABT */
+ case 0xe: /* MIATB */
+ case 0xf: /* MIATT */
if (insn & (1 << 16))
tcg_gen_shri_i32(tmp, tmp, 16);
if (insn & (1 << 17))
@@ -2907,13 +2907,13 @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn)
if (acc != 0)
return 1;
- if (insn & ARM_CP_RW_BIT) { /* MRA */
+ if (insn & ARM_CP_RW_BIT) { /* MRA */
iwmmxt_load_reg(cpu_V0, acc);
tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
tcg_gen_extrl_i64_i32(cpu_R[rdhi], cpu_V0);
tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
- } else { /* MAR */
+ } else { /* MAR */
tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
iwmmxt_store_reg(cpu_V0, acc);
}
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 4e4fe8fa8b..f24295e6e4 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -3880,6 +3880,9 @@ arch_query_cpu_model_expansion(CpuModelExpansionType type,
}
props = qdict_new();
+ ret->model = g_new0(CpuModelInfo, 1);
+ ret->model->props = QOBJECT(props);
+ ret->model->has_props = true;
switch (type) {
case CPU_MODEL_EXPANSION_TYPE_STATIC:
@@ -3900,15 +3903,9 @@ arch_query_cpu_model_expansion(CpuModelExpansionType type,
goto out;
}
- if (!props) {
- props = qdict_new();
- }
x86_cpu_to_dict(xc, props);
- ret->model = g_new0(CpuModelInfo, 1);
ret->model->name = g_strdup(base_name);
- ret->model->props = QOBJECT(props);
- ret->model->has_props = true;
out:
object_unref(OBJECT(xc));
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 9cad5812cd..b572a8e4aa 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1515,6 +1515,8 @@ int cpu_x86_support_mca_broadcast(CPUX86State *env);
int cpu_get_pic_interrupt(CPUX86State *s);
/* MSDOS compatibility mode FPU exception support */
void cpu_set_ferr(CPUX86State *s);
+/* mpx_helper.c */
+void cpu_sync_bndcs_hflags(CPUX86State *env);
/* this function must always be used to load data in the segment
cache: it synchronizes the hflags with the segment cache values */
@@ -1557,6 +1559,8 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env,
#error HF_CPL_MASK is hardcoded
#endif
env->hflags = (env->hflags & ~HF_CPL_MASK) | cpl;
+ /* Possibly switch between BNDCFGS and BNDCFGU */
+ cpu_sync_bndcs_hflags(env);
}
new_hflags = (env->segs[R_SS].flags & DESC_B_MASK)
>> (DESC_B_SHIFT - HF_SS32_SHIFT);
@@ -1889,9 +1893,6 @@ void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
*/
void x86_cpu_change_kvm_default(const char *prop, const char *value);
-/* mpx_helper.c */
-void cpu_sync_bndcs_hflags(CPUX86State *env);
-
/* Return name of 32-bit register, from a R_* constant */
const char *get_register_name_32(unsigned int reg);
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 9313602d3d..0b2a07d3a4 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -1381,17 +1381,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
int ret;
struct utsname utsname;
-#ifdef KVM_CAP_XSAVE
has_xsave = kvm_check_extension(s, KVM_CAP_XSAVE);
-#endif
-
-#ifdef KVM_CAP_XCRS
has_xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
-#endif
-
-#ifdef KVM_CAP_PIT_STATE2
has_pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
-#endif
hv_vpindex_settable = kvm_check_extension(s, KVM_CAP_HYPERV_VP_INDEX);
diff --git a/target/i386/seg_helper.c b/target/i386/seg_helper.c
index 00301a0c04..d1cbc6ebf0 100644
--- a/target/i386/seg_helper.c
+++ b/target/i386/seg_helper.c
@@ -518,6 +518,11 @@ static void switch_tss(CPUX86State *env, int tss_selector,
static inline unsigned int get_sp_mask(unsigned int e2)
{
+#ifdef TARGET_X86_64
+ if (e2 & DESC_L_MASK) {
+ return 0;
+ } else
+#endif
if (e2 & DESC_B_MASK) {
return 0xffffffff;
} else {
@@ -1628,8 +1633,8 @@ void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
}
limit = get_seg_limit(e1, e2);
if (new_eip > limit &&
- !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK)) {
- raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
+ (!(env->hflags & HF_LMA_MASK) || !(e2 & DESC_L_MASK))) {
+ raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
}
cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
get_seg_base(e1, e2), limit, e2);
@@ -1640,6 +1645,14 @@ void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
rpl = new_cs & 3;
cpl = env->hflags & HF_CPL_MASK;
type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+
+#ifdef TARGET_X86_64
+ if (env->efer & MSR_EFER_LMA) {
+ if (type != 12) {
+ raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
+ }
+ }
+#endif
switch (type) {
case 1: /* 286 TSS */
case 9: /* 386 TSS */
@@ -1662,6 +1675,23 @@ void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
if (type == 12) {
new_eip |= (e2 & 0xffff0000);
}
+
+#ifdef TARGET_X86_64
+ if (env->efer & MSR_EFER_LMA) {
+ /* load the upper 8 bytes of the 64-bit call gate */
+ if (load_segment_ra(env, &e1, &e2, new_cs + 8, GETPC())) {
+ raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc,
+ GETPC());
+ }
+ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+ if (type != 0) {
+ raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc,
+ GETPC());
+ }
+ new_eip |= ((target_ulong)e1) << 32;
+ }
+#endif
+
if (load_segment_ra(env, &e1, &e2, gate_cs, GETPC()) != 0) {
raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
}
@@ -1675,11 +1705,22 @@ void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
(!(e2 & DESC_C_MASK) && (dpl != cpl))) {
raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
}
+#ifdef TARGET_X86_64
+ if (env->efer & MSR_EFER_LMA) {
+ if (!(e2 & DESC_L_MASK)) {
+ raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
+ }
+ if (e2 & DESC_B_MASK) {
+ raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
+ }
+ }
+#endif
if (!(e2 & DESC_P_MASK)) {
raise_exception_err_ra(env, EXCP0D_GPF, gate_cs & 0xfffc, GETPC());
}
limit = get_seg_limit(e1, e2);
- if (new_eip > limit) {
+ if (new_eip > limit &&
+ (!(env->hflags & HF_LMA_MASK) || !(e2 & DESC_L_MASK))) {
raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
}
cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
@@ -1724,12 +1765,12 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
int shift, target_ulong next_eip)
{
int new_stack, i;
- uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
- uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask;
+ uint32_t e1, e2, cpl, dpl, rpl, selector, param_count;
+ uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, type, ss_dpl, sp_mask;
uint32_t val, limit, old_sp_mask;
- target_ulong ssp, old_ssp;
+ target_ulong ssp, old_ssp, offset, sp;
- LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
+ LOG_PCALL("lcall %04x:" TARGET_FMT_lx " s=%d\n", new_cs, new_eip, shift);
LOG_PCALL_STATE(CPU(x86_env_get_cpu(env)));
if ((new_cs & 0xfffc) == 0) {
raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
@@ -1807,6 +1848,15 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
rpl = new_cs & 3;
+
+#ifdef TARGET_X86_64
+ if (env->efer & MSR_EFER_LMA) {
+ if (type != 12) {
+ raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
+ }
+ }
+#endif
+
switch (type) {
case 1: /* available 286 TSS */
case 9: /* available 386 TSS */
@@ -1833,8 +1883,23 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
raise_exception_err_ra(env, EXCP0B_NOSEG, new_cs & 0xfffc, GETPC());
}
selector = e1 >> 16;
- offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
param_count = e2 & 0x1f;
+ offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+#ifdef TARGET_X86_64
+ if (env->efer & MSR_EFER_LMA) {
+ /* load the upper 8 bytes of the 64-bit call gate */
+ if (load_segment_ra(env, &e1, &e2, new_cs + 8, GETPC())) {
+ raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc,
+ GETPC());
+ }
+ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+ if (type != 0) {
+ raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc,
+ GETPC());
+ }
+ offset |= ((target_ulong)e1) << 32;
+ }
+#endif
if ((selector & 0xfffc) == 0) {
raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
}
@@ -1849,46 +1914,80 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
if (dpl > cpl) {
raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
}
+#ifdef TARGET_X86_64
+ if (env->efer & MSR_EFER_LMA) {
+ if (!(e2 & DESC_L_MASK)) {
+ raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
+ }
+ if (e2 & DESC_B_MASK) {
+ raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC());
+ }
+ shift++;
+ }
+#endif
if (!(e2 & DESC_P_MASK)) {
raise_exception_err_ra(env, EXCP0B_NOSEG, selector & 0xfffc, GETPC());
}
if (!(e2 & DESC_C_MASK) && dpl < cpl) {
/* to inner privilege */
- get_ss_esp_from_tss(env, &ss, &sp, dpl, GETPC());
- LOG_PCALL("new ss:esp=%04x:%08x param_count=%d env->regs[R_ESP]="
- TARGET_FMT_lx "\n", ss, sp, param_count,
- env->regs[R_ESP]);
- if ((ss & 0xfffc) == 0) {
- raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
- }
- if ((ss & 3) != dpl) {
- raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
- }
- if (load_segment_ra(env, &ss_e1, &ss_e2, ss, GETPC()) != 0) {
- raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
- }
- ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
- if (ss_dpl != dpl) {
- raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
- }
- if (!(ss_e2 & DESC_S_MASK) ||
- (ss_e2 & DESC_CS_MASK) ||
- !(ss_e2 & DESC_W_MASK)) {
- raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
- }
- if (!(ss_e2 & DESC_P_MASK)) {
- raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
+#ifdef TARGET_X86_64
+ if (shift == 2) {
+ sp = get_rsp_from_tss(env, dpl);
+ ss = dpl; /* SS = NULL selector with RPL = new CPL */
+ new_stack = 1;
+ sp_mask = 0;
+ ssp = 0; /* SS base is always zero in IA-32e mode */
+ LOG_PCALL("new ss:rsp=%04x:%016llx env->regs[R_ESP]="
+ TARGET_FMT_lx "\n", ss, sp, env->regs[R_ESP]);
+ } else
+#endif
+ {
+ uint32_t sp32;
+ get_ss_esp_from_tss(env, &ss, &sp32, dpl, GETPC());
+ LOG_PCALL("new ss:esp=%04x:%08x param_count=%d env->regs[R_ESP]="
+ TARGET_FMT_lx "\n", ss, sp32, param_count,
+ env->regs[R_ESP]);
+ sp = sp32;
+ if ((ss & 0xfffc) == 0) {
+ raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
+ }
+ if ((ss & 3) != dpl) {
+ raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
+ }
+ if (load_segment_ra(env, &ss_e1, &ss_e2, ss, GETPC()) != 0) {
+ raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
+ }
+ ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+ if (ss_dpl != dpl) {
+ raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
+ }
+ if (!(ss_e2 & DESC_S_MASK) ||
+ (ss_e2 & DESC_CS_MASK) ||
+ !(ss_e2 & DESC_W_MASK)) {
+ raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
+ }
+ if (!(ss_e2 & DESC_P_MASK)) {
+ raise_exception_err_ra(env, EXCP0A_TSS, ss & 0xfffc, GETPC());
+ }
+
+ sp_mask = get_sp_mask(ss_e2);
+ ssp = get_seg_base(ss_e1, ss_e2);
}
/* push_size = ((param_count * 2) + 8) << shift; */
old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
old_ssp = env->segs[R_SS].base;
-
- sp_mask = get_sp_mask(ss_e2);
- ssp = get_seg_base(ss_e1, ss_e2);
- if (shift) {
+#ifdef TARGET_X86_64
+ if (shift == 2) {
+ /* XXX: verify if new stack address is canonical */
+ PUSHQ_RA(sp, env->segs[R_SS].selector, GETPC());
+ PUSHQ_RA(sp, env->regs[R_ESP], GETPC());
+ /* parameters aren't supported for 64-bit call gates */
+ } else
+#endif
+ if (shift == 1) {
PUSHL_RA(ssp, sp, sp_mask, env->segs[R_SS].selector, GETPC());
PUSHL_RA(ssp, sp, sp_mask, env->regs[R_ESP], GETPC());
for (i = param_count - 1; i >= 0; i--) {
@@ -1917,7 +2016,13 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
new_stack = 0;
}
- if (shift) {
+#ifdef TARGET_X86_64
+ if (shift == 2) {
+ PUSHQ_RA(sp, env->segs[R_CS].selector, GETPC());
+ PUSHQ_RA(sp, next_eip, GETPC());
+ } else
+#endif
+ if (shift == 1) {
PUSHL_RA(ssp, sp, sp_mask, env->segs[R_CS].selector, GETPC());
PUSHL_RA(ssp, sp, sp_mask, next_eip, GETPC());
} else {
@@ -1928,11 +2033,18 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
/* from this point, not restartable */
if (new_stack) {
- ss = (ss & ~3) | dpl;
- cpu_x86_load_seg_cache(env, R_SS, ss,
- ssp,
- get_seg_limit(ss_e1, ss_e2),
- ss_e2);
+#ifdef TARGET_X86_64
+ if (shift == 2) {
+ cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
+ } else
+#endif
+ {
+ ss = (ss & ~3) | dpl;
+ cpu_x86_load_seg_cache(env, R_SS, ss,
+ ssp,
+ get_seg_limit(ss_e1, ss_e2),
+ ss_e2);
+ }
}
selector = (selector & ~3) | dpl;
diff --git a/target/i386/translate.c b/target/i386/translate.c
index 07d185e7b6..1f9d1d9b24 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -4689,6 +4689,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x82:
if (CODE64(s))
goto illegal_op;
+ /* fall through */
case 0x80: /* GRP1 */
case 0x81:
case 0x83:
@@ -8292,6 +8293,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x10e ... 0x10f:
/* 3DNow! instructions, ignore prefixes */
s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA);
+ /* fall through */
case 0x110 ... 0x117:
case 0x128 ... 0x12f:
case 0x138 ... 0x13a:
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 12e765ba1f..265d25c937 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -1096,7 +1096,7 @@ void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga,
const S390CPUDef *def = s390_find_cpu_def(type, gen, ec_ga, NULL);
g_assert(def);
- g_assert(QTAILQ_EMPTY(&cpus));
+ g_assert(QTAILQ_EMPTY_RCU(&cpus));
/* TCG emulates some features that can usually not be enabled with
* the emulated machine generation. Make sure they can be enabled
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 760a0f18b6..575a66f8b6 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -116,6 +116,10 @@ check-unit-y += tests/rcutorture$(EXESUF)
gcov-files-rcutorture-y = util/rcu.c
check-unit-y += tests/test-rcu-list$(EXESUF)
gcov-files-test-rcu-list-y = util/rcu.c
+check-unit-y += tests/test-rcu-simpleq$(EXESUF)
+gcov-files-test-rcu-simpleq-y = util/rcu.c
+check-unit-y += tests/test-rcu-tailq$(EXESUF)
+gcov-files-test-rcu-tailq-y = util/rcu.c
check-unit-y += tests/test-qdist$(EXESUF)
gcov-files-test-qdist-y = util/qdist.c
check-unit-y += tests/test-qht$(EXESUF)
@@ -124,7 +128,7 @@ check-unit-y += tests/test-qht-par$(EXESUF)
gcov-files-test-qht-par-y = util/qht.c
check-unit-y += tests/test-bitops$(EXESUF)
check-unit-y += tests/test-bitcnt$(EXESUF)
-check-unit-$(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) += tests/test-qdev-global-props$(EXESUF)
+check-unit-y += tests/test-qdev-global-props$(EXESUF)
check-unit-y += tests/check-qom-interface$(EXESUF)
gcov-files-check-qom-interface-y = qom/object.c
check-unit-y += tests/check-qom-proplist$(EXESUF)
@@ -215,27 +219,27 @@ check-qtest-pci-y += tests/e1000-test$(EXESUF)
gcov-files-pci-y += hw/net/e1000.c
check-qtest-pci-y += tests/e1000e-test$(EXESUF)
gcov-files-pci-y += hw/net/e1000e.c hw/net/e1000e_core.c
-check-qtest-pci-y += tests/rtl8139-test$(EXESUF)
-gcov-files-pci-y += hw/net/rtl8139.c
-check-qtest-pci-y += tests/pcnet-test$(EXESUF)
-gcov-files-pci-y += hw/net/pcnet.c
-gcov-files-pci-y += hw/net/pcnet-pci.c
-check-qtest-pci-y += tests/eepro100-test$(EXESUF)
-gcov-files-pci-y += hw/net/eepro100.c
-check-qtest-pci-y += tests/ne2000-test$(EXESUF)
-gcov-files-pci-y += hw/net/ne2000.c
-check-qtest-pci-y += tests/nvme-test$(EXESUF)
-gcov-files-pci-y += hw/block/nvme.c
-check-qtest-pci-y += tests/ac97-test$(EXESUF)
-gcov-files-pci-y += hw/audio/ac97.c
-check-qtest-pci-y += tests/es1370-test$(EXESUF)
-gcov-files-pci-y += hw/audio/es1370.c
+check-qtest-pci-$(CONFIG_RTL8139_PCI) += tests/rtl8139-test$(EXESUF)
+gcov-files-pci-$(CONFIG_RTL8139_PCI) += hw/net/rtl8139.c
+check-qtest-pci-$(CONFIG_PCNET_PCI) += tests/pcnet-test$(EXESUF)
+gcov-files-pci-$(CONFIG_PCNET_PCI) += hw/net/pcnet.c
+gcov-files-pci-$(CONFIG_PCNET_PCI) += hw/net/pcnet-pci.c
+check-qtest-pci-$(CONFIG_EEPRO100_PCI) += tests/eepro100-test$(EXESUF)
+gcov-files-pci-$(CONFIG_EEPRO100_PCI) += hw/net/eepro100.c
+check-qtest-pci-$(CONFIG_NE2000_PCI) += tests/ne2000-test$(EXESUF)
+gcov-files-pci-$(CONFIG_NE2000_PCI) += hw/net/ne2000.c
+check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF)
+gcov-files-pci-$(CONFIG_NVME_PCI) += hw/block/nvme.c
+check-qtest-pci-$(CONFIG_AC97) += tests/ac97-test$(EXESUF)
+gcov-files-pci-$(CONFIG_AC97) += hw/audio/ac97.c
+check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
+gcov-files-pci-$(CONFIG_ES1370) += hw/audio/es1370.c
check-qtest-pci-y += $(check-qtest-virtio-y)
gcov-files-pci-y += $(gcov-files-virtio-y) hw/virtio/virtio-pci.c
-check-qtest-pci-y += tests/tpci200-test$(EXESUF)
-gcov-files-pci-y += hw/ipack/tpci200.c
-check-qtest-pci-y += $(check-qtest-ipack-y)
-gcov-files-pci-y += $(gcov-files-ipack-y)
+check-qtest-pci-$(CONFIG_IPACK) += tests/tpci200-test$(EXESUF)
+gcov-files-pci-$(CONFIG_IPACK) += hw/ipack/tpci200.c
+check-qtest-pci-$(CONFIG_IPACK) += $(check-qtest-ipack-y)
+gcov-files-pci-$(CONFIG_IPACK) += $(gcov-files-ipack-y)
check-qtest-pci-y += tests/display-vga-test$(EXESUF)
gcov-files-pci-y += hw/display/vga.c
gcov-files-pci-y += hw/display/cirrus_vga.c
@@ -243,8 +247,8 @@ gcov-files-pci-y += hw/display/vga-pci.c
gcov-files-pci-y += hw/display/virtio-gpu.c
gcov-files-pci-y += hw/display/virtio-gpu-pci.c
gcov-files-pci-$(CONFIG_VIRTIO_VGA) += hw/display/virtio-vga.c
-check-qtest-pci-y += tests/intel-hda-test$(EXESUF)
-gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c
+check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
+gcov-files-pci-$(CONFIG_HDA) += hw/audio/intel-hda.c hw/audio/hda-codec.c
check-qtest-pci-$(CONFIG_IVSHMEM) += tests/ivshmem-test$(EXESUF)
gcov-files-pci-y += hw/misc/ivshmem.c
check-qtest-pci-y += tests/megasas-test$(EXESUF)
@@ -267,27 +271,29 @@ check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF)
check-qtest-i386-y += tests/i440fx-test$(EXESUF)
check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
check-qtest-i386-y += tests/drive_del-test$(EXESUF)
-check-qtest-i386-y += tests/wdt_ib700-test$(EXESUF)
+check-qtest-i386-$(CONFIG_WDT_IB700) += tests/wdt_ib700-test$(EXESUF)
+gcov-files-i386-$(CONFIG_WDT_IB700) += hw/watchdog/watchdog.c hw/watchdog/wdt_ib700.c
check-qtest-i386-y += tests/tco-test$(EXESUF)
-gcov-files-i386-y += hw/watchdog/watchdog.c hw/watchdog/wdt_ib700.c
check-qtest-i386-y += $(check-qtest-pci-y)
gcov-files-i386-y += $(gcov-files-pci-y)
-check-qtest-i386-y += tests/vmxnet3-test$(EXESUF)
-gcov-files-i386-y += hw/net/vmxnet3.c
+check-qtest-i386-$(CONFIG_VMXNET3_PCI) += tests/vmxnet3-test$(EXESUF)
+gcov-files-i386-$(CONFIG_VMXNET3_PCI) += hw/net/vmxnet3.c
gcov-files-i386-y += hw/net/net_rx_pkt.c
gcov-files-i386-y += hw/net/net_tx_pkt.c
-check-qtest-i386-y += tests/pvpanic-test$(EXESUF)
-gcov-files-i386-y += i386-softmmu/hw/misc/pvpanic.c
-check-qtest-i386-y += tests/i82801b11-test$(EXESUF)
-gcov-files-i386-y += hw/pci-bridge/i82801b11.c
-check-qtest-i386-y += tests/ioh3420-test$(EXESUF)
-gcov-files-i386-y += hw/pci-bridge/ioh3420.c
-check-qtest-i386-y += tests/usb-hcd-ohci-test$(EXESUF)
-gcov-files-i386-y += hw/usb/hcd-ohci.c
-check-qtest-i386-y += tests/usb-hcd-uhci-test$(EXESUF)
-gcov-files-i386-y += hw/usb/hcd-uhci.c
+check-qtest-i386-$(CONFIG_PVPANIC) += tests/pvpanic-test$(EXESUF)
+gcov-files-i386-$(CONFIG_PVPANIC) += i386-softmmu/hw/misc/pvpanic.c
+check-qtest-i386-$(CONFIG_I82801B11) += tests/i82801b11-test$(EXESUF)
+gcov-files-i386-$(CONFIG_I82801B11) += hw/pci-bridge/i82801b11.c
+check-qtest-i386-$(CONFIG_IOH3420) += tests/ioh3420-test$(EXESUF)
+gcov-files-i386-$(CONFIG_IOH3420) += hw/pci-bridge/ioh3420.c
+check-qtest-i386-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF)
+gcov-files-i386-$(CONFIG_USB_OHCI) += hw/usb/hcd-ohci.c
+check-qtest-i386-$(CONFIG_USB_UHCI) += tests/usb-hcd-uhci-test$(EXESUF)
+gcov-files-i386-$(CONFIG_USB_UHCI) += hw/usb/hcd-uhci.c
+ifeq ($(CONFIG_USB_ECHI)$(CONFIG_USB_UHCI),yy)
check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
-gcov-files-i386-y += hw/usb/hcd-ehci.c
+endif
+gcov-files-i386-$(CONFIG_USB_EHCI) += hw/usb/hcd-ehci.c
gcov-files-i386-y += hw/usb/dev-hid.c
gcov-files-i386-y += hw/usb/dev-storage.c
check-qtest-i386-y += tests/usb-hcd-xhci-test$(EXESUF)
@@ -300,18 +306,18 @@ check-qtest-i386-$(CONFIG_VHOST_USER_NET_TEST_i386) += tests/vhost-user-test$(EX
ifeq ($(CONFIG_VHOST_USER_NET_TEST_i386),)
check-qtest-x86_64-$(CONFIG_VHOST_USER_NET_TEST_x86_64) += tests/vhost-user-test$(EXESUF)
endif
-check-qtest-i386-$(CONFIG_TPM) += tests/tpm-crb-swtpm-test$(EXESUF)
-check-qtest-i386-$(CONFIG_TPM) += tests/tpm-crb-test$(EXESUF)
-check-qtest-i386-$(CONFIG_TPM) += tests/tpm-tis-swtpm-test$(EXESUF)
-check-qtest-i386-$(CONFIG_TPM) += tests/tpm-tis-test$(EXESUF)
+check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF)
+check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF)
+check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF)
+check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-test$(EXESUF)
check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF)
-check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF)
+check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF)
check-qtest-i386-y += tests/migration-test$(EXESUF)
check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF)
check-qtest-i386-y += tests/numa-test$(EXESUF)
check-qtest-x86_64-y += $(check-qtest-i386-y)
-check-qtest-x86_64-y += tests/sdhci-test$(EXESUF)
+check-qtest-x86_64-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
@@ -347,16 +353,16 @@ check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF)
check-qtest-ppc64-y += tests/migration-test$(EXESUF)
check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF)
-check-qtest-ppc64-y += tests/usb-hcd-ohci-test$(EXESUF)
-gcov-files-ppc64-y += hw/usb/hcd-ohci.c
-check-qtest-ppc64-y += tests/usb-hcd-uhci-test$(EXESUF)
-gcov-files-ppc64-y += hw/usb/hcd-uhci.c
+check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF)
+gcov-files-ppc64-$(CONFIG_USB_OHCI) += hw/usb/hcd-ohci.c
+check-qtest-ppc64-$(CONFIG_USB_UHCI) += tests/usb-hcd-uhci-test$(EXESUF)
+gcov-files-ppc64-$(CONFIG_USB_UHCI) += hw/usb/hcd-uhci.c
check-qtest-ppc64-y += tests/usb-hcd-xhci-test$(EXESUF)
gcov-files-ppc64-y += hw/usb/hcd-xhci.c
check-qtest-ppc64-y += $(check-qtest-virtio-y)
check-qtest-ppc64-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF)
-check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF)
+check-qtest-ppc64-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF)
check-qtest-ppc64-y += tests/display-vga-test$(EXESUF)
check-qtest-ppc64-y += tests/numa-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_IVSHMEM) += tests/ivshmem-test$(EXESUF)
@@ -385,11 +391,11 @@ gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c
check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
gcov-files-arm-y += hw/timer/arm_mptimer.c
check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
-check-qtest-arm-y += tests/sdhci-test$(EXESUF)
+check-qtest-arm-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
check-qtest-arm-y += tests/hexloader-test$(EXESUF)
check-qtest-aarch64-y = tests/numa-test$(EXESUF)
-check-qtest-aarch64-y += tests/sdhci-test$(EXESUF)
+check-qtest-aarch64-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF)
check-qtest-microblazeel-y = $(check-qtest-microblaze-y)
@@ -402,9 +408,7 @@ check-qtest-s390x-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF)
check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF)
check-qtest-s390x-y += tests/drive_del-test$(EXESUF)
-check-qtest-s390x-y += tests/virtio-balloon-test$(EXESUF)
-check-qtest-s390x-y += tests/virtio-console-test$(EXESUF)
-check-qtest-s390x-y += tests/virtio-serial-test$(EXESUF)
+check-qtest-s390x-y += tests/virtio-ccw-test$(EXESUF)
check-qtest-s390x-y += tests/cpu-plug-test$(EXESUF)
check-qtest-generic-y += tests/machine-none-test$(EXESUF)
@@ -600,6 +604,8 @@ test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o \
tests/test-opts-visitor.o tests/test-qmp-event.o \
tests/rcutorture.o tests/test-rcu-list.o \
+ tests/test-rcu-simpleq.o \
+ tests/test-rcu-tailq.o \
tests/test-qdist.o tests/test-shift128.o \
tests/test-qht.o tests/qht-bench.o tests/test-qht-par.o \
tests/atomic_add-bench.o
@@ -649,6 +655,8 @@ tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o $(test-util-obj-y)
tests/test-int128$(EXESUF): tests/test-int128.o
tests/rcutorture$(EXESUF): tests/rcutorture.o $(test-util-obj-y)
tests/test-rcu-list$(EXESUF): tests/test-rcu-list.o $(test-util-obj-y)
+tests/test-rcu-simpleq$(EXESUF): tests/test-rcu-simpleq.o $(test-util-obj-y)
+tests/test-rcu-tailq$(EXESUF): tests/test-rcu-tailq.o $(test-util-obj-y)
tests/test-qdist$(EXESUF): tests/test-qdist.o $(test-util-obj-y)
tests/test-qht$(EXESUF): tests/test-qht.o $(test-util-obj-y)
tests/test-qht-par$(EXESUF): tests/test-qht-par.o tests/qht-bench$(EXESUF) $(test-util-obj-y)
@@ -809,6 +817,7 @@ tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y)
tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o $(libqos-virtio-obj-y)
tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y)
+tests/virtio-ccw-test$(EXESUF): tests/virtio-ccw-test.o
tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y)
tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y)
tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y)
diff --git a/tests/atomic_add-bench.c b/tests/atomic_add-bench.c
index f96d448f77..2f6c72f63a 100644
--- a/tests/atomic_add-bench.c
+++ b/tests/atomic_add-bench.c
@@ -26,6 +26,7 @@ static bool test_stop;
static const char commands_string[] =
" -n = number of threads\n"
" -m = use mutexes instead of atomic increments\n"
+ " -p = enable sync profiler\n"
" -d = duration in seconds\n"
" -r = range (will be rounded up to pow2)";
@@ -143,7 +144,7 @@ static void parse_args(int argc, char *argv[])
int c;
for (;;) {
- c = getopt(argc, argv, "hd:n:mr:");
+ c = getopt(argc, argv, "hd:n:mpr:");
if (c < 0) {
break;
}
@@ -160,6 +161,9 @@ static void parse_args(int argc, char *argv[])
case 'm':
use_mutex = true;
break;
+ case 'p':
+ qsp_enable();
+ break;
case 'r':
range = pow2ceil(atoi(optarg));
break;
diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
index 9d98c48a3d..c60ebcf9d9 100644
--- a/tests/boot-order-test.c
+++ b/tests/boot-order-test.c
@@ -14,7 +14,7 @@
#include "libqos/fw_cfg.h"
#include "libqtest.h"
#include "qapi/qmp/qdict.h"
-#include "hw/nvram/fw_cfg_keys.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
/* TODO actually test the results and get rid of this */
#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c
index f5d57da60e..3e93c8e096 100644
--- a/tests/cpu-plug-test.c
+++ b/tests/cpu-plug-test.c
@@ -257,11 +257,11 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- qtest_cb_for_every_machine(add_pc_test_case);
+ qtest_cb_for_every_machine(add_pc_test_case, g_test_quick());
} else if (g_str_equal(arch, "ppc64")) {
- qtest_cb_for_every_machine(add_pseries_test_case);
+ qtest_cb_for_every_machine(add_pseries_test_case, g_test_quick());
} else if (g_str_equal(arch, "s390x")) {
- qtest_cb_for_every_machine(add_s390x_test_case);
+ qtest_cb_for_every_machine(add_s390x_test_case, g_test_quick());
}
return g_test_run();
diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c
index 0b4f221c29..a25092dfaa 100644
--- a/tests/device-introspect-test.c
+++ b/tests/device-introspect-test.c
@@ -103,7 +103,14 @@ static QList *device_type_list(bool abstract)
static void test_one_device(const char *type)
{
QDict *resp;
- char *help, *qom_tree;
+ char *help;
+ char *qom_tree_start, *qom_tree_end;
+ char *qtree_start, *qtree_end;
+
+ g_test_message("Testing device '%s'", type);
+
+ qom_tree_start = hmp("info qom-tree");
+ qtree_start = hmp("info qtree");
resp = qmp("{'execute': 'device-list-properties',"
" 'arguments': {'typename': %s}}",
@@ -115,10 +122,18 @@ static void test_one_device(const char *type)
/*
* Some devices leave dangling pointers in QOM behind.
- * "info qom-tree" has a good chance at crashing then
+ * "info qom-tree" or "info qtree" have a good chance at crashing then.
+ * Also make sure that the tree did not change.
*/
- qom_tree = hmp("info qom-tree");
- g_free(qom_tree);
+ qom_tree_end = hmp("info qom-tree");
+ g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
+ g_free(qom_tree_start);
+ g_free(qom_tree_end);
+
+ qtree_end = hmp("info qtree");
+ g_assert_cmpstr(qtree_start, ==, qtree_end);
+ g_free(qtree_start);
+ g_free(qtree_end);
}
static void test_device_intro_list(void)
@@ -206,13 +221,13 @@ static void test_device_intro_abstract(void)
qtest_end();
}
-static void test_device_intro_concrete(void)
+static void test_device_intro_concrete(const void *args)
{
QList *types;
QListEntry *entry;
const char *type;
- qtest_start(common_args);
+ qtest_start(args);
types = device_type_list(false);
QLIST_FOREACH_ENTRY(types, entry) {
@@ -224,6 +239,7 @@ static void test_device_intro_concrete(void)
qobject_unref(types);
qtest_end();
+ g_free((void *)args);
}
static void test_abstract_interfaces(void)
@@ -260,6 +276,26 @@ static void test_abstract_interfaces(void)
qtest_end();
}
+static void add_machine_test_case(const char *mname)
+{
+ char *path, *args;
+
+ /* Ignore blacklisted machines */
+ if (g_str_equal("xenfv", mname) || g_str_equal("xenpv", mname)) {
+ return;
+ }
+
+ path = g_strdup_printf("device/introspect/concrete/defaults/%s", mname);
+ args = g_strdup_printf("-M %s", mname);
+ qtest_add_data_func(path, args, test_device_intro_concrete);
+ g_free(path);
+
+ path = g_strdup_printf("device/introspect/concrete/nodefaults/%s", mname);
+ args = g_strdup_printf("-nodefaults -M %s", mname);
+ qtest_add_data_func(path, args, test_device_intro_concrete);
+ g_free(path);
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -268,8 +304,13 @@ int main(int argc, char **argv)
qtest_add_func("device/introspect/list-fields", test_qom_list_fields);
qtest_add_func("device/introspect/none", test_device_intro_none);
qtest_add_func("device/introspect/abstract", test_device_intro_abstract);
- qtest_add_func("device/introspect/concrete", test_device_intro_concrete);
qtest_add_func("device/introspect/abstract-interfaces", test_abstract_interfaces);
+ if (g_test_quick()) {
+ qtest_add_data_func("device/introspect/concrete/defaults/none",
+ g_strdup(common_args), test_device_intro_concrete);
+ } else {
+ qtest_cb_for_every_machine(add_machine_test_case, true);
+ }
return g_test_run();
}
diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c
index 1548bf14b2..1c5103fe1c 100644
--- a/tests/fw_cfg-test.c
+++ b/tests/fw_cfg-test.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "libqtest.h"
-#include "hw/nvram/fw_cfg_keys.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
#include "libqos/fw_cfg.h"
static uint64_t ram_size = 128 << 20;
diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index 634b9c288a..b83cb8f0af 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -14,7 +14,7 @@
#include "libqos/malloc-pc.h"
#include "libqos/fw_cfg.h"
-#include "hw/nvram/fw_cfg_keys.h"
+#include "standard-headers/linux/qemu_fw_cfg.h"
#include "qemu-common.h"
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 852ccff1ce..1105c37e08 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -991,7 +991,53 @@ bool qtest_big_endian(QTestState *s)
return s->big_endian;
}
-void qtest_cb_for_every_machine(void (*cb)(const char *machine))
+static bool qtest_check_machine_version(const char *mname, const char *basename,
+ int major, int minor)
+{
+ char *newname;
+ bool is_equal;
+
+ newname = g_strdup_printf("%s-%i.%i", basename, major, minor);
+ is_equal = g_str_equal(mname, newname);
+ g_free(newname);
+
+ return is_equal;
+}
+
+static bool qtest_is_old_versioned_machine(const char *mname)
+{
+ const char *dash = strrchr(mname, '-');
+ const char *dot = strrchr(mname, '.');
+ const char *chr;
+ char *bname;
+ const int major = QEMU_VERSION_MAJOR;
+ const int minor = QEMU_VERSION_MINOR;
+ bool res = false;
+
+ if (dash && dot && dot > dash) {
+ for (chr = dash + 1; *chr; chr++) {
+ if (!qemu_isdigit(*chr) && *chr != '.') {
+ return false;
+ }
+ }
+ /*
+ * Now check if it is one of the latest versions. Check major + 1
+ * and minor + 1 versions as well, since they might already exist
+ * in the development branch.
+ */
+ bname = g_strdup(mname);
+ bname[dash - mname] = 0;
+ res = !qtest_check_machine_version(mname, bname, major + 1, 0) &&
+ !qtest_check_machine_version(mname, bname, major, minor + 1) &&
+ !qtest_check_machine_version(mname, bname, major, minor);
+ g_free(bname);
+ }
+
+ return res;
+}
+
+void qtest_cb_for_every_machine(void (*cb)(const char *machine),
+ bool skip_old_versioned)
{
QDict *response, *minfo;
QList *list;
@@ -1014,7 +1060,9 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine))
qstr = qobject_to(QString, qobj);
g_assert(qstr);
mname = qstring_get_str(qstr);
- cb(mname);
+ if (!skip_old_versioned || !qtest_is_old_versioned_machine(mname)) {
+ cb(mname);
+ }
}
qtest_end();
diff --git a/tests/libqtest.h b/tests/libqtest.h
index def1edaafa..1159b73d15 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -954,10 +954,12 @@ QDict *qmp_fd(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
/**
* qtest_cb_for_every_machine:
* @cb: Pointer to the callback function
+ * @skip_old_versioned: true if versioned old machine types should be skipped
*
* Call a callback function for every name of all available machines.
*/
-void qtest_cb_for_every_machine(void (*cb)(const char *machine));
+void qtest_cb_for_every_machine(void (*cb)(const char *machine),
+ bool skip_old_versioned);
/**
* qtest_qmp_device_add:
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
new file mode 100755
index 0000000000..ff851ec431
--- /dev/null
+++ b/tests/qemu-iotests/229
@@ -0,0 +1,95 @@
+#!/bin/bash
+#
+# Test for force canceling a running blockjob that is paused in
+# an error state.
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=jcody@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_qemu
+ _cleanup_test_img
+ rm -f "$TEST_IMG" "$DEST_IMG"
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+# Needs backing file and backing format support
+_supported_fmt qcow2 qed
+_supported_proto file
+_supported_os Linux
+
+
+DEST_IMG="$TEST_DIR/d.$IMGFMT"
+TEST_IMG="$TEST_DIR/b.$IMGFMT"
+
+_make_test_img 2M
+
+# destination for mirror will be too small, causing error
+TEST_IMG=$DEST_IMG _make_test_img 1M
+
+$QEMU_IO -c 'write 0 2M' "$TEST_IMG" | _filter_qemu_io
+
+_launch_qemu -drive id=testdisk,file="$TEST_IMG",format="$IMGFMT"
+
+_send_qemu_cmd $QEMU_HANDLE \
+ "{'execute': 'qmp_capabilities'}" \
+ 'return'
+
+echo
+echo '=== Starting drive-mirror, causing error & stop ==='
+echo
+
+_send_qemu_cmd $QEMU_HANDLE \
+ "{'execute': 'drive-mirror',
+ 'arguments': {'device': 'testdisk',
+ 'mode': 'absolute-paths',
+ 'format': '$IMGFMT',
+ 'target': '$DEST_IMG',
+ 'sync': 'full',
+ 'mode': 'existing',
+ 'on-source-error': 'stop',
+ 'on-target-error': 'stop' }}" \
+ "JOB_STATUS_CHANGE.*pause"
+
+echo
+echo '=== Force cancel job paused in error state ==='
+echo
+
+success_or_failure="y" _send_qemu_cmd $QEMU_HANDLE \
+ "{'execute': 'block-job-cancel',
+ 'arguments': { 'device': 'testdisk',
+ 'force': true}}" \
+ "BLOCK_JOB_CANCELLED" "Assertion"
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/229.out b/tests/qemu-iotests/229.out
new file mode 100644
index 0000000000..4c4112805f
--- /dev/null
+++ b/tests/qemu-iotests/229.out
@@ -0,0 +1,23 @@
+QA output created by 229
+Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=2097152
+Formatting 'TEST_DIR/d.IMGFMT', fmt=IMGFMT size=1048576
+wrote 2097152/2097152 bytes at offset 0
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+{"return": {}}
+
+=== Starting drive-mirror, causing error & stop ===
+
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "testdisk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "testdisk", "operation": "write", "action": "stop"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "testdisk"}}
+
+=== Force cancel job paused in error state ===
+
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "testdisk", "operation": "write", "action": "stop"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "testdisk"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": 1048576, "speed": 0, "type": "mirror"}}
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index b973dc842d..743790745b 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -225,3 +225,4 @@
225 rw auto quick
226 auto quick
227 auto quick
+229 auto quick
diff --git a/tests/qom-test.c b/tests/qom-test.c
index e6f712cbd3..73c52af3bb 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -123,7 +123,7 @@ int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
- qtest_cb_for_every_machine(add_machine_test_case);
+ qtest_cb_for_every_machine(add_machine_test_case, g_test_quick());
return g_test_run();
}
diff --git a/tests/test-char.c b/tests/test-char.c
index 5905d31441..2a2ff32904 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -56,7 +56,6 @@ static void fe_event(void *opaque, int event)
}
}
-#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
#ifdef _WIN32
static void char_console_test_subprocess(void)
{
@@ -106,7 +105,6 @@ static void char_stdio_test(void)
g_test_trap_assert_passed();
g_test_trap_assert_stdout("buf");
}
-#endif
static void char_ringbuf_test(void)
{
@@ -807,14 +805,12 @@ int main(int argc, char **argv)
g_test_add_func("/char/invalid", char_invalid_test);
g_test_add_func("/char/ringbuf", char_ringbuf_test);
g_test_add_func("/char/mux", char_mux_test);
-#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
#ifdef _WIN32
g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
g_test_add_func("/char/console", char_console_test);
#endif
g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
g_test_add_func("/char/stdio", char_stdio_test);
-#endif
#ifndef _WIN32
g_test_add_func("/char/pipe", char_pipe_test);
#endif
diff --git a/tests/test-hmp.c b/tests/test-hmp.c
index 5352c9c088..1a3a9c5099 100644
--- a/tests/test-hmp.c
+++ b/tests/test-hmp.c
@@ -158,7 +158,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
- qtest_cb_for_every_machine(add_machine_test_case);
+ qtest_cb_for_every_machine(add_machine_test_case, g_test_quick());
/* as none machine has no memory by default, add a test case with memory */
qtest_add_data_func("hmp/none+2MB", g_strdup("none -m 2"), test_machine);
diff --git a/tests/test-rcu-list.c b/tests/test-rcu-list.c
index 1514d7ec97..192bfbf02e 100644
--- a/tests/test-rcu-list.c
+++ b/tests/test-rcu-list.c
@@ -44,7 +44,7 @@ static int nthreadsrunning;
#define GOFLAG_RUN 1
#define GOFLAG_STOP 2
-static volatile int goflag = GOFLAG_INIT;
+static int goflag = GOFLAG_INIT;
#define RCU_READ_RUN 1000
#define RCU_UPDATE_RUN 10
@@ -82,9 +82,20 @@ static void wait_all_threads(void)
n_threads = 0;
}
+#ifndef TEST_LIST_TYPE
+#define TEST_LIST_TYPE 1
+#endif
struct list_element {
+#if TEST_LIST_TYPE == 1
QLIST_ENTRY(list_element) entry;
+#elif TEST_LIST_TYPE == 2
+ QSIMPLEQ_ENTRY(list_element) entry;
+#elif TEST_LIST_TYPE == 3
+ QTAILQ_ENTRY(list_element) entry;
+#else
+#error Invalid TEST_LIST_TYPE
+#endif
struct rcu_head rcu;
};
@@ -96,8 +107,47 @@ static void reclaim_list_el(struct rcu_head *prcu)
n_reclaims++;
}
+#if TEST_LIST_TYPE == 1
static QLIST_HEAD(q_list_head, list_element) Q_list_head;
+#define TEST_NAME "qlist"
+#define TEST_LIST_REMOVE_RCU QLIST_REMOVE_RCU
+#define TEST_LIST_INSERT_AFTER_RCU QLIST_INSERT_AFTER_RCU
+#define TEST_LIST_INSERT_HEAD_RCU QLIST_INSERT_HEAD_RCU
+#define TEST_LIST_FOREACH_RCU QLIST_FOREACH_RCU
+#define TEST_LIST_FOREACH_SAFE_RCU QLIST_FOREACH_SAFE_RCU
+
+#elif TEST_LIST_TYPE == 2
+static QSIMPLEQ_HEAD(, list_element) Q_list_head =
+ QSIMPLEQ_HEAD_INITIALIZER(Q_list_head);
+
+#define TEST_NAME "qsimpleq"
+#define TEST_LIST_REMOVE_RCU(el, f) \
+ QSIMPLEQ_REMOVE_RCU(&Q_list_head, el, list_element, f)
+
+#define TEST_LIST_INSERT_AFTER_RCU(list_el, el, f) \
+ QSIMPLEQ_INSERT_AFTER_RCU(&Q_list_head, list_el, el, f)
+
+#define TEST_LIST_INSERT_HEAD_RCU QSIMPLEQ_INSERT_HEAD_RCU
+#define TEST_LIST_FOREACH_RCU QSIMPLEQ_FOREACH_RCU
+#define TEST_LIST_FOREACH_SAFE_RCU QSIMPLEQ_FOREACH_SAFE_RCU
+
+#elif TEST_LIST_TYPE == 3
+static QTAILQ_HEAD(, list_element) Q_list_head;
+
+#define TEST_NAME "qtailq"
+#define TEST_LIST_REMOVE_RCU(el, f) QTAILQ_REMOVE_RCU(&Q_list_head, el, f)
+
+#define TEST_LIST_INSERT_AFTER_RCU(list_el, el, f) \
+ QTAILQ_INSERT_AFTER_RCU(&Q_list_head, list_el, el, f)
+
+#define TEST_LIST_INSERT_HEAD_RCU QTAILQ_INSERT_HEAD_RCU
+#define TEST_LIST_FOREACH_RCU QTAILQ_FOREACH_RCU
+#define TEST_LIST_FOREACH_SAFE_RCU QTAILQ_FOREACH_SAFE_RCU
+#else
+#error Invalid TEST_LIST_TYPE
+#endif
+
static void *rcu_q_reader(void *arg)
{
long long n_reads_local = 0;
@@ -107,15 +157,15 @@ static void *rcu_q_reader(void *arg)
*(struct rcu_reader_data **)arg = &rcu_reader;
atomic_inc(&nthreadsrunning);
- while (goflag == GOFLAG_INIT) {
+ while (atomic_read(&goflag) == GOFLAG_INIT) {
g_usleep(1000);
}
- while (goflag == GOFLAG_RUN) {
+ while (atomic_read(&goflag) == GOFLAG_RUN) {
rcu_read_lock();
- QLIST_FOREACH_RCU(el, &Q_list_head, entry) {
+ TEST_LIST_FOREACH_RCU(el, &Q_list_head, entry) {
n_reads_local++;
- if (goflag == GOFLAG_STOP) {
+ if (atomic_read(&goflag) == GOFLAG_STOP) {
break;
}
}
@@ -142,35 +192,35 @@ static void *rcu_q_updater(void *arg)
*(struct rcu_reader_data **)arg = &rcu_reader;
atomic_inc(&nthreadsrunning);
- while (goflag == GOFLAG_INIT) {
+ while (atomic_read(&goflag) == GOFLAG_INIT) {
g_usleep(1000);
}
- while (goflag == GOFLAG_RUN) {
+ while (atomic_read(&goflag) == GOFLAG_RUN) {
target_el = select_random_el(RCU_Q_LEN);
j = 0;
/* FOREACH_RCU could work here but let's use both macros */
- QLIST_FOREACH_SAFE_RCU(prev_el, &Q_list_head, entry, el) {
+ TEST_LIST_FOREACH_SAFE_RCU(prev_el, &Q_list_head, entry, el) {
j++;
if (target_el == j) {
- QLIST_REMOVE_RCU(prev_el, entry);
+ TEST_LIST_REMOVE_RCU(prev_el, entry);
/* may be more than one updater in the future */
call_rcu1(&prev_el->rcu, reclaim_list_el);
n_removed_local++;
break;
}
}
- if (goflag == GOFLAG_STOP) {
+ if (atomic_read(&goflag) == GOFLAG_STOP) {
break;
}
target_el = select_random_el(RCU_Q_LEN);
j = 0;
- QLIST_FOREACH_RCU(el, &Q_list_head, entry) {
+ TEST_LIST_FOREACH_RCU(el, &Q_list_head, entry) {
j++;
if (target_el == j) {
- prev_el = g_new(struct list_element, 1);
+ struct list_element *new_el = g_new(struct list_element, 1);
n_nodes += n_nodes_local;
- QLIST_INSERT_BEFORE_RCU(el, prev_el, entry);
+ TEST_LIST_INSERT_AFTER_RCU(el, new_el, entry);
break;
}
}
@@ -195,7 +245,7 @@ static void rcu_qtest_init(void)
srand(time(0));
for (i = 0; i < RCU_Q_LEN; i++) {
new_el = g_new(struct list_element, 1);
- QLIST_INSERT_HEAD_RCU(&Q_list_head, new_el, entry);
+ TEST_LIST_INSERT_HEAD_RCU(&Q_list_head, new_el, entry);
}
qemu_mutex_lock(&counts_mutex);
n_nodes += RCU_Q_LEN;
@@ -209,9 +259,9 @@ static void rcu_qtest_run(int duration, int nreaders)
g_usleep(1000);
}
- goflag = GOFLAG_RUN;
+ atomic_set(&goflag, GOFLAG_RUN);
sleep(duration);
- goflag = GOFLAG_STOP;
+ atomic_set(&goflag, GOFLAG_STOP);
wait_all_threads();
}
@@ -230,8 +280,8 @@ static void rcu_qtest(const char *test, int duration, int nreaders)
create_thread(rcu_q_updater);
rcu_qtest_run(duration, nreaders);
- QLIST_FOREACH_SAFE_RCU(prev_el, &Q_list_head, entry, el) {
- QLIST_REMOVE_RCU(prev_el, entry);
+ TEST_LIST_FOREACH_SAFE_RCU(prev_el, &Q_list_head, entry, el) {
+ TEST_LIST_REMOVE_RCU(prev_el, entry);
call_rcu1(&prev_el->rcu, reclaim_list_el);
n_removed_local++;
}
@@ -290,9 +340,9 @@ int main(int argc, char *argv[])
} else {
gtest_seconds = 20;
}
- g_test_add_func("/rcu/qlist/single-threaded", gtest_rcuq_one);
- g_test_add_func("/rcu/qlist/short-few", gtest_rcuq_few);
- g_test_add_func("/rcu/qlist/long-many", gtest_rcuq_many);
+ g_test_add_func("/rcu/"TEST_NAME"/single-threaded", gtest_rcuq_one);
+ g_test_add_func("/rcu/"TEST_NAME"/short-few", gtest_rcuq_few);
+ g_test_add_func("/rcu/"TEST_NAME"/long-many", gtest_rcuq_many);
g_test_in_charge = 1;
return g_test_run();
}
diff --git a/tests/test-rcu-simpleq.c b/tests/test-rcu-simpleq.c
new file mode 100644
index 0000000000..057f7d33f7
--- /dev/null
+++ b/tests/test-rcu-simpleq.c
@@ -0,0 +1,2 @@
+#define TEST_LIST_TYPE 2
+#include "test-rcu-list.c"
diff --git a/tests/test-rcu-tailq.c b/tests/test-rcu-tailq.c
new file mode 100644
index 0000000000..8d487e0ee0
--- /dev/null
+++ b/tests/test-rcu-tailq.c
@@ -0,0 +1,2 @@
+#define TEST_LIST_TYPE 3
+#include "test-rcu-list.c"
diff --git a/tests/test-x86-cpuid-compat.c b/tests/test-x86-cpuid-compat.c
index 84ce9c71ae..e75b959950 100644
--- a/tests/test-x86-cpuid-compat.c
+++ b/tests/test-x86-cpuid-compat.c
@@ -35,7 +35,6 @@ static QObject *qom_get(const char *path, const char *prop)
return ret;
}
-#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
static bool qom_get_bool(const char *path, const char *prop)
{
QBool *value = qobject_to(QBool, qom_get(path, prop));
@@ -44,7 +43,6 @@ static bool qom_get_bool(const char *path, const char *prop)
qobject_unref(value);
return b;
}
-#endif
typedef struct CpuidTestArgs {
const char *cmdline;
@@ -168,7 +166,6 @@ static FeatureTestArgs *add_feature_test(const char *name, const char *cmdline,
return args;
}
-#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
static void test_plus_minus_subprocess(void)
{
char *path;
@@ -210,17 +207,14 @@ static void test_plus_minus(void)
"Don't mix both \"+cx8\" and \"cx8=off\"*");
g_test_trap_assert_stdout("");
}
-#endif
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
-#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
g_test_add_func("/x86/cpuid/parsing-plus-minus/subprocess",
test_plus_minus_subprocess);
g_test_add_func("/x86/cpuid/parsing-plus-minus", test_plus_minus);
-#endif
/* Original level values for CPU models: */
add_cpuid_test("x86/cpuid/phenom/level",
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index ca6251f5f8..716aff7153 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -768,7 +768,6 @@ static void wait_for_rings_started(TestServer *s, size_t count)
g_mutex_unlock(&s->data_mutex);
}
-#if defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS)
static inline void test_server_connect(TestServer *server)
{
test_server_create_chr(server, ",reconnect=1");
@@ -893,7 +892,6 @@ static void test_flags_mismatch(void)
g_free(path);
}
-#endif
static void test_multiqueue(void)
{
@@ -975,7 +973,6 @@ int main(int argc, char **argv)
qtest_add_func("/vhost-user/migrate", test_migrate);
qtest_add_func("/vhost-user/multiqueue", test_multiqueue);
-#if defined(CONFIG_HAS_GLIB_SUBPROCESS_TESTS)
/* keeps failing on build-system since Aug 15 2017 */
if (getenv("QTEST_VHOST_USER_FIXME")) {
qtest_add_func("/vhost-user/reconnect/subprocess",
@@ -988,7 +985,6 @@ int main(int argc, char **argv)
test_flags_mismatch_subprocess);
qtest_add_func("/vhost-user/flags-mismatch", test_flags_mismatch);
}
-#endif
ret = g_test_run();
diff --git a/tests/virtio-ccw-test.c b/tests/virtio-ccw-test.c
new file mode 100644
index 0000000000..48c714d84c
--- /dev/null
+++ b/tests/virtio-ccw-test.c
@@ -0,0 +1,110 @@
+/*
+ * QTest testcase for VirtIO CCW
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ * Copyright (c) 2018 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/* Until we have a full libqos implementation of virtio-ccw (which requires
+ * also to add support for I/O channels to qtest), we can only do simple
+ * tests that initialize the devices.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/virtio.h"
+
+static void virtio_balloon_nop(void)
+{
+ global_qtest = qtest_initf("-device virtio-balloon-ccw");
+ qtest_end();
+}
+
+static void virtconsole_nop(void)
+{
+ global_qtest = qtest_initf("-device virtio-serial-ccw,id=vser0 "
+ "-device virtconsole,bus=vser0.0");
+ qtest_end();
+}
+
+static void virtserialport_nop(void)
+{
+ global_qtest = qtest_initf("-device virtio-serial-ccw,id=vser0 "
+ "-device virtserialport,bus=vser0.0");
+ qtest_end();
+}
+
+static void virtio_serial_nop(void)
+{
+ global_qtest = qtest_initf("-device virtio-serial-ccw");
+ qtest_end();
+}
+
+static void virtio_serial_hotplug(void)
+{
+ global_qtest = qtest_initf("-device virtio-serial-ccw");
+ qtest_qmp_device_add("virtserialport", "hp-port", "{}");
+ qtest_qmp_device_del("hp-port");
+ qtest_end();
+}
+
+static void virtio_blk_nop(void)
+{
+ global_qtest = qtest_initf("-drive if=none,id=drv0,file=null-co://,format=raw "
+ "-device virtio-blk-ccw,drive=drv0");
+ qtest_end();
+}
+
+static void virtio_net_nop(void)
+{
+ global_qtest = qtest_initf("-device virtio-net-ccw");
+ qtest_end();
+}
+
+static void virtio_rng_nop(void)
+{
+ global_qtest = qtest_initf("-device virtio-rng-ccw");
+ qtest_end();
+}
+
+static void virtio_scsi_nop(void)
+{
+ global_qtest = qtest_initf("-device virtio-scsi-ccw");
+ qtest_end();
+}
+
+static void virtio_scsi_hotplug(void)
+{
+ global_qtest = qtest_initf("-drive if=none,id=drv0,file=null-co://,format=raw "
+ "-drive if=none,id=drv1,file=null-co://,format=raw "
+ "-device virtio-scsi-ccw "
+ "-device scsi-hd,drive=drv0");
+ qtest_qmp_device_add("scsi-hd", "scsihd", "{'drive': 'drv1'}");
+ qtest_qmp_device_del("scsihd");
+
+ qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/virtio/balloon/nop", virtio_balloon_nop);
+ qtest_add_func("/virtio/console/nop", virtconsole_nop);
+ qtest_add_func("/virtio/serialport/nop", virtserialport_nop);
+ qtest_add_func("/virtio/serial/nop", virtio_serial_nop);
+ qtest_add_func("/virtio/serial/hotplug", virtio_serial_hotplug);
+ qtest_add_func("/virtio/block/nop", virtio_blk_nop);
+ qtest_add_func("/virtio/net/nop", virtio_net_nop);
+ qtest_add_func("/virtio/rng/nop", virtio_rng_nop);
+ qtest_add_func("/virtio/scsi/nop", virtio_scsi_nop);
+ qtest_add_func("/virtio/scsi/hotplug", virtio_scsi_hotplug);
+
+ ret = g_test_run();
+
+ return ret;
+}
diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
index d7149dea7d..7e58d9e0ca 100755
--- a/tests/vm/basevm.py
+++ b/tests/vm/basevm.py
@@ -176,7 +176,7 @@ class BaseVM(object):
raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \
usernet_info)
- def wait_ssh(self, seconds=120):
+ def wait_ssh(self, seconds=300):
starttime = datetime.datetime.now()
guest_up = False
while (datetime.datetime.now() - starttime).total_seconds() < seconds:
diff --git a/util/Makefile.objs b/util/Makefile.objs
index e1c3fed4dc..e958116c86 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -44,6 +44,7 @@ util-obj-y += log.o
util-obj-y += pagesize.o
util-obj-y += qdist.o
util-obj-y += qht.o
+util-obj-y += qsp.o
util-obj-y += range.o
util-obj-y += stats64.o
util-obj-y += systemd.o
diff --git a/util/module.c b/util/module.c
index c90973721f..1259dd3686 100644
--- a/util/module.c
+++ b/util/module.c
@@ -162,9 +162,10 @@ void module_load_one(const char *prefix, const char *lib_name)
#ifdef CONFIG_MODULES
char *fname = NULL;
char *exec_dir;
- char *dirs[3];
+ const char *search_dir;
+ char *dirs[4];
char *module_name;
- int i = 0;
+ int i = 0, n_dirs = 0;
int ret;
static GHashTable *loaded_modules;
@@ -186,14 +187,19 @@ void module_load_one(const char *prefix, const char *lib_name)
g_hash_table_insert(loaded_modules, module_name, module_name);
exec_dir = qemu_get_exec_dir();
- dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
- dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : "");
- dirs[i++] = g_strdup_printf("%s", exec_dir ? : "");
- assert(i == ARRAY_SIZE(dirs));
+ search_dir = getenv("QEMU_MODULE_DIR");
+ if (search_dir != NULL) {
+ dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
+ }
+ dirs[n_dirs++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
+ dirs[n_dirs++] = g_strdup_printf("%s/..", exec_dir ? : "");
+ dirs[n_dirs++] = g_strdup_printf("%s", exec_dir ? : "");
+ assert(n_dirs <= ARRAY_SIZE(dirs));
+
g_free(exec_dir);
exec_dir = NULL;
- for (i = 0; i < ARRAY_SIZE(dirs); i++) {
+ for (i = 0; i < n_dirs; i++) {
fname = g_strdup_printf("%s/%s%s",
dirs[i], module_name, HOST_DSOSUF);
ret = module_load_file(fname);
@@ -205,7 +211,7 @@ void module_load_one(const char *prefix, const char *lib_name)
}
}
- for (i = 0; i < ARRAY_SIZE(dirs); i++) {
+ for (i = 0; i < n_dirs; i++) {
g_free(dirs[i]);
}
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index bb5ad28bd3..25dd1595ad 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -67,15 +67,24 @@ void *qemu_memalign(size_t alignment, size_t size)
return qemu_oom_check(qemu_try_memalign(alignment, size));
}
+static int get_allocation_granularity(void)
+{
+ SYSTEM_INFO system_info;
+
+ GetSystemInfo(&system_info);
+ return system_info.dwAllocationGranularity;
+}
+
void *qemu_anon_ram_alloc(size_t size, uint64_t *align, bool shared)
{
void *ptr;
- /* FIXME: this is not exactly optimal solution since VirtualAlloc
- has 64Kb granularity, but at least it guarantees us that the
- memory is page aligned. */
ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
trace_qemu_anon_ram_alloc(size, ptr);
+
+ if (ptr && align) {
+ *align = MAX(get_allocation_granularity(), getpagesize());
+ }
return ptr;
}
diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
index b303188a36..4a363ca675 100644
--- a/util/qemu-thread-win32.c
+++ b/util/qemu-thread-win32.c
@@ -97,13 +97,13 @@ void qemu_rec_mutex_destroy(QemuRecMutex *mutex)
DeleteCriticalSection(&mutex->lock);
}
-void qemu_rec_mutex_lock(QemuRecMutex *mutex)
+void qemu_rec_mutex_lock_impl(QemuRecMutex *mutex, const char *file, int line)
{
assert(mutex->initialized);
EnterCriticalSection(&mutex->lock);
}
-int qemu_rec_mutex_trylock(QemuRecMutex *mutex)
+int qemu_rec_mutex_trylock_impl(QemuRecMutex *mutex, const char *file, int line)
{
assert(mutex->initialized);
return !TryEnterCriticalSection(&mutex->lock);
diff --git a/util/qht.c b/util/qht.c
index c138777a9c..1e3a072e25 100644
--- a/util/qht.c
+++ b/util/qht.c
@@ -90,6 +90,33 @@
#endif
/*
+ * Do _not_ use qemu_mutex_[try]lock directly! Use these macros, otherwise
+ * the profiler (QSP) will deadlock.
+ */
+static inline void qht_lock(struct qht *ht)
+{
+ if (ht->mode & QHT_MODE_RAW_MUTEXES) {
+ qemu_mutex_lock__raw(&ht->lock);
+ } else {
+ qemu_mutex_lock(&ht->lock);
+ }
+}
+
+static inline int qht_trylock(struct qht *ht)
+{
+ if (ht->mode & QHT_MODE_RAW_MUTEXES) {
+ return qemu_mutex_trylock__raw(&(ht)->lock);
+ }
+ return qemu_mutex_trylock(&(ht)->lock);
+}
+
+/* this inline is not really necessary, but it helps keep code consistent */
+static inline void qht_unlock(struct qht *ht)
+{
+ qemu_mutex_unlock(&ht->lock);
+}
+
+/*
* Note: reading partially-updated pointers in @pointers could lead to
* segfaults. We thus access them with atomic_read/set; this guarantees
* that the compiler makes all those accesses atomic. We also need the
@@ -254,10 +281,10 @@ void qht_map_lock_buckets__no_stale(struct qht *ht, struct qht_map **pmap)
qht_map_unlock_buckets(map);
/* we raced with a resize; acquire ht->lock to see the updated ht->map */
- qemu_mutex_lock(&ht->lock);
+ qht_lock(ht);
map = ht->map;
qht_map_lock_buckets(map);
- qemu_mutex_unlock(&ht->lock);
+ qht_unlock(ht);
*pmap = map;
return;
}
@@ -288,11 +315,11 @@ struct qht_bucket *qht_bucket_lock__no_stale(struct qht *ht, uint32_t hash,
qemu_spin_unlock(&b->lock);
/* we raced with a resize; acquire ht->lock to see the updated ht->map */
- qemu_mutex_lock(&ht->lock);
+ qht_lock(ht);
map = ht->map;
b = qht_map_to_bucket(map, hash);
qemu_spin_lock(&b->lock);
- qemu_mutex_unlock(&ht->lock);
+ qht_unlock(ht);
*pmap = map;
return b;
}
@@ -430,13 +457,13 @@ bool qht_reset_size(struct qht *ht, size_t n_elems)
n_buckets = qht_elems_to_buckets(n_elems);
- qemu_mutex_lock(&ht->lock);
+ qht_lock(ht);
map = ht->map;
if (n_buckets != map->n_buckets) {
new = qht_map_create(n_buckets);
}
qht_do_resize_and_reset(ht, new);
- qemu_mutex_unlock(&ht->lock);
+ qht_unlock(ht);
return !!new;
}
@@ -565,7 +592,7 @@ static __attribute__((noinline)) void qht_grow_maybe(struct qht *ht)
* If the lock is taken it probably means there's an ongoing resize,
* so bail out.
*/
- if (qemu_mutex_trylock(&ht->lock)) {
+ if (qht_trylock(ht)) {
return;
}
map = ht->map;
@@ -575,7 +602,7 @@ static __attribute__((noinline)) void qht_grow_maybe(struct qht *ht)
qht_do_resize(ht, new);
}
- qemu_mutex_unlock(&ht->lock);
+ qht_unlock(ht);
}
bool qht_insert(struct qht *ht, void *p, uint32_t hash, void **existing)
@@ -788,7 +815,7 @@ bool qht_resize(struct qht *ht, size_t n_elems)
size_t n_buckets = qht_elems_to_buckets(n_elems);
size_t ret = false;
- qemu_mutex_lock(&ht->lock);
+ qht_lock(ht);
if (n_buckets != ht->map->n_buckets) {
struct qht_map *new;
@@ -796,7 +823,7 @@ bool qht_resize(struct qht *ht, size_t n_elems)
qht_do_resize(ht, new);
ret = true;
}
- qemu_mutex_unlock(&ht->lock);
+ qht_unlock(ht);
return ret;
}
diff --git a/util/qsp.c b/util/qsp.c
new file mode 100644
index 0000000000..b0c2575d10
--- /dev/null
+++ b/util/qsp.c
@@ -0,0 +1,828 @@
+/*
+ * qsp.c - QEMU Synchronization Profiler
+ *
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * QSP profiles the time spent in synchronization primitives, which can
+ * help diagnose performance problems, e.g. scalability issues when
+ * contention is high.
+ *
+ * The primitives currently supported are mutexes, recursive mutexes and
+ * condition variables. Note that not all related functions are intercepted;
+ * instead we profile only those functions that can have a performance impact,
+ * either due to blocking (e.g. cond_wait, mutex_lock) or cache line
+ * contention (e.g. mutex_lock, mutex_trylock).
+ *
+ * QSP's design focuses on speed and scalability. This is achieved
+ * by having threads do their profiling entirely on thread-local data.
+ * The appropriate thread-local data is found via a QHT, i.e. a concurrent hash
+ * table. To aggregate data in order to generate a report, we iterate over
+ * all entries in the hash table. Depending on the number of threads and
+ * synchronization objects this might be expensive, but note that it is
+ * very rarely called -- reports are generated only when requested by users.
+ *
+ * Reports are generated as a table where each row represents a call site. A
+ * call site is the triplet formed by the __file__ and __LINE__ of the caller
+ * as well as the address of the "object" (i.e. mutex, rec. mutex or condvar)
+ * being operated on. Optionally, call sites that operate on different objects
+ * of the same type can be coalesced, which can be particularly useful when
+ * profiling dynamically-allocated objects.
+ *
+ * Alternative designs considered:
+ *
+ * - Use an off-the-shelf profiler such as mutrace. This is not a viable option
+ * for us because QEMU has __malloc_hook set (by one of the libraries it
+ * uses); leaving this hook unset is required to avoid deadlock in mutrace.
+ *
+ * - Use a glib HT for each thread, protecting each HT with its own lock.
+ * This isn't simpler than the current design, and is 10% slower in the
+ * atomic_add-bench microbenchmark (-m option).
+ *
+ * - For reports, just use a binary tree as we aggregate data, instead of having
+ * an intermediate hash table. This would simplify the code only slightly, but
+ * would perform badly if there were many threads and objects to track.
+ *
+ * - Wrap operations on qsp entries with RCU read-side critical sections, so
+ * that qsp_reset() can delete entries. Unfortunately, the overhead of calling
+ * rcu_read_lock/unlock slows down atomic_add-bench -m by 24%. Having
+ * a snapshot that is updated on qsp_reset() avoids this overhead.
+ *
+ * Related Work:
+ * - Lennart Poettering's mutrace: http://0pointer.de/blog/projects/mutrace.html
+ * - Lozi, David, Thomas, Lawall and Muller. "Remote Core Locking: Migrating
+ * Critical-Section Execution to Improve the Performance of Multithreaded
+ * Applications", USENIX ATC'12.
+ */
+#include "qemu/osdep.h"
+#include "qemu/thread.h"
+#include "qemu/timer.h"
+#include "qemu/qht.h"
+#include "qemu/rcu.h"
+#include "exec/tb-hash-xx.h"
+
+enum QSPType {
+ QSP_MUTEX,
+ QSP_BQL_MUTEX,
+ QSP_REC_MUTEX,
+ QSP_CONDVAR,
+};
+
+struct QSPCallSite {
+ const void *obj;
+ const char *file; /* i.e. __FILE__; shortened later */
+ int line;
+ enum QSPType type;
+};
+typedef struct QSPCallSite QSPCallSite;
+
+struct QSPEntry {
+ void *thread_ptr;
+ const QSPCallSite *callsite;
+ uint64_t n_acqs;
+ uint64_t ns;
+ unsigned int n_objs; /* count of coalesced objs; only used for reporting */
+#ifndef CONFIG_ATOMIC64
+ /*
+ * If we cannot update the counts atomically, then use a seqlock.
+ * We don't need an associated lock because the updates are thread-local.
+ */
+ QemuSeqLock sequence;
+#endif
+};
+typedef struct QSPEntry QSPEntry;
+
+struct QSPSnapshot {
+ struct rcu_head rcu;
+ struct qht ht;
+};
+typedef struct QSPSnapshot QSPSnapshot;
+
+/* initial sizing for hash tables */
+#define QSP_INITIAL_SIZE 64
+
+/* If this file is moved, QSP_REL_PATH should be updated accordingly */
+#define QSP_REL_PATH "util/qsp.c"
+
+/* this file's full path. Used to present all call sites with relative paths */
+static size_t qsp_qemu_path_len;
+
+/* the address of qsp_thread gives us a unique 'thread ID' */
+static __thread int qsp_thread;
+
+/*
+ * Call sites are the same for all threads, so we track them in a separate hash
+ * table to save memory.
+ */
+static struct qht qsp_callsite_ht;
+
+static struct qht qsp_ht;
+static QSPSnapshot *qsp_snapshot;
+static bool qsp_initialized, qsp_initializing;
+
+static const char * const qsp_typenames[] = {
+ [QSP_MUTEX] = "mutex",
+ [QSP_BQL_MUTEX] = "BQL mutex",
+ [QSP_REC_MUTEX] = "rec_mutex",
+ [QSP_CONDVAR] = "condvar",
+};
+
+QemuMutexLockFunc qemu_bql_mutex_lock_func = qemu_mutex_lock_impl;
+QemuMutexLockFunc qemu_mutex_lock_func = qemu_mutex_lock_impl;
+QemuMutexTrylockFunc qemu_mutex_trylock_func = qemu_mutex_trylock_impl;
+QemuRecMutexLockFunc qemu_rec_mutex_lock_func = qemu_rec_mutex_lock_impl;
+QemuRecMutexTrylockFunc qemu_rec_mutex_trylock_func =
+ qemu_rec_mutex_trylock_impl;
+QemuCondWaitFunc qemu_cond_wait_func = qemu_cond_wait_impl;
+
+/*
+ * It pays off to _not_ hash callsite->file; hashing a string is slow, and
+ * without it we still get a pretty unique hash.
+ */
+static inline
+uint32_t do_qsp_callsite_hash(const QSPCallSite *callsite, uint64_t a)
+{
+ uint64_t b = (uint64_t)(uintptr_t)callsite->obj;
+ uint32_t e = callsite->line;
+ uint32_t f = callsite->type;
+
+ return tb_hash_func7(a, b, e, f, 0);
+}
+
+static inline
+uint32_t qsp_callsite_hash(const QSPCallSite *callsite)
+{
+ return do_qsp_callsite_hash(callsite, 0);
+}
+
+static inline uint32_t do_qsp_entry_hash(const QSPEntry *entry, uint64_t a)
+{
+ return do_qsp_callsite_hash(entry->callsite, a);
+}
+
+static uint32_t qsp_entry_hash(const QSPEntry *entry)
+{
+ return do_qsp_entry_hash(entry, (uint64_t)(uintptr_t)entry->thread_ptr);
+}
+
+static uint32_t qsp_entry_no_thread_hash(const QSPEntry *entry)
+{
+ return do_qsp_entry_hash(entry, 0);
+}
+
+/* without the objects we need to hash the file name to get a decent hash */
+static uint32_t qsp_entry_no_thread_obj_hash(const QSPEntry *entry)
+{
+ const QSPCallSite *callsite = entry->callsite;
+ uint64_t a = g_str_hash(callsite->file);
+ uint64_t b = callsite->line;
+ uint32_t e = callsite->type;
+
+ return tb_hash_func7(a, b, e, 0, 0);
+}
+
+static bool qsp_callsite_cmp(const void *ap, const void *bp)
+{
+ const QSPCallSite *a = ap;
+ const QSPCallSite *b = bp;
+
+ return a == b ||
+ (a->obj == b->obj &&
+ a->line == b->line &&
+ a->type == b->type &&
+ (a->file == b->file || !strcmp(a->file, b->file)));
+}
+
+static bool qsp_callsite_no_obj_cmp(const void *ap, const void *bp)
+{
+ const QSPCallSite *a = ap;
+ const QSPCallSite *b = bp;
+
+ return a == b ||
+ (a->line == b->line &&
+ a->type == b->type &&
+ (a->file == b->file || !strcmp(a->file, b->file)));
+}
+
+static bool qsp_entry_no_thread_cmp(const void *ap, const void *bp)
+{
+ const QSPEntry *a = ap;
+ const QSPEntry *b = bp;
+
+ return qsp_callsite_cmp(a->callsite, b->callsite);
+}
+
+static bool qsp_entry_no_thread_obj_cmp(const void *ap, const void *bp)
+{
+ const QSPEntry *a = ap;
+ const QSPEntry *b = bp;
+
+ return qsp_callsite_no_obj_cmp(a->callsite, b->callsite);
+}
+
+static bool qsp_entry_cmp(const void *ap, const void *bp)
+{
+ const QSPEntry *a = ap;
+ const QSPEntry *b = bp;
+
+ return a->thread_ptr == b->thread_ptr &&
+ qsp_callsite_cmp(a->callsite, b->callsite);
+}
+
+/*
+ * Normally we'd call this from a constructor function, but we want it to work
+ * via libutil as well.
+ */
+static void qsp_do_init(void)
+{
+ /* make sure this file's path in the tree is up to date with QSP_REL_PATH */
+ g_assert(strstr(__FILE__, QSP_REL_PATH));
+ qsp_qemu_path_len = strlen(__FILE__) - strlen(QSP_REL_PATH);
+
+ qht_init(&qsp_ht, qsp_entry_cmp, QSP_INITIAL_SIZE,
+ QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
+ qht_init(&qsp_callsite_ht, qsp_callsite_cmp, QSP_INITIAL_SIZE,
+ QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
+}
+
+static __attribute__((noinline)) void qsp_init__slowpath(void)
+{
+ if (atomic_cmpxchg(&qsp_initializing, false, true) == false) {
+ qsp_do_init();
+ atomic_set(&qsp_initialized, true);
+ } else {
+ while (!atomic_read(&qsp_initialized)) {
+ cpu_relax();
+ }
+ }
+}
+
+/* qsp_init() must be called from _all_ exported functions */
+static inline void qsp_init(void)
+{
+ if (likely(atomic_read(&qsp_initialized))) {
+ return;
+ }
+ qsp_init__slowpath();
+}
+
+static QSPCallSite *qsp_callsite_find(const QSPCallSite *orig)
+{
+ QSPCallSite *callsite;
+ uint32_t hash;
+
+ hash = qsp_callsite_hash(orig);
+ callsite = qht_lookup(&qsp_callsite_ht, orig, hash);
+ if (callsite == NULL) {
+ void *existing = NULL;
+
+ callsite = g_new(QSPCallSite, 1);
+ memcpy(callsite, orig, sizeof(*callsite));
+ qht_insert(&qsp_callsite_ht, callsite, hash, &existing);
+ if (unlikely(existing)) {
+ g_free(callsite);
+ callsite = existing;
+ }
+ }
+ return callsite;
+}
+
+static QSPEntry *
+qsp_entry_create(struct qht *ht, const QSPEntry *entry, uint32_t hash)
+{
+ QSPEntry *e;
+ void *existing = NULL;
+
+ e = g_new0(QSPEntry, 1);
+ e->thread_ptr = entry->thread_ptr;
+ e->callsite = qsp_callsite_find(entry->callsite);
+
+ qht_insert(ht, e, hash, &existing);
+ if (unlikely(existing)) {
+ g_free(e);
+ e = existing;
+ }
+ return e;
+}
+
+static QSPEntry *
+qsp_entry_find(struct qht *ht, const QSPEntry *entry, uint32_t hash)
+{
+ QSPEntry *e;
+
+ e = qht_lookup(ht, entry, hash);
+ if (e == NULL) {
+ e = qsp_entry_create(ht, entry, hash);
+ }
+ return e;
+}
+
+/*
+ * Note: Entries are never removed, so callers do not have to be in an RCU
+ * read-side critical section.
+ */
+static QSPEntry *qsp_entry_get(const void *obj, const char *file, int line,
+ enum QSPType type)
+{
+ QSPCallSite callsite = {
+ .obj = obj,
+ .file = file,
+ .line = line,
+ .type = type,
+ };
+ QSPEntry orig;
+ uint32_t hash;
+
+ qsp_init();
+
+ orig.thread_ptr = &qsp_thread;
+ orig.callsite = &callsite;
+
+ hash = qsp_entry_hash(&orig);
+ return qsp_entry_find(&qsp_ht, &orig, hash);
+}
+
+/*
+ * @from is in the global hash table; read it atomically if the host
+ * supports it, otherwise use the seqlock.
+ */
+static void qsp_entry_aggregate(QSPEntry *to, const QSPEntry *from)
+{
+#ifdef CONFIG_ATOMIC64
+ to->ns += atomic_read__nocheck(&from->ns);
+ to->n_acqs += atomic_read__nocheck(&from->n_acqs);
+#else
+ unsigned int version;
+ uint64_t ns, n_acqs;
+
+ do {
+ version = seqlock_read_begin(&from->sequence);
+ ns = atomic_read__nocheck(&from->ns);
+ n_acqs = atomic_read__nocheck(&from->n_acqs);
+ } while (seqlock_read_retry(&from->sequence, version));
+
+ to->ns += ns;
+ to->n_acqs += n_acqs;
+#endif
+}
+
+/*
+ * @e is in the global hash table; it is only written to by the current thread,
+ * so we write to it atomically (as in "write once") to prevent torn reads.
+ * If the host doesn't support u64 atomics, use the seqlock.
+ */
+static inline void do_qsp_entry_record(QSPEntry *e, int64_t delta, bool acq)
+{
+#ifndef CONFIG_ATOMIC64
+ seqlock_write_begin(&e->sequence);
+#endif
+ atomic_set__nocheck(&e->ns, e->ns + delta);
+ if (acq) {
+ atomic_set__nocheck(&e->n_acqs, e->n_acqs + 1);
+ }
+#ifndef CONFIG_ATOMIC64
+ seqlock_write_end(&e->sequence);
+#endif
+}
+
+static inline void qsp_entry_record(QSPEntry *e, int64_t delta)
+{
+ do_qsp_entry_record(e, delta, true);
+}
+
+#define QSP_GEN_VOID(type_, qsp_t_, func_, impl_) \
+ static void func_(type_ *obj, const char *file, int line) \
+ { \
+ QSPEntry *e; \
+ int64_t t0, t1; \
+ \
+ t0 = get_clock(); \
+ impl_(obj, file, line); \
+ t1 = get_clock(); \
+ \
+ e = qsp_entry_get(obj, file, line, qsp_t_); \
+ qsp_entry_record(e, t1 - t0); \
+ }
+
+#define QSP_GEN_RET1(type_, qsp_t_, func_, impl_) \
+ static int func_(type_ *obj, const char *file, int line) \
+ { \
+ QSPEntry *e; \
+ int64_t t0, t1; \
+ int err; \
+ \
+ t0 = get_clock(); \
+ err = impl_(obj, file, line); \
+ t1 = get_clock(); \
+ \
+ e = qsp_entry_get(obj, file, line, qsp_t_); \
+ do_qsp_entry_record(e, t1 - t0, !err); \
+ return err; \
+ }
+
+QSP_GEN_VOID(QemuMutex, QSP_BQL_MUTEX, qsp_bql_mutex_lock, qemu_mutex_lock_impl)
+QSP_GEN_VOID(QemuMutex, QSP_MUTEX, qsp_mutex_lock, qemu_mutex_lock_impl)
+QSP_GEN_RET1(QemuMutex, QSP_MUTEX, qsp_mutex_trylock, qemu_mutex_trylock_impl)
+
+QSP_GEN_VOID(QemuRecMutex, QSP_REC_MUTEX, qsp_rec_mutex_lock,
+ qemu_rec_mutex_lock_impl)
+QSP_GEN_RET1(QemuRecMutex, QSP_REC_MUTEX, qsp_rec_mutex_trylock,
+ qemu_rec_mutex_trylock_impl)
+
+#undef QSP_GEN_RET1
+#undef QSP_GEN_VOID
+
+static void
+qsp_cond_wait(QemuCond *cond, QemuMutex *mutex, const char *file, int line)
+{
+ QSPEntry *e;
+ int64_t t0, t1;
+
+ t0 = get_clock();
+ qemu_cond_wait_impl(cond, mutex, file, line);
+ t1 = get_clock();
+
+ e = qsp_entry_get(cond, file, line, QSP_CONDVAR);
+ qsp_entry_record(e, t1 - t0);
+}
+
+bool qsp_is_enabled(void)
+{
+ return atomic_read(&qemu_mutex_lock_func) == qsp_mutex_lock;
+}
+
+void qsp_enable(void)
+{
+ atomic_set(&qemu_mutex_lock_func, qsp_mutex_lock);
+ atomic_set(&qemu_mutex_trylock_func, qsp_mutex_trylock);
+ atomic_set(&qemu_bql_mutex_lock_func, qsp_bql_mutex_lock);
+ atomic_set(&qemu_rec_mutex_lock_func, qsp_rec_mutex_lock);
+ atomic_set(&qemu_rec_mutex_trylock_func, qsp_rec_mutex_trylock);
+ atomic_set(&qemu_cond_wait_func, qsp_cond_wait);
+}
+
+void qsp_disable(void)
+{
+ atomic_set(&qemu_mutex_lock_func, qemu_mutex_lock_impl);
+ atomic_set(&qemu_mutex_trylock_func, qemu_mutex_trylock_impl);
+ atomic_set(&qemu_bql_mutex_lock_func, qemu_mutex_lock_impl);
+ atomic_set(&qemu_rec_mutex_lock_func, qemu_rec_mutex_lock_impl);
+ atomic_set(&qemu_rec_mutex_trylock_func, qemu_rec_mutex_trylock_impl);
+ atomic_set(&qemu_cond_wait_func, qemu_cond_wait_impl);
+}
+
+static gint qsp_tree_cmp(gconstpointer ap, gconstpointer bp, gpointer up)
+{
+ const QSPEntry *a = ap;
+ const QSPEntry *b = bp;
+ enum QSPSortBy sort_by = *(enum QSPSortBy *)up;
+ const QSPCallSite *ca;
+ const QSPCallSite *cb;
+
+ switch (sort_by) {
+ case QSP_SORT_BY_TOTAL_WAIT_TIME:
+ if (a->ns > b->ns) {
+ return -1;
+ } else if (a->ns < b->ns) {
+ return 1;
+ }
+ break;
+ case QSP_SORT_BY_AVG_WAIT_TIME:
+ {
+ double avg_a = a->n_acqs ? a->ns / a->n_acqs : 0;
+ double avg_b = b->n_acqs ? b->ns / b->n_acqs : 0;
+
+ if (avg_a > avg_b) {
+ return -1;
+ } else if (avg_a < avg_b) {
+ return 1;
+ }
+ break;
+ }
+ default:
+ g_assert_not_reached();
+ }
+
+ ca = a->callsite;
+ cb = b->callsite;
+ /* Break the tie with the object's address */
+ if (ca->obj < cb->obj) {
+ return -1;
+ } else if (ca->obj > cb->obj) {
+ return 1;
+ } else {
+ int cmp;
+
+ /* same obj. Break the tie with the callsite's file */
+ cmp = strcmp(ca->file, cb->file);
+ if (cmp) {
+ return cmp;
+ }
+ /* same callsite file. Break the tie with the callsite's line */
+ g_assert(ca->line != cb->line);
+ if (ca->line < cb->line) {
+ return -1;
+ } else if (ca->line > cb->line) {
+ return 1;
+ } else {
+ /* break the tie with the callsite's type */
+ return cb->type - ca->type;
+ }
+ }
+}
+
+static void qsp_sort(struct qht *ht, void *p, uint32_t h, void *userp)
+{
+ QSPEntry *e = p;
+ GTree *tree = userp;
+
+ g_tree_insert(tree, e, NULL);
+}
+
+static void qsp_aggregate(struct qht *global_ht, void *p, uint32_t h, void *up)
+{
+ struct qht *ht = up;
+ const QSPEntry *e = p;
+ QSPEntry *agg;
+ uint32_t hash;
+
+ hash = qsp_entry_no_thread_hash(e);
+ agg = qsp_entry_find(ht, e, hash);
+ qsp_entry_aggregate(agg, e);
+}
+
+static void qsp_iter_diff(struct qht *orig, void *p, uint32_t hash, void *htp)
+{
+ struct qht *ht = htp;
+ QSPEntry *old = p;
+ QSPEntry *new;
+
+ new = qht_lookup(ht, old, hash);
+ /* entries are never deleted, so we must have this one */
+ g_assert(new != NULL);
+ /* our reading of the stats happened after the snapshot was taken */
+ g_assert(new->n_acqs >= old->n_acqs);
+ g_assert(new->ns >= old->ns);
+
+ new->n_acqs -= old->n_acqs;
+ new->ns -= old->ns;
+
+ /* No point in reporting an empty entry */
+ if (new->n_acqs == 0 && new->ns == 0) {
+ bool removed = qht_remove(ht, new, hash);
+
+ g_assert(removed);
+ g_free(new);
+ }
+}
+
+static void qsp_diff(struct qht *orig, struct qht *new)
+{
+ qht_iter(orig, qsp_iter_diff, new);
+}
+
+static void
+qsp_iter_callsite_coalesce(struct qht *orig, void *p, uint32_t h, void *htp)
+{
+ struct qht *ht = htp;
+ QSPEntry *old = p;
+ QSPEntry *e;
+ uint32_t hash;
+
+ hash = qsp_entry_no_thread_obj_hash(old);
+ e = qht_lookup(ht, old, hash);
+ if (e == NULL) {
+ e = qsp_entry_create(ht, old, hash);
+ e->n_objs = 1;
+ } else if (e->callsite->obj != old->callsite->obj) {
+ e->n_objs++;
+ }
+ e->ns += old->ns;
+ e->n_acqs += old->n_acqs;
+}
+
+static void qsp_ht_delete(struct qht *ht, void *p, uint32_t h, void *htp)
+{
+ g_free(p);
+}
+
+static void qsp_mktree(GTree *tree, bool callsite_coalesce)
+{
+ QSPSnapshot *snap;
+ struct qht ht, coalesce_ht;
+ struct qht *htp;
+
+ /*
+ * First, see if there's a prior snapshot, so that we read the global hash
+ * table _after_ the snapshot has been created, which guarantees that
+ * the entries we'll read will be a superset of the snapshot's entries.
+ *
+ * We must remain in an RCU read-side critical section until we're done
+ * with the snapshot.
+ */
+ rcu_read_lock();
+ snap = atomic_rcu_read(&qsp_snapshot);
+
+ /* Aggregate all results from the global hash table into a local one */
+ qht_init(&ht, qsp_entry_no_thread_cmp, QSP_INITIAL_SIZE,
+ QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
+ qht_iter(&qsp_ht, qsp_aggregate, &ht);
+
+ /* compute the difference wrt the snapshot, if any */
+ if (snap) {
+ qsp_diff(&snap->ht, &ht);
+ }
+ /* done with the snapshot; RCU can reclaim it */
+ rcu_read_unlock();
+
+ htp = &ht;
+ if (callsite_coalesce) {
+ qht_init(&coalesce_ht, qsp_entry_no_thread_obj_cmp, QSP_INITIAL_SIZE,
+ QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
+ qht_iter(&ht, qsp_iter_callsite_coalesce, &coalesce_ht);
+
+ /* free the previous hash table, and point htp to coalesce_ht */
+ qht_iter(&ht, qsp_ht_delete, NULL);
+ qht_destroy(&ht);
+ htp = &coalesce_ht;
+ }
+
+ /* sort the hash table elements by using a tree */
+ qht_iter(htp, qsp_sort, tree);
+
+ /* free the hash table, but keep the elements (those are in the tree now) */
+ qht_destroy(htp);
+}
+
+/* free string with g_free */
+static char *qsp_at(const QSPCallSite *callsite)
+{
+ GString *s = g_string_new(NULL);
+ const char *shortened;
+
+ /* remove the absolute path to qemu */
+ if (unlikely(strlen(callsite->file) < qsp_qemu_path_len)) {
+ shortened = callsite->file;
+ } else {
+ shortened = callsite->file + qsp_qemu_path_len;
+ }
+ g_string_append_printf(s, "%s:%u", shortened, callsite->line);
+ return g_string_free(s, FALSE);
+}
+
+struct QSPReportEntry {
+ const void *obj;
+ char *callsite_at;
+ const char *typename;
+ double time_s;
+ double ns_avg;
+ uint64_t n_acqs;
+ unsigned int n_objs;
+};
+typedef struct QSPReportEntry QSPReportEntry;
+
+struct QSPReport {
+ QSPReportEntry *entries;
+ size_t n_entries;
+ size_t max_n_entries;
+};
+typedef struct QSPReport QSPReport;
+
+static gboolean qsp_tree_report(gpointer key, gpointer value, gpointer udata)
+{
+ const QSPEntry *e = key;
+ QSPReport *report = udata;
+ QSPReportEntry *entry;
+
+ if (report->n_entries == report->max_n_entries) {
+ return TRUE;
+ }
+ entry = &report->entries[report->n_entries];
+ report->n_entries++;
+
+ entry->obj = e->callsite->obj;
+ entry->n_objs = e->n_objs;
+ entry->callsite_at = qsp_at(e->callsite);
+ entry->typename = qsp_typenames[e->callsite->type];
+ entry->time_s = e->ns * 1e-9;
+ entry->n_acqs = e->n_acqs;
+ entry->ns_avg = e->n_acqs ? e->ns / e->n_acqs : 0;
+ return FALSE;
+}
+
+static void
+pr_report(const QSPReport *rep, FILE *f, fprintf_function pr)
+{
+ char *dashes;
+ size_t max_len = 0;
+ int callsite_len = 0;
+ int callsite_rspace;
+ int n_dashes;
+ size_t i;
+
+ /* find out the maximum length of all 'callsite' fields */
+ for (i = 0; i < rep->n_entries; i++) {
+ const QSPReportEntry *e = &rep->entries[i];
+ size_t len = strlen(e->callsite_at);
+
+ if (len > max_len) {
+ max_len = len;
+ }
+ }
+
+ callsite_len = MAX(max_len, strlen("Call site"));
+ /* white space to leave to the right of "Call site" */
+ callsite_rspace = callsite_len - strlen("Call site");
+
+ pr(f, "Type Object Call site%*s Wait Time (s) "
+ " Count Average (us)\n", callsite_rspace, "");
+
+ /* build a horizontal rule with dashes */
+ n_dashes = 79 + callsite_rspace;
+ dashes = g_malloc(n_dashes + 1);
+ memset(dashes, '-', n_dashes);
+ dashes[n_dashes] = '\0';
+ pr(f, "%s\n", dashes);
+
+ for (i = 0; i < rep->n_entries; i++) {
+ const QSPReportEntry *e = &rep->entries[i];
+ GString *s = g_string_new(NULL);
+
+ g_string_append_printf(s, "%-9s ", e->typename);
+ if (e->n_objs > 1) {
+ g_string_append_printf(s, "[%12u]", e->n_objs);
+ } else {
+ g_string_append_printf(s, "%14p", e->obj);
+ }
+ g_string_append_printf(s, " %s%*s %13.5f %12" PRIu64 " %12.2f\n",
+ e->callsite_at,
+ callsite_len - (int)strlen(e->callsite_at), "",
+ e->time_s, e->n_acqs, e->ns_avg * 1e-3);
+ pr(f, "%s", s->str);
+ g_string_free(s, TRUE);
+ }
+
+ pr(f, "%s\n", dashes);
+ g_free(dashes);
+}
+
+static void report_destroy(QSPReport *rep)
+{
+ size_t i;
+
+ for (i = 0; i < rep->n_entries; i++) {
+ QSPReportEntry *e = &rep->entries[i];
+
+ g_free(e->callsite_at);
+ }
+ g_free(rep->entries);
+}
+
+void qsp_report(FILE *f, fprintf_function cpu_fprintf, size_t max,
+ enum QSPSortBy sort_by, bool callsite_coalesce)
+{
+ GTree *tree = g_tree_new_full(qsp_tree_cmp, &sort_by, g_free, NULL);
+ QSPReport rep;
+
+ qsp_init();
+
+ rep.entries = g_new0(QSPReportEntry, max);
+ rep.n_entries = 0;
+ rep.max_n_entries = max;
+
+ qsp_mktree(tree, callsite_coalesce);
+ g_tree_foreach(tree, qsp_tree_report, &rep);
+ g_tree_destroy(tree);
+
+ pr_report(&rep, f, cpu_fprintf);
+ report_destroy(&rep);
+}
+
+static void qsp_snapshot_destroy(QSPSnapshot *snap)
+{
+ qht_iter(&snap->ht, qsp_ht_delete, NULL);
+ qht_destroy(&snap->ht);
+ g_free(snap);
+}
+
+void qsp_reset(void)
+{
+ QSPSnapshot *new = g_new(QSPSnapshot, 1);
+ QSPSnapshot *old;
+
+ qsp_init();
+
+ qht_init(&new->ht, qsp_entry_cmp, QSP_INITIAL_SIZE,
+ QHT_MODE_AUTO_RESIZE | QHT_MODE_RAW_MUTEXES);
+
+ /* take a snapshot of the current state */
+ qht_iter(&qsp_ht, qsp_aggregate, &new->ht);
+
+ /* replace the previous snapshot, if any */
+ old = atomic_xchg(&qsp_snapshot, new);
+ if (old) {
+ call_rcu(old, qsp_snapshot_destroy, rcu);
+ }
+}
diff --git a/vl.c b/vl.c
index 16b913f9d5..5ba06adf78 100644
--- a/vl.c
+++ b/vl.c
@@ -2987,6 +2987,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_object_opts);
qemu_add_opts(&qemu_tpmdev_opts);
qemu_add_opts(&qemu_realtime_opts);
+ qemu_add_opts(&qemu_overcommit_opts);
qemu_add_opts(&qemu_msg_opts);
qemu_add_opts(&qemu_name_opts);
qemu_add_opts(&qemu_numa_opts);
@@ -3959,6 +3960,9 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
+ case QEMU_OPTION_enable_sync_profile:
+ qsp_enable();
+ break;
case QEMU_OPTION_nodefconfig:
case QEMU_OPTION_nouserconfig:
/* Nothing to be parsed here. Especially, do not error out below. */
@@ -4559,11 +4563,10 @@ int main(int argc, char **argv, char **envp)
* (2) CONFIG_SLIRP not set, in which case the implicit "-net nic"
* sets up a nic that isn't connected to anything.
*/
- if (!default_net) {
+ if (!default_net && (!qtest_enabled() || has_defaults)) {
net_check_clients();
}
-
if (boot_once) {
qemu_boot_set(boot_once, &error_fatal);
qemu_register_reset(restore_boot_order, g_strdup(boot_order));