diff options
-rw-r--r-- | .gdbinit | 8 | ||||
-rw-r--r-- | block/block-backend.c | 2 | ||||
-rw-r--r-- | block/commit.c | 7 | ||||
-rw-r--r-- | block/nbd-client.c | 41 | ||||
-rw-r--r-- | block/qcow.c | 1 | ||||
-rw-r--r-- | blockdev.c | 4 | ||||
-rw-r--r-- | chardev/char.c | 4 | ||||
-rwxr-xr-x | configure | 79 | ||||
-rw-r--r-- | cpus.c | 2 | ||||
-rw-r--r-- | disas/libvixl/Makefile.objs | 4 | ||||
-rw-r--r-- | docs/config/ich9-ehci-uhci.cfg (renamed from docs/ich9-ehci-uhci.cfg) | 0 | ||||
-rw-r--r-- | docs/config/mach-virt-graphical.cfg (renamed from docs/mach-virt-graphical.cfg) | 0 | ||||
-rw-r--r-- | docs/config/mach-virt-serial.cfg (renamed from docs/mach-virt-serial.cfg) | 0 | ||||
-rw-r--r-- | docs/config/q35-emulated.cfg (renamed from docs/q35-emulated.cfg) | 0 | ||||
-rw-r--r-- | docs/config/q35-virtio-graphical.cfg (renamed from docs/q35-virtio-graphical.cfg) | 0 | ||||
-rw-r--r-- | docs/config/q35-virtio-serial.cfg (renamed from docs/q35-virtio-serial.cfg) | 0 | ||||
-rw-r--r-- | docs/devel/atomics.txt (renamed from docs/atomics.txt) | 0 | ||||
-rw-r--r-- | docs/devel/bitmaps.md (renamed from docs/bitmaps.md) | 0 | ||||
-rw-r--r-- | docs/devel/blkdebug.txt (renamed from docs/blkdebug.txt) | 0 | ||||
-rw-r--r-- | docs/devel/blkverify.txt (renamed from docs/blkverify.txt) | 0 | ||||
-rw-r--r-- | docs/devel/build-system.txt (renamed from docs/build-system.txt) | 0 | ||||
-rw-r--r-- | docs/devel/lockcnt.txt (renamed from docs/lockcnt.txt) | 0 | ||||
-rw-r--r-- | docs/devel/memory.txt (renamed from docs/memory.txt) | 0 | ||||
-rw-r--r-- | docs/devel/migration.txt (renamed from docs/migration.txt) | 0 | ||||
-rw-r--r-- | docs/devel/multi-thread-tcg.txt (renamed from docs/multi-thread-tcg.txt) | 0 | ||||
-rw-r--r-- | docs/devel/multiple-iothreads.txt (renamed from docs/multiple-iothreads.txt) | 0 | ||||
-rw-r--r-- | docs/devel/qapi-code-gen.txt (renamed from docs/qapi-code-gen.txt) | 0 | ||||
-rw-r--r-- | docs/devel/rcu.txt (renamed from docs/rcu.txt) | 0 | ||||
-rw-r--r-- | docs/devel/tracing.txt (renamed from docs/tracing.txt) | 0 | ||||
-rw-r--r-- | docs/devel/virtio-migration.txt (renamed from docs/virtio-migration.txt) | 0 | ||||
-rw-r--r-- | docs/devel/writing-qmp-commands.txt (renamed from docs/writing-qmp-commands.txt) | 0 | ||||
-rw-r--r-- | docs/spin/aio_notify.promela (renamed from docs/aio_notify.promela) | 0 | ||||
-rw-r--r-- | docs/spin/aio_notify_accept.promela (renamed from docs/aio_notify_accept.promela) | 0 | ||||
-rw-r--r-- | docs/spin/aio_notify_bug.promela (renamed from docs/aio_notify_bug.promela) | 0 | ||||
-rw-r--r-- | docs/spin/tcg-exclusive.promela (renamed from docs/tcg-exclusive.promela) | 0 | ||||
-rw-r--r-- | docs/spin/win32-qemu-event.promela (renamed from docs/win32-qemu-event.promela) | 0 | ||||
-rw-r--r-- | exec.c | 13 | ||||
-rw-r--r-- | gdb-xml/i386-32bit-sse.xml | 52 | ||||
-rw-r--r-- | gdb-xml/i386-32bit.xml | 14 | ||||
-rw-r--r-- | gdb-xml/i386-64bit-sse.xml | 60 | ||||
-rw-r--r-- | gdb-xml/i386-64bit.xml | 14 | ||||
-rw-r--r-- | hw/acpi/nvdimm.c | 7 | ||||
-rw-r--r-- | hw/i386/kvm/clock.c | 3 | ||||
-rw-r--r-- | hw/misc/edu.c | 12 | ||||
-rw-r--r-- | hw/pci-bridge/gen_pcie_root_port.c | 25 | ||||
-rw-r--r-- | hw/pci/msix.c | 11 | ||||
-rw-r--r-- | hw/pci/trace-events | 3 | ||||
-rw-r--r-- | hw/s390x/css.c | 19 | ||||
-rw-r--r-- | hw/s390x/virtio-ccw.c | 6 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 3 | ||||
-rw-r--r-- | hw/timer/mc146818rtc.c | 203 | ||||
-rw-r--r-- | include/block/nbd.h | 8 | ||||
-rw-r--r-- | include/chardev/char-parallel.h | 5 | ||||
-rw-r--r-- | include/chardev/char-serial.h | 8 | ||||
-rw-r--r-- | include/hw/compat.h | 4 | ||||
-rw-r--r-- | include/hw/s390x/ioinst.h | 1 | ||||
-rw-r--r-- | include/hw/timer/mc146818rtc_regs.h | 20 | ||||
-rw-r--r-- | include/qemu/osdep.h | 13 | ||||
-rw-r--r-- | kvm-all.c | 8 | ||||
-rw-r--r-- | migration/block.c | 22 | ||||
-rw-r--r-- | migration/migration.c | 12 | ||||
-rw-r--r-- | nbd/client.c | 125 | ||||
-rw-r--r-- | nbd/common.c | 23 | ||||
-rw-r--r-- | nbd/nbd-internal.h | 40 | ||||
-rw-r--r-- | nbd/server.c | 100 | ||||
-rw-r--r-- | pc-bios/linuxboot_dma.bin | bin | 1536 -> 1536 bytes | |||
-rw-r--r-- | pc-bios/optionrom/Makefile | 1 | ||||
-rw-r--r-- | pc-bios/s390-ccw/Makefile | 4 | ||||
-rw-r--r-- | qemu-nbd.c | 5 | ||||
-rw-r--r-- | rules.mak | 3 | ||||
-rw-r--r-- | scripts/coccinelle/return_directly.cocci | 2 | ||||
-rwxr-xr-x | scripts/simpletrace.py | 10 | ||||
-rw-r--r-- | target/i386/arch_memory_mapping.c | 18 | ||||
-rw-r--r-- | target/i386/cpu.c | 23 | ||||
-rw-r--r-- | target/i386/cpu.h | 20 | ||||
-rw-r--r-- | target/i386/helper.c | 96 | ||||
-rw-r--r-- | target/i386/kvm.c | 36 | ||||
-rw-r--r-- | target/i386/machine.c | 4 | ||||
-rw-r--r-- | target/i386/smm_helper.c | 18 | ||||
-rw-r--r-- | target/i386/translate.c | 12 | ||||
-rw-r--r-- | target/s390x/cpu_models.c | 10 | ||||
-rw-r--r-- | target/s390x/cpu_models.h | 10 | ||||
-rw-r--r-- | target/s390x/ioinst.c | 4 | ||||
-rw-r--r-- | target/s390x/kvm.c | 1 | ||||
-rwxr-xr-x | tests/qemu-iotests/040 | 35 | ||||
-rw-r--r-- | tests/qemu-iotests/040.out | 4 | ||||
-rw-r--r-- | tests/qemu-iotests/083.out | 2 | ||||
-rwxr-xr-x | tests/qemu-iotests/183 | 140 | ||||
-rw-r--r-- | tests/qemu-iotests/183.out | 46 | ||||
-rw-r--r-- | tests/qemu-iotests/group | 1 | ||||
-rw-r--r-- | tests/rtc-test.c | 49 | ||||
-rw-r--r-- | tests/test-char.c | 29 | ||||
-rw-r--r-- | tests/vhost-user-bridge.c | 11 | ||||
-rw-r--r-- | trace-events | 3 | ||||
-rw-r--r-- | util/oslib-posix.c | 6 | ||||
-rw-r--r-- | util/qemu-coroutine-lock.c | 19 | ||||
-rw-r--r-- | util/qemu-coroutine.c | 5 | ||||
-rw-r--r-- | util/qemu-sockets.c | 68 |
98 files changed, 1213 insertions, 468 deletions
diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..9d322fc --- /dev/null +++ b/.gdbinit @@ -0,0 +1,8 @@ +# GDB may have ./.gdbinit loading disabled by default. In that case you can +# follow the instructions it prints. They boil down to adding the following to +# your home directory's ~/.gdbinit file: +# +# add-auto-load-safe-path /path/to/qemu/.gdbinit + +# Load QEMU-specific sub-commands and settings +source scripts/qemu-gdb.py diff --git a/block/block-backend.c b/block/block-backend.c index f3a6008..7d7f369 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -168,7 +168,7 @@ static int blk_root_inactivate(BdrvChild *child) * this point because the VM is stopped) and unattached monitor-owned * BlockBackends. If there is still any other user like a block job, then * we simply can't inactivate the image. */ - if (!blk->dev && !blk->name[0]) { + if (!blk->dev && !blk_name(blk)[0]) { return -EPERM; } diff --git a/block/commit.c b/block/commit.c index a3028b2..af6fa68 100644 --- a/block/commit.c +++ b/block/commit.c @@ -89,6 +89,10 @@ static void commit_complete(BlockJob *job, void *opaque) int ret = data->ret; bool remove_commit_top_bs = false; + /* Make sure overlay_bs and top stay around until bdrv_set_backing_hd() */ + bdrv_ref(top); + bdrv_ref(overlay_bs); + /* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before * the normal backing chain can be restored. */ blk_unref(s->base); @@ -124,6 +128,9 @@ static void commit_complete(BlockJob *job, void *opaque) if (remove_commit_top_bs) { bdrv_set_backing_hd(overlay_bs, top, &error_abort); } + + bdrv_unref(overlay_bs); + bdrv_unref(top); } static void coroutine_fn commit_run(void *opaque) diff --git a/block/nbd-client.c b/block/nbd-client.c index 1e2952f..87d19c7 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -28,6 +28,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "nbd-client.h" #define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs)) @@ -70,10 +71,14 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) NBDClientSession *s = opaque; uint64_t i; int ret; + Error *local_err = NULL; for (;;) { assert(s->reply.handle == 0); - ret = nbd_receive_reply(s->ioc, &s->reply); + ret = nbd_receive_reply(s->ioc, &s->reply, &local_err); + if (ret < 0) { + error_report_err(local_err); + } if (ret <= 0) { break; } @@ -114,6 +119,10 @@ static int nbd_co_send_request(BlockDriverState *bs, int rc, ret, i; qemu_co_mutex_lock(&s->send_mutex); + while (s->in_flight == MAX_NBD_REQUESTS) { + qemu_co_queue_wait(&s->free_sema, &s->send_mutex); + } + s->in_flight++; for (i = 0; i < MAX_NBD_REQUESTS; i++) { if (s->recv_coroutine[i] == NULL) { @@ -136,7 +145,7 @@ static int nbd_co_send_request(BlockDriverState *bs, rc = nbd_send_request(s->ioc, request); if (rc >= 0) { ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov, request->len, - false); + false, NULL); if (ret != request->len) { rc = -EIO; } @@ -165,7 +174,7 @@ static void nbd_co_receive_reply(NBDClientSession *s, } else { if (qiov && reply->error == 0) { ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov, request->len, - true); + true, NULL); if (ret != request->len) { reply->error = EIO; } @@ -176,20 +185,6 @@ static void nbd_co_receive_reply(NBDClientSession *s, } } -static void nbd_coroutine_start(NBDClientSession *s, - NBDRequest *request) -{ - /* Poor man semaphore. The free_sema is locked when no other request - * can be accepted, and unlocked after receiving one reply. */ - if (s->in_flight == MAX_NBD_REQUESTS) { - qemu_co_queue_wait(&s->free_sema, NULL); - assert(s->in_flight < MAX_NBD_REQUESTS); - } - s->in_flight++; - - /* s->recv_coroutine[i] is set as soon as we get the send_lock. */ -} - static void nbd_coroutine_end(BlockDriverState *bs, NBDRequest *request) { @@ -197,13 +192,16 @@ static void nbd_coroutine_end(BlockDriverState *bs, int i = HANDLE_TO_INDEX(s, request->handle); s->recv_coroutine[i] = NULL; - s->in_flight--; - qemu_co_queue_next(&s->free_sema); /* Kick the read_reply_co to get the next reply. */ if (s->read_reply_co) { aio_co_wake(s->read_reply_co); } + + qemu_co_mutex_lock(&s->send_mutex); + s->in_flight--; + qemu_co_queue_next(&s->free_sema); + qemu_co_mutex_unlock(&s->send_mutex); } int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, @@ -221,7 +219,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, assert(bytes <= NBD_MAX_BUFFER_SIZE); assert(!flags); - nbd_coroutine_start(client, &request); ret = nbd_co_send_request(bs, &request, NULL); if (ret < 0) { reply.error = -ret; @@ -251,7 +248,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, assert(bytes <= NBD_MAX_BUFFER_SIZE); - nbd_coroutine_start(client, &request); ret = nbd_co_send_request(bs, &request, qiov); if (ret < 0) { reply.error = -ret; @@ -286,7 +282,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, request.flags |= NBD_CMD_FLAG_NO_HOLE; } - nbd_coroutine_start(client, &request); ret = nbd_co_send_request(bs, &request, NULL); if (ret < 0) { reply.error = -ret; @@ -311,7 +306,6 @@ int nbd_client_co_flush(BlockDriverState *bs) request.from = 0; request.len = 0; - nbd_coroutine_start(client, &request); ret = nbd_co_send_request(bs, &request, NULL); if (ret < 0) { reply.error = -ret; @@ -337,7 +331,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) return 0; } - nbd_coroutine_start(client, &request); ret = nbd_co_send_request(bs, &request, NULL); if (ret < 0) { reply.error = -ret; diff --git a/block/qcow.c b/block/qcow.c index 95ab123..7bd94dc 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -852,6 +852,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) header_size += backing_filename_len; } else { /* special backing file for vvfat */ + g_free(backing_file); backing_file = NULL; } header.cluster_bits = 9; /* 512 byte cluster to avoid copying @@ -1803,7 +1803,11 @@ static void external_snapshot_abort(BlkActionState *common) DO_UPCAST(ExternalSnapshotState, common, common); if (state->new_bs) { if (state->overlay_appended) { + bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd() + close state->old_bs; we need it */ + bdrv_set_backing_hd(state->new_bs, NULL, &error_abort); bdrv_replace_node(state->new_bs, state->old_bs, &error_abort); + bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */ } } } diff --git a/chardev/char.c b/chardev/char.c index 7aa0210..bcfc065 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -450,12 +450,12 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) } if (strstart(filename, "/dev/parport", NULL) || strstart(filename, "/dev/ppi", NULL)) { - qemu_opt_set(opts, "backend", "parport", &error_abort); + qemu_opt_set(opts, "backend", "parallel", &error_abort); qemu_opt_set(opts, "path", filename, &error_abort); return opts; } if (strstart(filename, "/dev/", NULL)) { - qemu_opt_set(opts, "backend", "tty", &error_abort); + qemu_opt_set(opts, "backend", "serial", &error_abort); qemu_opt_set(opts, "path", filename, &error_abort); return opts; } @@ -91,7 +91,8 @@ update_cxxflags() { # Set QEMU_CXXFLAGS from QEMU_CFLAGS by filtering out those # options which some versions of GCC's C++ compiler complain about # because they only make sense for C programs. - QEMU_CXXFLAGS= + QEMU_CXXFLAGS="$QEMU_CXXFLAGS -D__STDC_LIMIT_MACROS" + for arg in $QEMU_CFLAGS; do case $arg in -Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\ @@ -345,6 +346,9 @@ for opt do --extra-cflags=*) QEMU_CFLAGS="$QEMU_CFLAGS $optarg" EXTRA_CFLAGS="$optarg" ;; + --extra-cxxflags=*) QEMU_CXXFLAGS="$QEMU_CXXFLAGS $optarg" + EXTRA_CXXFLAGS="$optarg" + ;; --extra-ldflags=*) LDFLAGS="$LDFLAGS $optarg" EXTRA_LDFLAGS="$optarg" ;; @@ -788,6 +792,8 @@ for opt do ;; --extra-cflags=*) ;; + --extra-cxxflags=*) + ;; --extra-ldflags=*) ;; --enable-debug-info) @@ -1305,6 +1311,7 @@ Advanced options (experts only): --cxx=CXX use C++ compiler CXX [$cxx] --objcc=OBJCC use Objective-C compiler OBJCC [$objcc] --extra-cflags=CFLAGS append extra C compiler flags QEMU_CFLAGS + --extra-cxxflags=CXXFLAGS append extra C++ compiler flags QEMU_CXXFLAGS --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS --make=MAKE use specified make [$make] --install=INSTALL use specified install [$install] @@ -1490,37 +1497,6 @@ if test "$bogus_os" = "yes"; then error_exit "Unrecognized host OS $targetos" fi -# Check that the C++ compiler exists and works with the C compiler -if has $cxx; then - cat > $TMPC <<EOF -int c_function(void); -int main(void) { return c_function(); } -EOF - - compile_object - - cat > $TMPCXX <<EOF -extern "C" { - int c_function(void); -} -int c_function(void) { return 42; } -EOF - - update_cxxflags - - if do_cxx $QEMU_CXXFLAGS -o $TMPE $TMPCXX $TMPO $LDFLAGS; then - # C++ compiler $cxx works ok with C compiler $cc - : - else - echo "C++ compiler $cxx does not work with C compiler $cc" - echo "Disabling C++ specific optional code" - cxx= - fi -else - echo "No C++ compiler available; disabling C++ specific optional code" - cxx= -fi - gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" @@ -5064,6 +5040,38 @@ EOF fi fi +# Check that the C++ compiler exists and works with the C compiler. +# All the QEMU_CXXFLAGS are based on QEMU_CFLAGS. Keep this at the end to don't miss any other that could be added. +if has $cxx; then + cat > $TMPC <<EOF +int c_function(void); +int main(void) { return c_function(); } +EOF + + compile_object + + cat > $TMPCXX <<EOF +extern "C" { + int c_function(void); +} +int c_function(void) { return 42; } +EOF + + update_cxxflags + + if do_cxx $QEMU_CXXFLAGS -o $TMPE $TMPCXX $TMPO $LDFLAGS; then + # C++ compiler $cxx works ok with C compiler $cc + : + else + echo "C++ compiler $cxx does not work with C compiler $cc" + echo "Disabling C++ specific optional code" + cxx= + fi +else + echo "No C++ compiler available; disabling C++ specific optional code" + cxx= +fi + echo_version() { if test "$1" = "yes" ; then echo "($2)" @@ -5269,6 +5277,7 @@ if test "$mingw32" = "no" ; then fi echo "qemu_helperdir=$libexecdir" >> $config_host_mak echo "extra_cflags=$EXTRA_CFLAGS" >> $config_host_mak +echo "extra_cxxflags=$EXTRA_CXXFLAGS" >> $config_host_mak echo "extra_ldflags=$EXTRA_LDFLAGS" >> $config_host_mak echo "qemu_localedir=$qemu_localedir" >> $config_host_mak echo "libs_softmmu=$libs_softmmu" >> $config_host_mak @@ -5911,6 +5920,7 @@ echo "WINDRES=$windres" >> $config_host_mak echo "CFLAGS=$CFLAGS" >> $config_host_mak echo "CFLAGS_NOPIE=$CFLAGS_NOPIE" >> $config_host_mak echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak +echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak if test "$sparse" = "yes" ; then echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_host_mak @@ -6027,11 +6037,11 @@ TARGET_ABI_DIR="" case "$target_name" in i386) - gdb_xml_files="i386-32bit-core.xml" + gdb_xml_files="i386-32bit.xml i386-32bit-core.xml i386-32bit-sse.xml" ;; x86_64) TARGET_BASE_ARCH=i386 - gdb_xml_files="i386-64bit-core.xml" + gdb_xml_files="i386-64bit.xml i386-64bit-core.xml i386-64bit-sse.xml" ;; alpha) mttcg="yes" @@ -6376,6 +6386,7 @@ FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES pc-bios/s390-ccw/Makefile" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" FILES="$FILES pc-bios/qemu-icon.bmp" +FILES="$FILES .gdbinit scripts" # scripts needed by relative path in .gdbinit for bios_file in \ $source_path/pc-bios/*.bin \ $source_path/pc-bios/*.lid \ @@ -677,9 +677,9 @@ static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque) sleeptime_ns = (long)(throttle_ratio * CPU_THROTTLE_TIMESLICE_NS); qemu_mutex_unlock_iothread(); - atomic_set(&cpu->throttle_thread_scheduled, 0); g_usleep(sleeptime_ns / 1000); /* Convert ns to us for usleep call */ qemu_mutex_lock_iothread(); + atomic_set(&cpu->throttle_thread_scheduled, 0); } static void cpu_throttle_timer_tick(void *opaque) diff --git a/disas/libvixl/Makefile.objs b/disas/libvixl/Makefile.objs index 860fb7f..27183b7 100644 --- a/disas/libvixl/Makefile.objs +++ b/disas/libvixl/Makefile.objs @@ -6,9 +6,9 @@ libvixl_OBJS = vixl/utils.o \ # The -Wno-sign-compare is needed only for gcc 4.6, which complains about # some signed-unsigned equality comparisons which later gcc versions do not. -$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS := -I$(SRC_PATH)/disas/libvixl $(QEMU_CFLAGS) -Wno-sign-compare +$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CXXFLAGS := -I$(SRC_PATH)/disas/libvixl $(QEMU_CXXFLAGS) -Wno-sign-compare # Ensure that C99 macros are defined regardless of the inclusion order of # headers in vixl. This is required at least on NetBSD. -$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS +$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CXXFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS common-obj-$(CONFIG_ARM_A64_DIS) += $(libvixl_OBJS) diff --git a/docs/ich9-ehci-uhci.cfg b/docs/config/ich9-ehci-uhci.cfg index a0e9b96..a0e9b96 100644 --- a/docs/ich9-ehci-uhci.cfg +++ b/docs/config/ich9-ehci-uhci.cfg diff --git a/docs/mach-virt-graphical.cfg b/docs/config/mach-virt-graphical.cfg index 0fdf684..0fdf684 100644 --- a/docs/mach-virt-graphical.cfg +++ b/docs/config/mach-virt-graphical.cfg diff --git a/docs/mach-virt-serial.cfg b/docs/config/mach-virt-serial.cfg index aee9f1c..aee9f1c 100644 --- a/docs/mach-virt-serial.cfg +++ b/docs/config/mach-virt-serial.cfg diff --git a/docs/q35-emulated.cfg b/docs/config/q35-emulated.cfg index c6416d6..c6416d6 100644 --- a/docs/q35-emulated.cfg +++ b/docs/config/q35-emulated.cfg diff --git a/docs/q35-virtio-graphical.cfg b/docs/config/q35-virtio-graphical.cfg index 28bde2f..28bde2f 100644 --- a/docs/q35-virtio-graphical.cfg +++ b/docs/config/q35-virtio-graphical.cfg diff --git a/docs/q35-virtio-serial.cfg b/docs/config/q35-virtio-serial.cfg index c33c9cc..c33c9cc 100644 --- a/docs/q35-virtio-serial.cfg +++ b/docs/config/q35-virtio-serial.cfg diff --git a/docs/atomics.txt b/docs/devel/atomics.txt index 3ef5d85..3ef5d85 100644 --- a/docs/atomics.txt +++ b/docs/devel/atomics.txt diff --git a/docs/bitmaps.md b/docs/devel/bitmaps.md index a2e8d51..a2e8d51 100644 --- a/docs/bitmaps.md +++ b/docs/devel/bitmaps.md diff --git a/docs/blkdebug.txt b/docs/devel/blkdebug.txt index 43d8e8f..43d8e8f 100644 --- a/docs/blkdebug.txt +++ b/docs/devel/blkdebug.txt diff --git a/docs/blkverify.txt b/docs/devel/blkverify.txt index d556dc4..d556dc4 100644 --- a/docs/blkverify.txt +++ b/docs/devel/blkverify.txt diff --git a/docs/build-system.txt b/docs/devel/build-system.txt index 2af1e66..2af1e66 100644 --- a/docs/build-system.txt +++ b/docs/devel/build-system.txt diff --git a/docs/lockcnt.txt b/docs/devel/lockcnt.txt index 2a79b32..2a79b32 100644 --- a/docs/lockcnt.txt +++ b/docs/devel/lockcnt.txt diff --git a/docs/memory.txt b/docs/devel/memory.txt index 811b1bd..811b1bd 100644 --- a/docs/memory.txt +++ b/docs/devel/memory.txt diff --git a/docs/migration.txt b/docs/devel/migration.txt index 1b940a8..1b940a8 100644 --- a/docs/migration.txt +++ b/docs/devel/migration.txt diff --git a/docs/multi-thread-tcg.txt b/docs/devel/multi-thread-tcg.txt index a99b456..a99b456 100644 --- a/docs/multi-thread-tcg.txt +++ b/docs/devel/multi-thread-tcg.txt diff --git a/docs/multiple-iothreads.txt b/docs/devel/multiple-iothreads.txt index e4d340b..e4d340b 100644 --- a/docs/multiple-iothreads.txt +++ b/docs/devel/multiple-iothreads.txt diff --git a/docs/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 52e3874..52e3874 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt diff --git a/docs/rcu.txt b/docs/devel/rcu.txt index c84e7f4..c84e7f4 100644 --- a/docs/rcu.txt +++ b/docs/devel/rcu.txt diff --git a/docs/tracing.txt b/docs/devel/tracing.txt index 8c0029b..8c0029b 100644 --- a/docs/tracing.txt +++ b/docs/devel/tracing.txt diff --git a/docs/virtio-migration.txt b/docs/devel/virtio-migration.txt index 98a6b0f..98a6b0f 100644 --- a/docs/virtio-migration.txt +++ b/docs/devel/virtio-migration.txt diff --git a/docs/writing-qmp-commands.txt b/docs/devel/writing-qmp-commands.txt index 1e63754..1e63754 100644 --- a/docs/writing-qmp-commands.txt +++ b/docs/devel/writing-qmp-commands.txt diff --git a/docs/aio_notify.promela b/docs/spin/aio_notify.promela index fccc7ee..fccc7ee 100644 --- a/docs/aio_notify.promela +++ b/docs/spin/aio_notify.promela diff --git a/docs/aio_notify_accept.promela b/docs/spin/aio_notify_accept.promela index 9cef2c9..9cef2c9 100644 --- a/docs/aio_notify_accept.promela +++ b/docs/spin/aio_notify_accept.promela diff --git a/docs/aio_notify_bug.promela b/docs/spin/aio_notify_bug.promela index b3bfca1..b3bfca1 100644 --- a/docs/aio_notify_bug.promela +++ b/docs/spin/aio_notify_bug.promela diff --git a/docs/tcg-exclusive.promela b/docs/spin/tcg-exclusive.promela index c91cfca..c91cfca 100644 --- a/docs/tcg-exclusive.promela +++ b/docs/spin/tcg-exclusive.promela diff --git a/docs/win32-qemu-event.promela b/docs/spin/win32-qemu-event.promela index c446a71..c446a71 100644 --- a/docs/win32-qemu-event.promela +++ b/docs/spin/win32-qemu-event.promela @@ -374,10 +374,11 @@ static inline bool section_covers_addr(const MemoryRegionSection *section, int128_getlo(section->size), addr); } -static MemoryRegionSection *phys_page_find(PhysPageEntry lp, hwaddr addr, - Node *nodes, MemoryRegionSection *sections) +static MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr addr) { - PhysPageEntry *p; + PhysPageEntry lp = d->phys_map, *p; + Node *nodes = d->map.nodes; + MemoryRegionSection *sections = d->map.sections; hwaddr index = addr >> TARGET_PAGE_BITS; int i; @@ -415,8 +416,7 @@ static MemoryRegionSection *address_space_lookup_region(AddressSpaceDispatch *d, section_covers_addr(section, addr)) { update = false; } else { - section = phys_page_find(d->phys_map, addr, d->map.nodes, - d->map.sections); + section = phys_page_find(d, addr); update = true; } if (resolve_subpage && section->mr->subpage) { @@ -1285,8 +1285,7 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti subpage_t *subpage; hwaddr base = section->offset_within_address_space & TARGET_PAGE_MASK; - MemoryRegionSection *existing = phys_page_find(d->phys_map, base, - d->map.nodes, d->map.sections); + MemoryRegionSection *existing = phys_page_find(d, base); MemoryRegionSection subsection = { .offset_within_address_space = base, .size = int128_make64(TARGET_PAGE_SIZE), diff --git a/gdb-xml/i386-32bit-sse.xml b/gdb-xml/i386-32bit-sse.xml new file mode 100644 index 0000000..5767847 --- /dev/null +++ b/gdb-xml/i386-32bit-sse.xml @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2010-2017 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.i386.32bit.sse"> + <vector id="v4f" type="ieee_single" count="4"/> + <vector id="v2d" type="ieee_double" count="2"/> + <vector id="v16i8" type="int8" count="16"/> + <vector id="v8i16" type="int16" count="8"/> + <vector id="v4i32" type="int32" count="4"/> + <vector id="v2i64" type="int64" count="2"/> + <union id="vec128"> + <field name="v4_float" type="v4f"/> + <field name="v2_double" type="v2d"/> + <field name="v16_int8" type="v16i8"/> + <field name="v8_int16" type="v8i16"/> + <field name="v4_int32" type="v4i32"/> + <field name="v2_int64" type="v2i64"/> + <field name="uint128" type="uint128"/> + </union> + <flags id="i386_mxcsr" size="4"> + <field name="IE" start="0" end="0"/> + <field name="DE" start="1" end="1"/> + <field name="ZE" start="2" end="2"/> + <field name="OE" start="3" end="3"/> + <field name="UE" start="4" end="4"/> + <field name="PE" start="5" end="5"/> + <field name="DAZ" start="6" end="6"/> + <field name="IM" start="7" end="7"/> + <field name="DM" start="8" end="8"/> + <field name="ZM" start="9" end="9"/> + <field name="OM" start="10" end="10"/> + <field name="UM" start="11" end="11"/> + <field name="PM" start="12" end="12"/> + <field name="FZ" start="15" end="15"/> + </flags> + + <reg name="xmm0" bitsize="128" type="vec128" regnum="32"/> + <reg name="xmm1" bitsize="128" type="vec128"/> + <reg name="xmm2" bitsize="128" type="vec128"/> + <reg name="xmm3" bitsize="128" type="vec128"/> + <reg name="xmm4" bitsize="128" type="vec128"/> + <reg name="xmm5" bitsize="128" type="vec128"/> + <reg name="xmm6" bitsize="128" type="vec128"/> + <reg name="xmm7" bitsize="128" type="vec128"/> + + <reg name="mxcsr" bitsize="32" type="i386_mxcsr" group="vector"/> +</feature> diff --git a/gdb-xml/i386-32bit.xml b/gdb-xml/i386-32bit.xml new file mode 100644 index 0000000..956fc7f --- /dev/null +++ b/gdb-xml/i386-32bit.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2010-2017 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!-- I386 with SSE --> + +<!DOCTYPE target SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.i386.32bit"> + <xi:include href="i386-32bit-core.xml"/> + <xi:include href="i386-32bit-sse.xml"/> +</feature> diff --git a/gdb-xml/i386-64bit-sse.xml b/gdb-xml/i386-64bit-sse.xml new file mode 100644 index 0000000..e86efc9 --- /dev/null +++ b/gdb-xml/i386-64bit-sse.xml @@ -0,0 +1,60 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2010-2017 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.i386.64bit.sse"> + <vector id="v4f" type="ieee_single" count="4"/> + <vector id="v2d" type="ieee_double" count="2"/> + <vector id="v16i8" type="int8" count="16"/> + <vector id="v8i16" type="int16" count="8"/> + <vector id="v4i32" type="int32" count="4"/> + <vector id="v2i64" type="int64" count="2"/> + <union id="vec128"> + <field name="v4_float" type="v4f"/> + <field name="v2_double" type="v2d"/> + <field name="v16_int8" type="v16i8"/> + <field name="v8_int16" type="v8i16"/> + <field name="v4_int32" type="v4i32"/> + <field name="v2_int64" type="v2i64"/> + <field name="uint128" type="uint128"/> + </union> + <flags id="i386_mxcsr" size="4"> + <field name="IE" start="0" end="0"/> + <field name="DE" start="1" end="1"/> + <field name="ZE" start="2" end="2"/> + <field name="OE" start="3" end="3"/> + <field name="UE" start="4" end="4"/> + <field name="PE" start="5" end="5"/> + <field name="DAZ" start="6" end="6"/> + <field name="IM" start="7" end="7"/> + <field name="DM" start="8" end="8"/> + <field name="ZM" start="9" end="9"/> + <field name="OM" start="10" end="10"/> + <field name="UM" start="11" end="11"/> + <field name="PM" start="12" end="12"/> + <field name="FZ" start="15" end="15"/> + </flags> + + <reg name="xmm0" bitsize="128" type="vec128" regnum="40"/> + <reg name="xmm1" bitsize="128" type="vec128"/> + <reg name="xmm2" bitsize="128" type="vec128"/> + <reg name="xmm3" bitsize="128" type="vec128"/> + <reg name="xmm4" bitsize="128" type="vec128"/> + <reg name="xmm5" bitsize="128" type="vec128"/> + <reg name="xmm6" bitsize="128" type="vec128"/> + <reg name="xmm7" bitsize="128" type="vec128"/> + <reg name="xmm8" bitsize="128" type="vec128"/> + <reg name="xmm9" bitsize="128" type="vec128"/> + <reg name="xmm10" bitsize="128" type="vec128"/> + <reg name="xmm11" bitsize="128" type="vec128"/> + <reg name="xmm12" bitsize="128" type="vec128"/> + <reg name="xmm13" bitsize="128" type="vec128"/> + <reg name="xmm14" bitsize="128" type="vec128"/> + <reg name="xmm15" bitsize="128" type="vec128"/> + + <reg name="mxcsr" bitsize="32" type="i386_mxcsr" group="vector"/> +</feature> diff --git a/gdb-xml/i386-64bit.xml b/gdb-xml/i386-64bit.xml new file mode 100644 index 0000000..0b2f00c --- /dev/null +++ b/gdb-xml/i386-64bit.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2010-2017 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!-- I386 64bit --> + +<!DOCTYPE target SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.i386.64bit"> + <xi:include href="i386-64bit-core.xml"/> + <xi:include href="i386-64bit-sse.xml"/> +</feature> diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index 8e7d6ec..b5734f5 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -338,9 +338,10 @@ static void nvdimm_build_structure_dcr(GArray *structures, DeviceState *dev) nfit_dcr->revision_id = cpu_to_le16(1 /* Current Revision supported in ACPI 6.0 is 1. */); nfit_dcr->serial_number = cpu_to_le32(sn); - nfit_dcr->fic = cpu_to_le16(0x201 /* Format Interface Code. See Chapter - 2: NVDIMM Device Specific Method - (DSM) in DSM Spec Rev1.*/); + nfit_dcr->fic = cpu_to_le16(0x301 /* Format Interface Code: + Byte addressable, no energy backed. + See ACPI 6.2, sect 5.2.25.6 and + JEDEC Annex L Release 3. */); } static GArray *nvdimm_build_device_structure(void) diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 13eca37..363d1b5 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -19,6 +19,7 @@ #include "qemu/host-utils.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" +#include "sysemu/hw_accel.h" #include "kvm_i386.h" #include "hw/sysbus.h" #include "hw/kvm/clock.h" @@ -69,6 +70,8 @@ static uint64_t kvmclock_current_nsec(KVMClockState *s) uint64_t nsec_hi; uint64_t nsec; + cpu_synchronize_state(cpu); + if (!(env->system_time_msr & 1ULL)) { /* KVM clock not active */ return 0; diff --git a/hw/misc/edu.c b/hw/misc/edu.c index 401039c..01acacf 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -343,6 +343,12 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp) EduState *edu = DO_UPCAST(EduState, pdev, pdev); uint8_t *pci_conf = pdev->config; + pci_config_set_interrupt_pin(pci_conf, 1); + + if (msi_init(pdev, 0, 1, true, false, errp)) { + return; + } + timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu); qemu_mutex_init(&edu->thr_mutex); @@ -350,12 +356,6 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp) qemu_thread_create(&edu->thread, "edu", edu_fact_thread, edu, QEMU_THREAD_JOINABLE); - pci_config_set_interrupt_pin(pci_conf, 1); - - if (msi_init(pdev, 0, 1, true, false, errp)) { - return; - } - memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu, "edu-mmio", 1 << 20); pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio); diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index 8ebffa8..cb694d6 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -20,6 +20,14 @@ #define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100 #define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1 +typedef struct GenPCIERootPort { + /*< private >*/ + PCIESlot parent_obj; + /*< public >*/ + + bool migrate_msix; +} GenPCIERootPort; + static uint8_t gen_rp_aer_vector(const PCIDevice *d) { return 0; @@ -45,6 +53,13 @@ static void gen_rp_interrupts_uninit(PCIDevice *d) msix_uninit_exclusive_bar(d); } +static bool gen_rp_test_migrate_msix(void *opaque, int version_id) +{ + GenPCIERootPort *rp = opaque; + + return rp->migrate_msix; +} + static const VMStateDescription vmstate_rp_dev = { .name = "pcie-root-port", .version_id = 1, @@ -54,10 +69,18 @@ static const VMStateDescription vmstate_rp_dev = { VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot), VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log, PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog), + VMSTATE_MSIX_TEST(parent_obj.parent_obj.parent_obj.parent_obj, + GenPCIERootPort, + gen_rp_test_migrate_msix), VMSTATE_END_OF_LIST() } }; +static Property gen_rp_props[] = { + DEFINE_PROP_BOOL("x-migrate-msix", GenPCIERootPort, migrate_msix, true), + DEFINE_PROP_END_OF_LIST() +}; + static void gen_rp_dev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -68,6 +91,7 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_RP; dc->desc = "PCI Express Root Port"; dc->vmsd = &vmstate_rp_dev; + dc->props = gen_rp_props; rpc->aer_vector = gen_rp_aer_vector; rpc->interrupts_init = gen_rp_interrupts_init; rpc->interrupts_uninit = gen_rp_interrupts_uninit; @@ -77,6 +101,7 @@ static void gen_rp_dev_class_init(ObjectClass *klass, void *data) static const TypeInfo gen_rp_dev_info = { .name = TYPE_GEN_PCIE_ROOT_PORT, .parent = TYPE_PCIE_ROOT_PORT, + .instance_size = sizeof(GenPCIERootPort), .class_init = gen_rp_dev_class_init, }; diff --git a/hw/pci/msix.c b/hw/pci/msix.c index bb54e8b..fc5fe51 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -22,6 +22,7 @@ #include "hw/xen/xen.h" #include "qemu/range.h" #include "qapi/error.h" +#include "trace.h" #define MSIX_CAP_LENGTH 12 @@ -130,10 +131,14 @@ static void msix_handle_mask_update(PCIDevice *dev, int vector, bool was_masked) } } +static bool msix_masked(PCIDevice *dev) +{ + return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK; +} + static void msix_update_function_masked(PCIDevice *dev) { - dev->msix_function_masked = !msix_enabled(dev) || - (dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK); + dev->msix_function_masked = !msix_enabled(dev) || msix_masked(dev); } /* Handle MSI-X capability config write. */ @@ -148,6 +153,8 @@ void msix_write_config(PCIDevice *dev, uint32_t addr, return; } + trace_msix_write_config(dev->name, msix_enabled(dev), msix_masked(dev)); + was_masked = dev->msix_function_masked; msix_update_function_masked(dev); diff --git a/hw/pci/trace-events b/hw/pci/trace-events index 2b9cf24..83c8f5a 100644 --- a/hw/pci/trace-events +++ b/hw/pci/trace-events @@ -7,3 +7,6 @@ pci_update_mappings_add(void *d, uint32_t bus, uint32_t slot, uint32_t func, int # hw/pci/pci_host.c pci_cfg_read(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x -> 0x%x" pci_cfg_write(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x <- 0x%x" + +# hw/pci/msix.c +msix_write_config(char *name, bool enabled, bool masked) "dev %s enabled %d masked %d" diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 1e2f26b..599805d 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -15,6 +15,7 @@ #include "hw/qdev.h" #include "qemu/error-report.h" #include "qemu/bitops.h" +#include "qemu/error-report.h" #include "exec/address-spaces.h" #include "cpu.h" #include "hw/s390x/ioinst.h" @@ -432,6 +433,11 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, return -EINVAL; } + /* We don't support MIDA. */ + if (ccw.flags & CCW_FLAG_MIDA) { + return -EINVAL; + } + if (ccw.flags & CCW_FLAG_SUSPEND) { return suspend_allowed ? -EINPROGRESS : -EINVAL; } @@ -1800,13 +1806,26 @@ void subch_device_save(SubchDev *s, QEMUFile *f) int subch_device_load(SubchDev *s, QEMUFile *f) { SubchDev *old_s; + Error *err = NULL; uint16_t old_schid = s->schid; + uint16_t old_devno = s->devno; int i; s->cssid = qemu_get_byte(f); s->ssid = qemu_get_byte(f); s->schid = qemu_get_be16(f); s->devno = qemu_get_be16(f); + if (s->devno != old_devno) { + /* Only possible if machine < 2.7 (no css_dev_path) */ + + error_setg(&err, "%x != %x", old_devno, s->devno); + error_append_hint(&err, "Devno mismatch, tried to load wrong section!" + " Likely reason: some sequences of plug and unplug" + " can break migration for machine versions prior to" + " 2.7 (known design flaw).\n"); + error_report_err(err); + return -EINVAL; + } /* Re-assign subch. */ if (old_schid != s->schid) { old_s = channel_subsys.css[s->cssid]->sch_set[s->ssid]->sch[old_schid]; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index e6a6f74..90d37cb 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1279,9 +1279,13 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) SubchDev *s = ccw_dev->sch; VirtIODevice *vdev = virtio_ccw_get_vdev(s); int len; + int ret; s->driver_data = dev; - subch_device_load(s, f); + ret = subch_device_load(s, f); + if (ret) { + return ret; + } /* Re-fill subch_id after loading the subchannel states.*/ if (ck->refill_ids) { ck->refill_ids(ccw_dev); diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 46a3e3f..f46f06d 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -918,6 +918,9 @@ void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp) static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) { + VirtIOSCSI *s = VIRTIO_SCSI(dev); + + qbus_set_hotplug_handler(BUS(&s->bus), NULL, &error_abort); virtio_scsi_common_unrealize(dev, errp); } diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 93de3e1..1b8d3d7 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -112,7 +112,6 @@ static uint64_t get_guest_rtc_ns(RTCState *s) guest_clock - s->last_update + s->offset; } -#ifdef TARGET_I386 static void rtc_coalesced_timer_update(RTCState *s) { if (s->irq_coalesced == 0) { @@ -121,21 +120,39 @@ static void rtc_coalesced_timer_update(RTCState *s) /* divide each RTC interval to 2 - 8 smaller intervals */ int c = MIN(s->irq_coalesced, 7) + 1; int64_t next_clock = qemu_clock_get_ns(rtc_clock) + - muldiv64(s->period / c, NANOSECONDS_PER_SECOND, RTC_CLOCK_RATE); + periodic_clock_to_ns(s->period / c); timer_mod(s->coalesced_timer, next_clock); } } +static QLIST_HEAD(, RTCState) rtc_devices = + QLIST_HEAD_INITIALIZER(rtc_devices); + +#ifdef TARGET_I386 +void qmp_rtc_reset_reinjection(Error **errp) +{ + RTCState *s; + + QLIST_FOREACH(s, &rtc_devices, link) { + s->irq_coalesced = 0; + } +} + +static bool rtc_policy_slew_deliver_irq(RTCState *s) +{ + apic_reset_irq_delivered(); + qemu_irq_raise(s->irq); + return apic_get_irq_delivered(); +} + static void rtc_coalesced_timer(void *opaque) { RTCState *s = opaque; if (s->irq_coalesced != 0) { - apic_reset_irq_delivered(); s->cmos_data[RTC_REG_C] |= 0xc0; DPRINTF_C("cmos: injecting from timer\n"); - qemu_irq_raise(s->irq); - if (apic_get_irq_delivered()) { + if (rtc_policy_slew_deliver_irq(s)) { s->irq_coalesced--; DPRINTF_C("cmos: coalesced irqs decreased to %d\n", s->irq_coalesced); @@ -144,40 +161,101 @@ static void rtc_coalesced_timer(void *opaque) rtc_coalesced_timer_update(s); } +#else +static bool rtc_policy_slew_deliver_irq(RTCState *s) +{ + assert(0); + return false; +} #endif -/* handle periodic timer */ -static void periodic_timer_update(RTCState *s, int64_t current_time) +static uint32_t rtc_periodic_clock_ticks(RTCState *s) { - int period_code, period; - int64_t cur_clock, next_irq_clock; + int period_code; + + if (!(s->cmos_data[RTC_REG_B] & REG_B_PIE)) { + return 0; + } period_code = s->cmos_data[RTC_REG_A] & 0x0f; - if (period_code != 0 - && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { - if (period_code <= 2) - period_code += 7; - /* period in 32 Khz cycles */ - period = 1 << (period_code - 1); -#ifdef TARGET_I386 - if (period != s->period) { - s->irq_coalesced = (s->irq_coalesced * s->period) / period; - DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced); - } - s->period = period; -#endif + + return periodic_period_to_clock(period_code); +} + +/* + * handle periodic timer. @old_period indicates the periodic timer update + * is just due to period adjustment. + */ +static void +periodic_timer_update(RTCState *s, int64_t current_time, uint32_t old_period) +{ + uint32_t period; + int64_t cur_clock, next_irq_clock, lost_clock = 0; + + period = rtc_periodic_clock_ticks(s); + + if (period) { /* compute 32 khz clock */ cur_clock = muldiv64(current_time, RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND); - next_irq_clock = (cur_clock & ~(period - 1)) + period; - s->next_periodic_time = muldiv64(next_irq_clock, NANOSECONDS_PER_SECOND, - RTC_CLOCK_RATE) + 1; + /* + * if the periodic timer's update is due to period re-configuration, + * we should count the clock since last interrupt. + */ + if (old_period) { + int64_t last_periodic_clock, next_periodic_clock; + + next_periodic_clock = muldiv64(s->next_periodic_time, + RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND); + last_periodic_clock = next_periodic_clock - old_period; + lost_clock = cur_clock - last_periodic_clock; + assert(lost_clock >= 0); + } + + /* + * s->irq_coalesced can change for two reasons: + * + * a) if one or more periodic timer interrupts have been lost, + * lost_clock will be more that a period. + * + * b) when the period may be reconfigured, we expect the OS to + * treat delayed tick as the new period. So, when switching + * from a shorter to a longer period, scale down the missing, + * because the OS will treat past delayed ticks as longer + * (leftovers are put back into lost_clock). When switching + * to a shorter period, scale up the missing ticks since the + * OS handler will treat past delayed ticks as shorter. + */ + if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { + uint32_t old_irq_coalesced = s->irq_coalesced; + + s->period = period; + lost_clock += old_irq_coalesced * old_period; + s->irq_coalesced = lost_clock / s->period; + lost_clock %= s->period; + if (old_irq_coalesced != s->irq_coalesced || + old_period != s->period) { + DPRINTF_C("cmos: coalesced irqs scaled from %d to %d, " + "period scaled from %d to %d\n", old_irq_coalesced, + s->irq_coalesced, old_period, s->period); + rtc_coalesced_timer_update(s); + } + } else { + /* + * no way to compensate the interrupt if LOST_TICK_POLICY_SLEW + * is not used, we should make the time progress anyway. + */ + lost_clock = MIN(lost_clock, period); + } + + assert(lost_clock >= 0 && lost_clock <= period); + + next_irq_clock = cur_clock + period - lost_clock; + s->next_periodic_time = periodic_clock_to_ns(next_irq_clock) + 1; timer_mod(s->periodic_timer, s->next_periodic_time); } else { -#ifdef TARGET_I386 s->irq_coalesced = 0; -#endif timer_del(s->periodic_timer); } } @@ -186,25 +264,21 @@ static void rtc_periodic_timer(void *opaque) { RTCState *s = opaque; - periodic_timer_update(s, s->next_periodic_time); + periodic_timer_update(s, s->next_periodic_time, 0); s->cmos_data[RTC_REG_C] |= REG_C_PF; if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= REG_C_IRQF; -#ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) - s->irq_reinject_on_ack_count = 0; - apic_reset_irq_delivered(); - qemu_irq_raise(s->irq); - if (!apic_get_irq_delivered()) { + s->irq_reinject_on_ack_count = 0; + if (!rtc_policy_slew_deliver_irq(s)) { s->irq_coalesced++; rtc_coalesced_timer_update(s); DPRINTF_C("cmos: coalesced irqs increased to %d\n", s->irq_coalesced); } } else -#endif - qemu_irq_raise(s->irq); + qemu_irq_raise(s->irq); } } @@ -391,6 +465,8 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { RTCState *s = opaque; + uint32_t old_period; + bool update_periodic_timer; if ((addr & 1) == 0) { s->cmos_index = data & 0x7f; @@ -423,6 +499,9 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, } break; case RTC_REG_A: + update_periodic_timer = (s->cmos_data[RTC_REG_A] ^ data) & 0x0f; + old_period = rtc_periodic_clock_ticks(s); + if ((data & 0x60) == 0x60) { if (rtc_running(s)) { rtc_update_time(s); @@ -445,10 +524,19 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, /* UIP bit is read only */ s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | (s->cmos_data[RTC_REG_A] & REG_A_UIP); - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); + + if (update_periodic_timer) { + periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), + old_period); + } + check_update_timer(s); break; case RTC_REG_B: + update_periodic_timer = (s->cmos_data[RTC_REG_B] ^ data) + & REG_B_PIE; + old_period = rtc_periodic_clock_ticks(s); + if (data & REG_B_SET) { /* update cmos to when the rtc was stopping */ if (rtc_running(s)) { @@ -475,7 +563,12 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, qemu_irq_lower(s->irq); } s->cmos_data[RTC_REG_B] = data; - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); + + if (update_periodic_timer) { + periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), + old_period); + } + check_update_timer(s); break; case RTC_REG_C: @@ -529,20 +622,6 @@ static void rtc_get_time(RTCState *s, struct tm *tm) rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900; } -static QLIST_HEAD(, RTCState) rtc_devices = - QLIST_HEAD_INITIALIZER(rtc_devices); - -#ifdef TARGET_I386 -void qmp_rtc_reset_reinjection(Error **errp) -{ - RTCState *s; - - QLIST_FOREACH(s, &rtc_devices, link) { - s->irq_coalesced = 0; - } -} -#endif - static void rtc_set_time(RTCState *s) { struct tm tm; @@ -662,22 +741,19 @@ static uint64_t cmos_ioport_read(void *opaque, hwaddr addr, if (ret & (REG_C_UF | REG_C_AF)) { check_update_timer(s); } -#ifdef TARGET_I386 + if(s->irq_coalesced && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) { s->irq_reinject_on_ack_count++; s->cmos_data[RTC_REG_C] |= REG_C_IRQF | REG_C_PF; - apic_reset_irq_delivered(); DPRINTF_C("cmos: injecting on ack\n"); - qemu_irq_raise(s->irq); - if (apic_get_irq_delivered()) { + if (rtc_policy_slew_deliver_irq(s)) { s->irq_coalesced--; DPRINTF_C("cmos: coalesced irqs decreased to %d\n", s->irq_coalesced); } } -#endif break; default: ret = s->cmos_data[s->cmos_index]; @@ -743,17 +819,15 @@ static int rtc_post_load(void *opaque, int version_id) uint64_t now = qemu_clock_get_ns(rtc_clock); if (now < s->next_periodic_time || now > (s->next_periodic_time + get_max_clock_jump())) { - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); + periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), 0); } } -#ifdef TARGET_I386 if (version_id >= 2) { if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { rtc_coalesced_timer_update(s); } } -#endif return 0; } @@ -808,13 +882,12 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data) int64_t now = *(int64_t *)data; rtc_set_date_from_host(ISA_DEVICE(s)); - periodic_timer_update(s, now); + periodic_timer_update(s, now, 0); check_update_timer(s); -#ifdef TARGET_I386 + if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { rtc_coalesced_timer_update(s); } -#endif } /* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) @@ -835,12 +908,10 @@ static void rtc_reset(void *opaque) qemu_irq_lower(s->irq); -#ifdef TARGET_I386 if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { s->irq_coalesced = 0; s->irq_reinject_on_ack_count = 0; } -#endif } static const MemoryRegionOps cmos_ops = { @@ -886,19 +957,19 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) rtc_set_date_from_host(isadev); -#ifdef TARGET_I386 switch (s->lost_tick_policy) { +#ifdef TARGET_I386 case LOST_TICK_POLICY_SLEW: s->coalesced_timer = timer_new_ns(rtc_clock, rtc_coalesced_timer, s); break; +#endif case LOST_TICK_POLICY_DISCARD: break; default: error_setg(errp, "Invalid lost tick policy."); return; } -#endif s->periodic_timer = timer_new_ns(rtc_clock, rtc_periodic_timer, s); s->update_timer = timer_new_ns(rtc_clock, rtc_update_timer, s); diff --git a/include/block/nbd.h b/include/block/nbd.h index 0ed0775..416257a 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -127,14 +127,16 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc, struct iovec *iov, size_t niov, size_t length, - bool do_read); + bool do_read, + Error **errp); int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, QCryptoTLSCreds *tlscreds, const char *hostname, QIOChannel **outioc, off_t *size, Error **errp); -int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size); +int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size, + Error **errp); ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request); -ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply); +ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp); int nbd_client(int fd); int nbd_disconnect(int fd); diff --git a/include/chardev/char-parallel.h b/include/chardev/char-parallel.h index 3284a1b..c09751f 100644 --- a/include/chardev/char-parallel.h +++ b/include/chardev/char-parallel.h @@ -26,11 +26,6 @@ #include "chardev/char.h" -#if defined(__linux__) || defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#define HAVE_CHARDEV_PARPORT 1 -#endif - #define CHR_IOCTL_PP_READ_DATA 3 #define CHR_IOCTL_PP_WRITE_DATA 4 #define CHR_IOCTL_PP_READ_CONTROL 5 diff --git a/include/chardev/char-serial.h b/include/chardev/char-serial.h index cb2e59e..ad6891b 100644 --- a/include/chardev/char-serial.h +++ b/include/chardev/char-serial.h @@ -26,14 +26,6 @@ #include "chardev/char.h" -#ifdef _WIN32 -#define HAVE_CHARDEV_SERIAL 1 -#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ - || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ - || defined(__GLIBC__) -#define HAVE_CHARDEV_SERIAL 1 -#endif - #define CHR_IOCTL_SERIAL_SET_PARAMS 1 typedef struct { int speed; diff --git a/include/hw/compat.h b/include/hw/compat.h index 400c64b..26cd585 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -14,6 +14,10 @@ .driver = "virtio-net-device",\ .property = "x-mtu-bypass-backend",\ .value = "off",\ + },{\ + .driver = "pcie-root-port",\ + .property = "x-migrate-msix",\ + .value = "false",\ }, #define HW_COMPAT_2_8 \ diff --git a/include/hw/s390x/ioinst.h b/include/hw/s390x/ioinst.h index c559f53..92d1565 100644 --- a/include/hw/s390x/ioinst.h +++ b/include/hw/s390x/ioinst.h @@ -182,6 +182,7 @@ typedef struct CCW1 { #define CCW_FLAG_PCI 0x08 #define CCW_FLAG_IDA 0x04 #define CCW_FLAG_SUSPEND 0x02 +#define CCW_FLAG_MIDA 0x01 #define CCW_CMD_NOOP 0x03 #define CCW_CMD_BASIC_SENSE 0x04 diff --git a/include/hw/timer/mc146818rtc_regs.h b/include/hw/timer/mc146818rtc_regs.h index 6ede6c8..c62f17b 100644 --- a/include/hw/timer/mc146818rtc_regs.h +++ b/include/hw/timer/mc146818rtc_regs.h @@ -65,4 +65,24 @@ #define REG_C_AF 0x20 #define REG_C_MASK 0x70 +static inline uint32_t periodic_period_to_clock(int period_code) +{ + if (!period_code) { + return 0; + } + + if (period_code <= 2) { + period_code += 7; + } + /* period in 32 Khz cycles */ + return 1 << (period_code - 1); +} + +#define RTC_CLOCK_RATE 32768 + +static inline int64_t periodic_clock_to_ns(int64_t clocks) +{ + return muldiv64(clocks, NANOSECONDS_PER_SECOND, RTC_CLOCK_RATE); +} + #endif diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 1c9f5e2..fb008a2 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -284,6 +284,19 @@ void qemu_anon_ram_free(void *ptr, size_t size); #endif +#ifdef _WIN32 +#define HAVE_CHARDEV_SERIAL 1 +#elif defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ + || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ + || defined(__GLIBC__) +#define HAVE_CHARDEV_SERIAL 1 +#endif + +#if defined(__linux__) || defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#define HAVE_CHARDEV_PARPORT 1 +#endif + #if defined(CONFIG_LINUX) #ifndef BUS_MCEERR_AR #define BUS_MCEERR_AR 4 @@ -1144,6 +1144,7 @@ void kvm_irqchip_release_virq(KVMState *s, int virq) } clear_gsi(s, virq); kvm_arch_release_virq_post(virq); + trace_kvm_irqchip_release_virq(virq); } static unsigned int kvm_hash_msi(uint32_t data) @@ -1287,7 +1288,8 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) return -EINVAL; } - trace_kvm_irqchip_add_msi_route(virq); + trace_kvm_irqchip_add_msi_route(dev ? dev->name : (char *)"N/A", + vector, virq); kvm_add_routing_entry(s, &kroute); kvm_arch_add_msi_route_post(&kroute, vector, dev); @@ -1746,6 +1748,8 @@ static int kvm_init(MachineState *ms) kvm_ioeventfd_any_length_allowed = (kvm_check_extension(s, KVM_CAP_IOEVENTFD_ANY_LENGTH) > 0); + kvm_state = s; + ret = kvm_arch_init(ms, s); if (ret < 0) { goto err; @@ -1755,8 +1759,6 @@ static int kvm_init(MachineState *ms) kvm_irqchip_create(ms, s); } - kvm_state = s; - if (kvm_eventfds_allowed) { s->memory_listener.listener.eventfd_add = kvm_mem_ioeventfd_add; s->memory_listener.listener.eventfd_del = kvm_mem_ioeventfd_del; diff --git a/migration/block.c b/migration/block.c index 4d8c2e9..114cedb 100644 --- a/migration/block.c +++ b/migration/block.c @@ -674,16 +674,14 @@ static int64_t get_remaining_dirty(void) return dirty << BDRV_SECTOR_BITS; } -/* Called with iothread lock taken. */ -static void block_migration_cleanup(void *opaque) + +/* Called with iothread lock taken. */ +static void block_migration_cleanup_bmds(void) { BlkMigDevState *bmds; - BlkMigBlock *blk; AioContext *ctx; - bdrv_drain_all(); - unset_dirty_tracking(); while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { @@ -701,6 +699,16 @@ static void block_migration_cleanup(void *opaque) g_free(bmds->aio_bitmap); g_free(bmds); } +} + +/* Called with iothread lock taken. */ +static void block_migration_cleanup(void *opaque) +{ + BlkMigBlock *blk; + + bdrv_drain_all(); + + block_migration_cleanup_bmds(); blk_mig_lock(); while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) { @@ -844,6 +852,10 @@ static int block_save_complete(QEMUFile *f, void *opaque) qemu_put_be64(f, BLK_MIG_FLAG_EOS); + /* Make sure that our BlockBackends are gone, so that the block driver + * nodes can be inactivated. */ + block_migration_cleanup_bmds(); + return 0; } diff --git a/migration/migration.c b/migration/migration.c index 6f0705a..fc95acb 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1825,17 +1825,19 @@ static void migration_completion(MigrationState *s, int current_active_state, if (!ret) { ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + if (ret >= 0) { + qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX); + qemu_savevm_state_complete_precopy(s->to_dst_file, false); + } /* * Don't mark the image with BDRV_O_INACTIVE flag if * we will go into COLO stage later. */ if (ret >= 0 && !migrate_colo_enabled()) { ret = bdrv_inactivate_all(); - } - if (ret >= 0) { - qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX); - qemu_savevm_state_complete_precopy(s->to_dst_file, false); - s->block_inactive = true; + if (ret >= 0) { + s->block_inactive = true; + } } } qemu_mutex_unlock_iothread(); diff --git a/nbd/client.c b/nbd/client.c index a58fb02..595d99e 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -86,9 +86,9 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); */ -/* Discard length bytes from channel. Return -errno on failure, or - * the amount of bytes consumed. */ -static ssize_t drop_sync(QIOChannel *ioc, size_t size) +/* Discard length bytes from channel. Return -errno on failure and 0 on + * success*/ +static int drop_sync(QIOChannel *ioc, size_t size, Error **errp) { ssize_t ret = 0; char small[1024]; @@ -96,14 +96,13 @@ static ssize_t drop_sync(QIOChannel *ioc, size_t size) buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); while (size > 0) { - ssize_t count = read_sync(ioc, buffer, MIN(65536, size)); + ssize_t count = MIN(65536, size); + ret = read_sync(ioc, buffer, MIN(65536, size), errp); - if (count <= 0) { + if (ret < 0) { goto cleanup; } - assert(count <= size); size -= count; - ret += count; } cleanup: @@ -136,13 +135,13 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt, stl_be_p(&req.option, opt); stl_be_p(&req.length, len); - if (write_sync(ioc, &req, sizeof(req)) != sizeof(req)) { - error_setg(errp, "Failed to send option request header"); + if (write_sync(ioc, &req, sizeof(req), errp) < 0) { + error_prepend(errp, "Failed to send option request header"); return -1; } - if (len && write_sync(ioc, (char *) data, len) != len) { - error_setg(errp, "Failed to send option request data"); + if (len && write_sync(ioc, (char *) data, len, errp) < 0) { + error_prepend(errp, "Failed to send option request data"); return -1; } @@ -170,8 +169,8 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, nbd_opt_reply *reply, Error **errp) { QEMU_BUILD_BUG_ON(sizeof(*reply) != 20); - if (read_sync(ioc, reply, sizeof(*reply)) != sizeof(*reply)) { - error_setg(errp, "failed to read option reply"); + if (read_sync(ioc, reply, sizeof(*reply), errp) < 0) { + error_prepend(errp, "failed to read option reply"); nbd_send_opt_abort(ioc); return -1; } @@ -219,8 +218,8 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply, goto cleanup; } msg = g_malloc(reply->length + 1); - if (read_sync(ioc, msg, reply->length) != reply->length) { - error_setg(errp, "failed to read option error message"); + if (read_sync(ioc, msg, reply->length, errp) < 0) { + error_prepend(errp, "failed to read option error message"); goto cleanup; } msg[reply->length] = '\0'; @@ -321,8 +320,8 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, nbd_send_opt_abort(ioc); return -1; } - if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) { - error_setg(errp, "failed to read option name length"); + if (read_sync(ioc, &namelen, sizeof(namelen), errp) < 0) { + error_prepend(errp, "failed to read option name length"); nbd_send_opt_abort(ioc); return -1; } @@ -334,8 +333,8 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, return -1; } if (namelen != strlen(want)) { - if (drop_sync(ioc, len) != len) { - error_setg(errp, "failed to skip export name with wrong length"); + if (drop_sync(ioc, len, errp) < 0) { + error_prepend(errp, "failed to skip export name with wrong length"); nbd_send_opt_abort(ioc); return -1; } @@ -343,15 +342,15 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, } assert(namelen < sizeof(name)); - if (read_sync(ioc, name, namelen) != namelen) { - error_setg(errp, "failed to read export name"); + if (read_sync(ioc, name, namelen, errp) < 0) { + error_prepend(errp, "failed to read export name"); nbd_send_opt_abort(ioc); return -1; } name[namelen] = '\0'; len -= namelen; - if (drop_sync(ioc, len) != len) { - error_setg(errp, "failed to read export description"); + if (drop_sync(ioc, len, errp) < 0) { + error_prepend(errp, "failed to read export description"); nbd_send_opt_abort(ioc); return -1; } @@ -477,8 +476,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, goto fail; } - if (read_sync(ioc, buf, 8) != 8) { - error_setg(errp, "Failed to read data"); + if (read_sync(ioc, buf, 8, errp) < 0) { + error_prepend(errp, "Failed to read data"); goto fail; } @@ -503,8 +502,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, goto fail; } - if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) { - error_setg(errp, "Failed to read magic"); + if (read_sync(ioc, &magic, sizeof(magic), errp) < 0) { + error_prepend(errp, "Failed to read magic"); goto fail; } magic = be64_to_cpu(magic); @@ -515,9 +514,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, uint16_t globalflags; bool fixedNewStyle = false; - if (read_sync(ioc, &globalflags, sizeof(globalflags)) != - sizeof(globalflags)) { - error_setg(errp, "Failed to read server flags"); + if (read_sync(ioc, &globalflags, sizeof(globalflags), errp) < 0) { + error_prepend(errp, "Failed to read server flags"); goto fail; } globalflags = be16_to_cpu(globalflags); @@ -534,9 +532,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, } /* client requested flags */ clientflags = cpu_to_be32(clientflags); - if (write_sync(ioc, &clientflags, sizeof(clientflags)) != - sizeof(clientflags)) { - error_setg(errp, "Failed to send clientflags field"); + if (write_sync(ioc, &clientflags, sizeof(clientflags), errp) < 0) { + error_prepend(errp, "Failed to send clientflags field"); goto fail; } if (tlscreds) { @@ -573,14 +570,14 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, } /* Read the response */ - if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) { - error_setg(errp, "Failed to read export length"); + if (read_sync(ioc, &s, sizeof(s), errp) < 0) { + error_prepend(errp, "Failed to read export length"); goto fail; } *size = be64_to_cpu(s); - if (read_sync(ioc, flags, sizeof(*flags)) != sizeof(*flags)) { - error_setg(errp, "Failed to read export flags"); + if (read_sync(ioc, flags, sizeof(*flags), errp) < 0) { + error_prepend(errp, "Failed to read export flags"); goto fail; } be16_to_cpus(flags); @@ -596,15 +593,15 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, goto fail; } - if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) { - error_setg(errp, "Failed to read export length"); + if (read_sync(ioc, &s, sizeof(s), errp) < 0) { + error_prepend(errp, "Failed to read export length"); goto fail; } *size = be64_to_cpu(s); TRACE("Size is %" PRIu64, *size); - if (read_sync(ioc, &oldflags, sizeof(oldflags)) != sizeof(oldflags)) { - error_setg(errp, "Failed to read export flags"); + if (read_sync(ioc, &oldflags, sizeof(oldflags), errp) < 0) { + error_prepend(errp, "Failed to read export flags"); goto fail; } be32_to_cpus(&oldflags); @@ -619,8 +616,8 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, } TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags); - if (zeroes && drop_sync(ioc, 124) != 124) { - error_setg(errp, "Failed to read reserved block"); + if (zeroes && drop_sync(ioc, 124, errp) < 0) { + error_prepend(errp, "Failed to read reserved block"); goto fail; } rc = 0; @@ -630,11 +627,13 @@ fail: } #ifdef __linux__ -int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size) +int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size, + Error **errp) { unsigned long sectors = size / BDRV_SECTOR_SIZE; if (size / BDRV_SECTOR_SIZE != sectors) { - LOG("Export size %lld too large for 32-bit kernel", (long long) size); + error_setg(errp, "Export size %lld too large for 32-bit kernel", + (long long) size); return -E2BIG; } @@ -642,7 +641,7 @@ int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size) if (ioctl(fd, NBD_SET_SOCK, (unsigned long) sioc->fd) < 0) { int serrno = errno; - LOG("Failed to set NBD socket"); + error_setg(errp, "Failed to set NBD socket"); return -serrno; } @@ -650,7 +649,7 @@ int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size) if (ioctl(fd, NBD_SET_BLKSIZE, (unsigned long)BDRV_SECTOR_SIZE) < 0) { int serrno = errno; - LOG("Failed setting NBD block size"); + error_setg(errp, "Failed setting NBD block size"); return -serrno; } @@ -662,7 +661,7 @@ int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size) if (ioctl(fd, NBD_SET_SIZE_BLOCKS, sectors) < 0) { int serrno = errno; - LOG("Failed setting size (in blocks)"); + error_setg(errp, "Failed setting size (in blocks)"); return -serrno; } @@ -673,12 +672,12 @@ int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size) if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) { int serrno = errno; - LOG("Failed setting read-only attribute"); + error_setg(errp, "Failed setting read-only attribute"); return -serrno; } } else { int serrno = errno; - LOG("Failed setting flags"); + error_setg(errp, "Failed setting flags"); return -serrno; } } @@ -726,8 +725,10 @@ int nbd_disconnect(int fd) } #else -int nbd_init(int fd, QIOChannelSocket *ioc, uint16_t flags, off_t size) +int nbd_init(int fd, QIOChannelSocket *ioc, uint16_t flags, off_t size, + Error **errp) { + error_setg(errp, "nbd_init is only supported on Linux"); return -ENOTSUP; } @@ -744,7 +745,6 @@ int nbd_disconnect(int fd) ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request) { uint8_t buf[NBD_REQUEST_SIZE]; - ssize_t ret; TRACE("Sending request to server: " "{ .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 @@ -759,31 +759,22 @@ ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request) stq_be_p(buf + 16, request->from); stl_be_p(buf + 24, request->len); - ret = write_sync(ioc, buf, sizeof(buf)); - if (ret < 0) { - return ret; - } - - if (ret != sizeof(buf)) { - LOG("writing to socket failed"); - return -EINVAL; - } - return 0; + return write_sync(ioc, buf, sizeof(buf), NULL); } -ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply) +ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) { uint8_t buf[NBD_REPLY_SIZE]; uint32_t magic; ssize_t ret; - ret = read_sync(ioc, buf, sizeof(buf)); + ret = read_sync_eof(ioc, buf, sizeof(buf), errp); if (ret <= 0) { return ret; } if (ret != sizeof(buf)) { - LOG("read failed"); + error_setg(errp, "read failed"); return -EINVAL; } @@ -801,7 +792,7 @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply) if (reply->error == ESHUTDOWN) { /* This works even on mingw which lacks a native ESHUTDOWN */ - LOG("server shutting down"); + error_setg(errp, "server shutting down"); return -EINVAL; } TRACE("Got reply: { magic = 0x%" PRIx32 ", .error = % " PRId32 @@ -809,7 +800,7 @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply) magic, reply->error, reply->handle); if (magic != NBD_REPLY_MAGIC) { - LOG("invalid magic (got 0x%" PRIx32 ")", magic); + error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic); return -EINVAL; } return sizeof(buf); diff --git a/nbd/common.c b/nbd/common.c index dccbb8e..bd81637 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -20,14 +20,18 @@ #include "qapi/error.h" #include "nbd-internal.h" +/* nbd_wr_syncv + * The function may be called from coroutine or from non-coroutine context. + * When called from non-coroutine context @ioc must be in blocking mode. + */ ssize_t nbd_wr_syncv(QIOChannel *ioc, struct iovec *iov, size_t niov, size_t length, - bool do_read) + bool do_read, + Error **errp) { ssize_t done = 0; - Error *local_err = NULL; struct iovec *local_iov = g_new(struct iovec, niov); struct iovec *local_iov_head = local_iov; unsigned int nlocal_iov = niov; @@ -37,22 +41,17 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc, while (nlocal_iov > 0) { ssize_t len; if (do_read) { - len = qio_channel_readv(ioc, local_iov, nlocal_iov, &local_err); + len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp); } else { - len = qio_channel_writev(ioc, local_iov, nlocal_iov, &local_err); + len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp); } if (len == QIO_CHANNEL_ERR_BLOCK) { - if (qemu_in_coroutine()) { - qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT); - } else { - return -EAGAIN; - } + /* errp should not be set */ + assert(qemu_in_coroutine()); + qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT); continue; } if (len < 0) { - TRACE("I/O error: %s", error_get_pretty(local_err)); - error_free(local_err); - /* XXX handle Error objects */ done = -EIO; goto cleanup; } diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index f43d990..d607164 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -94,7 +94,14 @@ #define NBD_ENOSPC 28 #define NBD_ESHUTDOWN 108 -static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size) +/* read_sync_eof + * Tries to read @size bytes from @ioc. Returns number of bytes actually read. + * May return a value >= 0 and < size only on EOF, i.e. when iteratively called + * qio_channel_readv() returns 0. So, there are no needs to call read_sync_eof + * iteratively. + */ +static inline ssize_t read_sync_eof(QIOChannel *ioc, void *buffer, size_t size, + Error **errp) { struct iovec iov = { .iov_base = buffer, .iov_len = size }; /* Sockets are kept in blocking mode in the negotiation phase. After @@ -102,15 +109,38 @@ static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size) * our request/reply. Synchronization is done with recv_coroutine, so * that this is coroutine-safe. */ - return nbd_wr_syncv(ioc, &iov, 1, size, true); + return nbd_wr_syncv(ioc, &iov, 1, size, true, errp); +} + +/* read_sync + * Reads @size bytes from @ioc. Returns 0 on success. + */ +static inline int read_sync(QIOChannel *ioc, void *buffer, size_t size, + Error **errp) +{ + ssize_t ret = read_sync_eof(ioc, buffer, size, errp); + + if (ret >= 0 && ret != size) { + ret = -EINVAL; + error_setg(errp, "End of file"); + } + + return ret < 0 ? ret : 0; } -static inline ssize_t write_sync(QIOChannel *ioc, const void *buffer, - size_t size) +/* write_sync + * Writes @size bytes to @ioc. Returns 0 on success. + */ +static inline int write_sync(QIOChannel *ioc, const void *buffer, size_t size, + Error **errp) { struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size }; - return nbd_wr_syncv(ioc, &iov, 1, size, false); + ssize_t ret = nbd_wr_syncv(ioc, &iov, 1, size, false, errp); + + assert(ret < 0 || ret == size); + + return ret < 0 ? ret : 0; } struct NBDTLSHandshakeData { diff --git a/nbd/server.c b/nbd/server.c index 924a1fe..49b55f6 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -112,7 +112,7 @@ static gboolean nbd_negotiate_continue(QIOChannel *ioc, return TRUE; } -static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) +static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) { ssize_t ret; guint watch; @@ -124,14 +124,13 @@ static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) nbd_negotiate_continue, qemu_coroutine_self(), NULL); - ret = read_sync(ioc, buffer, size); + ret = read_sync(ioc, buffer, size, NULL); g_source_remove(watch); return ret; } -static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer, - size_t size) +static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size) { ssize_t ret; guint watch; @@ -143,29 +142,29 @@ static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer, nbd_negotiate_continue, qemu_coroutine_self(), NULL); - ret = write_sync(ioc, buffer, size); + ret = write_sync(ioc, buffer, size, NULL); g_source_remove(watch); return ret; } -static ssize_t nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size) +static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size) { - ssize_t ret, dropped = size; + ssize_t ret; uint8_t *buffer = g_malloc(MIN(65536, size)); while (size > 0) { - ret = nbd_negotiate_read(ioc, buffer, MIN(65536, size)); + size_t count = MIN(65536, size); + ret = nbd_negotiate_read(ioc, buffer, count); if (ret < 0) { g_free(buffer); return ret; } - assert(ret <= size); - size -= ret; + size -= count; } g_free(buffer); - return dropped; + return 0; } /* Basic flow for negotiation @@ -206,22 +205,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type, type, opt, len); magic = cpu_to_be64(NBD_REP_MAGIC); - if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) { + if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) { LOG("write failed (rep magic)"); return -EINVAL; } opt = cpu_to_be32(opt); - if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) != sizeof(opt)) { + if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) { LOG("write failed (rep opt)"); return -EINVAL; } type = cpu_to_be32(type); - if (nbd_negotiate_write(ioc, &type, sizeof(type)) != sizeof(type)) { + if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) { LOG("write failed (rep type)"); return -EINVAL; } len = cpu_to_be32(len); - if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) { + if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { LOG("write failed (rep data length)"); return -EINVAL; } @@ -256,7 +255,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type, if (ret < 0) { goto out; } - if (nbd_negotiate_write(ioc, msg, len) != len) { + if (nbd_negotiate_write(ioc, msg, len) < 0) { LOG("write failed (error message)"); ret = -EIO; } else { @@ -287,15 +286,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp) } len = cpu_to_be32(name_len); - if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) { + if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { LOG("write failed (name length)"); return -EINVAL; } - if (nbd_negotiate_write(ioc, name, name_len) != name_len) { + if (nbd_negotiate_write(ioc, name, name_len) < 0) { LOG("write failed (name buffer)"); return -EINVAL; } - if (nbd_negotiate_write(ioc, desc, desc_len) != desc_len) { + if (nbd_negotiate_write(ioc, desc, desc_len) < 0) { LOG("write failed (description buffer)"); return -EINVAL; } @@ -309,7 +308,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length) NBDExport *exp; if (length) { - if (nbd_negotiate_drop_sync(client->ioc, length) != length) { + if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { return -EIO; } return nbd_negotiate_send_rep_err(client->ioc, @@ -340,7 +339,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length) LOG("Bad length received"); goto fail; } - if (nbd_negotiate_read(client->ioc, name, length) != length) { + if (nbd_negotiate_read(client->ioc, name, length) < 0) { LOG("read failed"); goto fail; } @@ -373,7 +372,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, TRACE("Setting up TLS"); ioc = client->ioc; if (length) { - if (nbd_negotiate_drop_sync(ioc, length) != length) { + if (nbd_negotiate_drop_sync(ioc, length) < 0) { return NULL; } nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS, @@ -437,8 +436,7 @@ static int nbd_negotiate_options(NBDClient *client) ... Rest of request */ - if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) != - sizeof(flags)) { + if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) { LOG("read failed"); return -EIO; } @@ -464,8 +462,7 @@ static int nbd_negotiate_options(NBDClient *client) uint32_t clientflags, length; uint64_t magic; - if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) != - sizeof(magic)) { + if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) { LOG("read failed"); return -EINVAL; } @@ -476,14 +473,14 @@ static int nbd_negotiate_options(NBDClient *client) } if (nbd_negotiate_read(client->ioc, &clientflags, - sizeof(clientflags)) != sizeof(clientflags)) { + sizeof(clientflags)) < 0) + { LOG("read failed"); return -EINVAL; } clientflags = be32_to_cpu(clientflags); - if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) != - sizeof(length)) { + if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) { LOG("read failed"); return -EINVAL; } @@ -513,7 +510,7 @@ static int nbd_negotiate_options(NBDClient *client) return -EINVAL; default: - if (nbd_negotiate_drop_sync(client->ioc, length) != length) { + if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { return -EIO; } ret = nbd_negotiate_send_rep_err(client->ioc, @@ -551,7 +548,7 @@ static int nbd_negotiate_options(NBDClient *client) return nbd_negotiate_handle_export_name(client, length); case NBD_OPT_STARTTLS: - if (nbd_negotiate_drop_sync(client->ioc, length) != length) { + if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { return -EIO; } if (client->tlscreds) { @@ -570,7 +567,7 @@ static int nbd_negotiate_options(NBDClient *client) } break; default: - if (nbd_negotiate_drop_sync(client->ioc, length) != length) { + if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { return -EIO; } ret = nbd_negotiate_send_rep_err(client->ioc, @@ -659,12 +656,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) TRACE("TLS cannot be enabled with oldstyle protocol"); goto fail; } - if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) != sizeof(buf)) { + if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) { LOG("write failed"); goto fail; } } else { - if (nbd_negotiate_write(client->ioc, buf, 18) != 18) { + if (nbd_negotiate_write(client->ioc, buf, 18) < 0) { LOG("write failed"); goto fail; } @@ -679,7 +676,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) stq_be_p(buf + 18, client->exp->size); stw_be_p(buf + 26, client->exp->nbdflags | myflags); len = client->no_zeroes ? 10 : sizeof(buf) - 18; - if (nbd_negotiate_write(client->ioc, buf + 18, len) != len) { + if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) { LOG("write failed"); goto fail; } @@ -697,16 +694,11 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request) uint32_t magic; ssize_t ret; - ret = read_sync(ioc, buf, sizeof(buf)); + ret = read_sync(ioc, buf, sizeof(buf), NULL); if (ret < 0) { return ret; } - if (ret != sizeof(buf)) { - LOG("read failed"); - return -EINVAL; - } - /* Request [ 0 .. 3] magic (NBD_REQUEST_MAGIC) [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...) @@ -737,7 +729,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request) static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply) { uint8_t buf[NBD_REPLY_SIZE]; - ssize_t ret; reply->error = system_errno_to_nbd_errno(reply->error); @@ -754,16 +745,7 @@ static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply) stl_be_p(buf + 4, reply->error); stq_be_p(buf + 8, reply->handle); - ret = write_sync(ioc, buf, sizeof(buf)); - if (ret < 0) { - return ret; - } - - if (ret != sizeof(buf)) { - LOG("writing to socket failed"); - return -EINVAL; - } - return 0; + return write_sync(ioc, buf, sizeof(buf), NULL); } #define MAX_NBD_REQUESTS 16 @@ -1066,8 +1048,8 @@ static ssize_t nbd_co_send_reply(NBDRequestData *req, NBDReply *reply, qio_channel_set_cork(client->ioc, true); rc = nbd_send_reply(client->ioc, reply); if (rc >= 0) { - ret = write_sync(client->ioc, req->data, len); - if (ret != len) { + ret = write_sync(client->ioc, req->data, len, NULL); + if (ret < 0) { rc = -EIO; } } @@ -1141,7 +1123,7 @@ static ssize_t nbd_co_receive_request(NBDRequestData *req, if (request->type == NBD_CMD_WRITE) { TRACE("Reading %" PRIu32 " byte(s)", request->len); - if (read_sync(client->ioc, req->data, request->len) != request->len) { + if (read_sync(client->ioc, req->data, request->len, NULL) < 0) { LOG("reading from socket failed"); rc = -EIO; goto out; @@ -1376,16 +1358,14 @@ static coroutine_fn void nbd_co_client_start(void *opaque) if (exp) { nbd_export_get(exp); + QTAILQ_INSERT_TAIL(&exp->clients, client, next); } + qemu_co_mutex_init(&client->send_lock); + if (nbd_negotiate(data)) { client_close(client); goto out; } - qemu_co_mutex_init(&client->send_lock); - - if (exp) { - QTAILQ_INSERT_TAIL(&exp->clients, client, next); - } nbd_client_receive_next_request(client); diff --git a/pc-bios/linuxboot_dma.bin b/pc-bios/linuxboot_dma.bin Binary files differindex 218d3ab..d176f62 100644 --- a/pc-bios/linuxboot_dma.bin +++ b/pc-bios/linuxboot_dma.bin diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index fa53d9e..a9a9e5e 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -13,6 +13,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/optionrom) ifeq ($(lastword $(filter -O%, -O0 $(CFLAGS))),-O0) override CFLAGS += -O2 endif +override CFLAGS += -march=i486 # Drop -fstack-protector and the like QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS)) $(CFLAGS_NOPIE) -ffreestanding diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 79a46b6..fb88c13 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -21,8 +21,10 @@ build-all: s390-ccw.img s390-ccw.elf: $(OBJECTS) $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),"BUILD","$(TARGET_DIR)$@") +STRIP ?= strip + s390-ccw.img: s390-ccw.elf - $(call quiet-command,strip --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") + $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,"STRIP","$(TARGET_DIR)$@") $(OBJECTS): Makefile @@ -288,8 +288,9 @@ static void *nbd_client_thread(void *arg) goto out_socket; } - ret = nbd_init(fd, sioc, nbdflags, size); + ret = nbd_init(fd, sioc, nbdflags, size, &local_error); if (ret < 0) { + error_report_err(local_error); goto out_fd; } @@ -324,7 +325,7 @@ out: static int nbd_can_accept(void) { - return nb_fds < shared; + return state == RUNNING && nb_fds < shared; } static void nbd_export_closed(NBDExport *exp) @@ -20,9 +20,6 @@ MAKEFLAGS += -rR %.mak: clean-target: -# Flags for C++ compilation -QEMU_CXXFLAGS = -D__STDC_LIMIT_MACROS $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls, $(QEMU_CFLAGS)) - # Flags for dependency generation QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(@D)/$(*F).d diff --git a/scripts/coccinelle/return_directly.cocci b/scripts/coccinelle/return_directly.cocci index 48680f2..4cf50e7 100644 --- a/scripts/coccinelle/return_directly.cocci +++ b/scripts/coccinelle/return_directly.cocci @@ -1,4 +1,4 @@ -// replace 'R = X; return R;' with 'return R;' +// replace 'R = X; return R;' with 'return X;' @@ identifier VAR; expression E; diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index d60b3a0..f1be6e4 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -42,7 +42,15 @@ def get_record(edict, idtoname, rechdr, fobj): event_id = rechdr[0] name = idtoname[event_id] rec = (name, rechdr[1], rechdr[3]) - event = edict[name] + try: + event = edict[name] + except KeyError, e: + import sys + sys.stderr.write('%s event is logged but is not declared ' \ + 'in the trace events file, try using ' \ + 'trace-events-all instead.\n' % str(e)) + sys.exit(1) + for type, name in event.args: if is_string(type): l = fobj.read(4) diff --git a/target/i386/arch_memory_mapping.c b/target/i386/arch_memory_mapping.c index 826aee5..647cff2 100644 --- a/target/i386/arch_memory_mapping.c +++ b/target/i386/arch_memory_mapping.c @@ -272,25 +272,27 @@ void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + int32_t a20_mask; if (!cpu_paging_enabled(cs)) { /* paging is disabled */ return; } + a20_mask = x86_get_a20_mask(env); if (env->cr[4] & CR4_PAE_MASK) { #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { if (env->cr[4] & CR4_LA57_MASK) { hwaddr pml5e_addr; - pml5e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask; - walk_pml5e(list, cs->as, pml5e_addr, env->a20_mask); + pml5e_addr = (env->cr[3] & PLM4_ADDR_MASK) & a20_mask; + walk_pml5e(list, cs->as, pml5e_addr, a20_mask); } else { hwaddr pml4e_addr; - pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & env->a20_mask; - walk_pml4e(list, cs->as, pml4e_addr, env->a20_mask, + pml4e_addr = (env->cr[3] & PLM4_ADDR_MASK) & a20_mask; + walk_pml4e(list, cs->as, pml4e_addr, a20_mask, 0xffffULL << 48); } } else @@ -298,16 +300,16 @@ void x86_cpu_get_memory_mapping(CPUState *cs, MemoryMappingList *list, { hwaddr pdpe_addr; - pdpe_addr = (env->cr[3] & ~0x1f) & env->a20_mask; - walk_pdpe2(list, cs->as, pdpe_addr, env->a20_mask); + pdpe_addr = (env->cr[3] & ~0x1f) & a20_mask; + walk_pdpe2(list, cs->as, pdpe_addr, a20_mask); } } else { hwaddr pde_addr; bool pse; - pde_addr = (env->cr[3] & ~0xfff) & env->a20_mask; + pde_addr = (env->cr[3] & ~0xfff) & a20_mask; pse = !!(env->cr[4] & CR4_PSE_MASK); - walk_pde2(list, cs->as, pde_addr, env->a20_mask, pse); + walk_pde2(list, cs->as, pde_addr, a20_mask, pse); } } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ffb5267..b2b1d20 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3239,7 +3239,7 @@ static void x86_cpu_machine_done(Notifier *n, void *unused) cpu->smram = g_new(MemoryRegion, 1); memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", smram, 0, 1ull << 32); - memory_region_set_enabled(cpu->smram, false); + memory_region_set_enabled(cpu->smram, true); memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1); } } @@ -3619,7 +3619,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY if (tcg_enabled()) { - AddressSpace *newas = g_new(AddressSpace, 1); + AddressSpace *as_normal = address_space_init_shareable(cs->memory, + "cpu-memory"); + AddressSpace *as_smm = g_new(AddressSpace, 1); cpu->cpu_as_mem = g_new(MemoryRegion, 1); cpu->cpu_as_root = g_new(MemoryRegion, 1); @@ -3635,9 +3637,11 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) get_system_memory(), 0, ~0ull); memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); memory_region_set_enabled(cpu->cpu_as_mem, true); - address_space_init(newas, cpu->cpu_as_root, "CPU"); - cs->num_ases = 1; - cpu_address_space_init(cs, newas, 0); + address_space_init(as_smm, cpu->cpu_as_root, "CPU"); + + cs->num_ases = 2; + cpu_address_space_init(cs, as_normal, 0); + cpu_address_space_init(cs, as_smm, 1); /* ... SMRAM with higher priority, linked from /machine/smram. */ cpu->machine_done.notify = x86_cpu_machine_done; @@ -4053,6 +4057,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) #ifdef CONFIG_USER_ONLY cc->handle_mmu_fault = x86_cpu_handle_mmu_fault; #else + cc->asidx_from_attrs = x86_asidx_from_attrs; cc->get_memory_mapping = x86_cpu_get_memory_mapping; cc->get_phys_page_debug = x86_cpu_get_phys_page_debug; cc->write_elf64_note = x86_cpu_write_elf64_note; @@ -4063,11 +4068,11 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) #endif cc->gdb_arch_name = x86_gdb_arch_name; #ifdef TARGET_X86_64 - cc->gdb_core_xml_file = "i386-64bit-core.xml"; - cc->gdb_num_core_regs = 40; + cc->gdb_core_xml_file = "i386-64bit.xml"; + cc->gdb_num_core_regs = 57; #else - cc->gdb_core_xml_file = "i386-32bit-core.xml"; - cc->gdb_num_core_regs = 32; + cc->gdb_core_xml_file = "i386-32bit.xml"; + cc->gdb_num_core_regs = 41; #endif #ifndef CONFIG_USER_ONLY cc->debug_excp_handler = breakpoint_handler; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index cfe825f..de0551f 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1451,6 +1451,16 @@ int x86_cpu_handle_mmu_fault(CPUState *cpu, vaddr addr, void x86_cpu_set_a20(X86CPU *cpu, int a20_state); #ifndef CONFIG_USER_ONLY +static inline int x86_asidx_from_attrs(CPUState *cs, MemTxAttrs attrs) +{ + return !!attrs.secure; +} + +static inline AddressSpace *cpu_addressspace(CPUState *cs, MemTxAttrs attrs) +{ + return cpu_get_address_space(cs, cpu_asidx_from_attrs(cs, attrs)); +} + uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr); uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr); uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr); @@ -1625,6 +1635,15 @@ static inline MemTxAttrs cpu_get_mem_attrs(CPUX86State *env) return ((MemTxAttrs) { .secure = (env->hflags & HF_SMM_MASK) != 0 }); } +static inline int32_t x86_get_a20_mask(CPUX86State *env) +{ + if (env->hflags & HF_SMM_MASK) { + return -1; + } else { + return env->a20_mask; + } +} + /* fpu_helper.c */ void cpu_set_mxcsr(CPUX86State *env, uint32_t val); void cpu_set_fpuc(CPUX86State *env, uint16_t val); @@ -1644,7 +1663,6 @@ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); /* smm_helper.c */ void do_smm_enter(X86CPU *cpu); -void cpu_smm_update(X86CPU *cpu); /* apic.c */ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); diff --git a/target/i386/helper.c b/target/i386/helper.c index ee7eff2..ef05059 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -724,6 +724,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; uint64_t ptep, pte; + int32_t a20_mask; target_ulong pde_addr, pte_addr; int error_code = 0; int is_dirty, prot, page_size, is_write, is_user; @@ -739,6 +740,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, #endif is_write = is_write1 & 1; + a20_mask = x86_get_a20_mask(env); if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr; #ifdef TARGET_X86_64 @@ -777,7 +779,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, if (la57) { pml5e_addr = ((env->cr[3] & ~0xfff) + - (((addr >> 48) & 0x1ff) << 3)) & env->a20_mask; + (((addr >> 48) & 0x1ff) << 3)) & a20_mask; pml5e = x86_ldq_phys(cs, pml5e_addr); if (!(pml5e & PG_PRESENT_MASK)) { goto do_fault; @@ -796,7 +798,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, } pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + - (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; + (((addr >> 39) & 0x1ff) << 3)) & a20_mask; pml4e = x86_ldq_phys(cs, pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { goto do_fault; @@ -810,7 +812,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, } ptep &= pml4e ^ PG_NX_MASK; pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & - env->a20_mask; + a20_mask; pdpe = x86_ldq_phys(cs, pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { goto do_fault; @@ -835,7 +837,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, { /* XXX: load them when cr3 is loaded ? */ pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & - env->a20_mask; + a20_mask; pdpe = x86_ldq_phys(cs, pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { goto do_fault; @@ -848,7 +850,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, } pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & - env->a20_mask; + a20_mask; pde = x86_ldq_phys(cs, pde_addr); if (!(pde & PG_PRESENT_MASK)) { goto do_fault; @@ -870,7 +872,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, x86_stl_phys_notdirty(cs, pde_addr, pde); } pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & - env->a20_mask; + a20_mask; pte = x86_ldq_phys(cs, pte_addr); if (!(pte & PG_PRESENT_MASK)) { goto do_fault; @@ -886,7 +888,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, /* page directory entry */ pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & - env->a20_mask; + a20_mask; pde = x86_ldl_phys(cs, pde_addr); if (!(pde & PG_PRESENT_MASK)) { goto do_fault; @@ -913,7 +915,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, /* page directory entry */ pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & - env->a20_mask; + a20_mask; pte = x86_ldl_phys(cs, pte_addr); if (!(pte & PG_PRESENT_MASK)) { goto do_fault; @@ -992,7 +994,7 @@ do_check_protect_pse36: } do_mapping: - pte = pte & env->a20_mask; + pte = pte & a20_mask; /* align to page_size */ pte &= PG_ADDRESS_MASK & ~(page_size - 1); @@ -1039,11 +1041,13 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) CPUX86State *env = &cpu->env; target_ulong pde_addr, pte_addr; uint64_t pte; + int32_t a20_mask; uint32_t page_offset; int page_size; + a20_mask = x86_get_a20_mask(env); if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr & env->a20_mask; + pte = addr & a20_mask; page_size = 4096; } else if (env->cr[4] & CR4_PAE_MASK) { target_ulong pdpe_addr; @@ -1064,7 +1068,7 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) if (la57) { pml5e_addr = ((env->cr[3] & ~0xfff) + - (((addr >> 48) & 0x1ff) << 3)) & env->a20_mask; + (((addr >> 48) & 0x1ff) << 3)) & a20_mask; pml5e = x86_ldq_phys(cs, pml5e_addr); if (!(pml5e & PG_PRESENT_MASK)) { return -1; @@ -1074,13 +1078,13 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) } pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + - (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; + (((addr >> 39) & 0x1ff) << 3)) & a20_mask; pml4e = x86_ldq_phys(cs, pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { return -1; } pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + - (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; + (((addr >> 30) & 0x1ff) << 3)) & a20_mask; pdpe = x86_ldq_phys(cs, pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { return -1; @@ -1095,14 +1099,14 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) #endif { pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & - env->a20_mask; + a20_mask; pdpe = x86_ldq_phys(cs, pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) return -1; } pde_addr = ((pdpe & PG_ADDRESS_MASK) + - (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask; + (((addr >> 21) & 0x1ff) << 3)) & a20_mask; pde = x86_ldq_phys(cs, pde_addr); if (!(pde & PG_PRESENT_MASK)) { return -1; @@ -1114,7 +1118,7 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) } else { /* 4 KB page */ pte_addr = ((pde & PG_ADDRESS_MASK) + - (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask; + (((addr >> 12) & 0x1ff) << 3)) & a20_mask; page_size = 4096; pte = x86_ldq_phys(cs, pte_addr); } @@ -1125,7 +1129,7 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) uint32_t pde; /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask; + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask; pde = x86_ldl_phys(cs, pde_addr); if (!(pde & PG_PRESENT_MASK)) return -1; @@ -1134,14 +1138,14 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) page_size = 4096 * 1024; } else { /* page directory entry */ - pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask; pte = x86_ldl_phys(cs, pte_addr); if (!(pte & PG_PRESENT_MASK)) { return -1; } page_size = 4096; } - pte = pte & env->a20_mask; + pte = pte & a20_mask; } #ifdef TARGET_X86_64 @@ -1399,89 +1403,89 @@ uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - return address_space_ldub(cs->as, addr, - cpu_get_mem_attrs(env), - NULL); + return address_space_ldub(as, addr, attrs, NULL); } uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - return address_space_lduw(cs->as, addr, - cpu_get_mem_attrs(env), - NULL); + return address_space_lduw(as, addr, attrs, NULL); } uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - return address_space_ldl(cs->as, addr, - cpu_get_mem_attrs(env), - NULL); + return address_space_ldl(as, addr, attrs, NULL); } uint64_t x86_ldq_phys(CPUState *cs, hwaddr addr) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - return address_space_ldq(cs->as, addr, - cpu_get_mem_attrs(env), - NULL); + return address_space_ldq(as, addr, attrs, NULL); } void x86_stb_phys(CPUState *cs, hwaddr addr, uint8_t val) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - address_space_stb(cs->as, addr, val, - cpu_get_mem_attrs(env), - NULL); + address_space_stb(as, addr, val, attrs, NULL); } void x86_stl_phys_notdirty(CPUState *cs, hwaddr addr, uint32_t val) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - address_space_stl_notdirty(cs->as, addr, val, - cpu_get_mem_attrs(env), - NULL); + address_space_stl_notdirty(as, addr, val, attrs, NULL); } void x86_stw_phys(CPUState *cs, hwaddr addr, uint32_t val) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - address_space_stw(cs->as, addr, val, - cpu_get_mem_attrs(env), - NULL); + address_space_stw(as, addr, val, attrs, NULL); } void x86_stl_phys(CPUState *cs, hwaddr addr, uint32_t val) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - address_space_stl(cs->as, addr, val, - cpu_get_mem_attrs(env), - NULL); + address_space_stl(as, addr, val, attrs, NULL); } void x86_stq_phys(CPUState *cs, hwaddr addr, uint64_t val) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; + MemTxAttrs attrs = cpu_get_mem_attrs(env); + AddressSpace *as = cpu_addressspace(cs, attrs); - address_space_stq(cs->as, addr, val, - cpu_get_mem_attrs(env), - NULL); + address_space_stq(as, addr, val, attrs, NULL); } #endif diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 49b6115..ee36502 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -43,6 +43,7 @@ #include "standard-headers/asm-x86/hyperv.h" #include "hw/pci/pci.h" #include "hw/pci/msi.h" +#include "hw/pci/msix.h" #include "migration/blocker.h" #include "exec/memattrs.h" #include "trace.h" @@ -1254,7 +1255,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } - if (kvm_check_extension(s, KVM_CAP_X86_SMM)) { + if (kvm_check_extension(s, KVM_CAP_X86_SMM) && + object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE) && + pc_machine_is_smm_enabled(PC_MACHINE(ms))) { smram_machine_done.notify = register_smram_listener; qemu_add_machine_init_done_notifier(&smram_machine_done); } @@ -1300,18 +1303,14 @@ static void get_seg(SegmentCache *lhs, const struct kvm_segment *rhs) lhs->selector = rhs->selector; lhs->base = rhs->base; lhs->limit = rhs->limit; - if (rhs->unusable) { - lhs->flags = 0; - } else { - lhs->flags = (rhs->type << DESC_TYPE_SHIFT) | - (rhs->present * DESC_P_MASK) | - (rhs->dpl << DESC_DPL_SHIFT) | - (rhs->db << DESC_B_SHIFT) | - (rhs->s * DESC_S_MASK) | - (rhs->l << DESC_L_SHIFT) | - (rhs->g * DESC_G_MASK) | - (rhs->avl * DESC_AVL_MASK); - } + lhs->flags = (rhs->type << DESC_TYPE_SHIFT) | + ((rhs->present && !rhs->unusable) * DESC_P_MASK) | + (rhs->dpl << DESC_DPL_SHIFT) | + (rhs->db << DESC_B_SHIFT) | + (rhs->s * DESC_S_MASK) | + (rhs->l << DESC_L_SHIFT) | + (rhs->g * DESC_G_MASK) | + (rhs->avl * DESC_AVL_MASK); } static void kvm_getput_reg(__u64 *kvm_reg, target_ulong *qemu_reg, int set) @@ -3510,12 +3509,17 @@ static void kvm_update_msi_routes_all(void *private, bool global, int cnt = 0; MSIRouteEntry *entry; MSIMessage msg; + PCIDevice *dev; + /* TODO: explicit route update */ QLIST_FOREACH(entry, &msi_route_list, list) { cnt++; - msg = pci_get_msi_message(entry->dev, entry->vector); - kvm_irqchip_update_msi_route(kvm_state, entry->virq, - msg, entry->dev); + dev = entry->dev; + if (!msix_enabled(dev) && !msi_enabled(dev)) { + continue; + } + msg = pci_get_msi_message(dev, entry->vector); + kvm_irqchip_update_msi_route(kvm_state, entry->virq, msg, dev); } kvm_irqchip_commit_routes(kvm_state); trace_kvm_x86_update_msi_routes(cnt); diff --git a/target/i386/machine.c b/target/i386/machine.c index 3cb2729..8c7a822 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -274,10 +274,6 @@ static int cpu_post_load(void *opaque, int version_id) cpu_x86_update_dr7(env, dr7); } tlb_flush(cs); - - if (tcg_enabled()) { - cpu_smm_update(cpu); - } return 0; } diff --git a/target/i386/smm_helper.c b/target/i386/smm_helper.c index f051a77..90621e5 100644 --- a/target/i386/smm_helper.c +++ b/target/i386/smm_helper.c @@ -43,19 +43,6 @@ void helper_rsm(CPUX86State *env) #define SMM_REVISION_ID 0x00020000 #endif -/* Called with iothread lock taken */ -void cpu_smm_update(X86CPU *cpu) -{ - CPUX86State *env = &cpu->env; - bool smm_enabled = (env->hflags & HF_SMM_MASK); - - g_assert(qemu_mutex_iothread_locked()); - - if (cpu->smram) { - memory_region_set_enabled(cpu->smram, smm_enabled); - } -} - void do_smm_enter(X86CPU *cpu) { CPUX86State *env = &cpu->env; @@ -73,7 +60,6 @@ void do_smm_enter(X86CPU *cpu) } else { env->hflags2 |= HF2_NMI_MASK; } - cpu_smm_update(cpu); sm_state = env->smbase + 0x8000; @@ -338,10 +324,6 @@ void helper_rsm(CPUX86State *env) env->hflags2 &= ~HF2_SMM_INSIDE_NMI_MASK; env->hflags &= ~HF_SMM_MASK; - qemu_mutex_lock_iothread(); - cpu_smm_update(cpu); - qemu_mutex_unlock_iothread(); - qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP); } diff --git a/target/i386/translate.c b/target/i386/translate.c index 674ec96..ed3b896 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -7939,14 +7939,26 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); if (b & 2) { + if (s->tb->cflags & CF_USE_ICOUNT) { + gen_io_start(); + } gen_op_mov_v_reg(ot, cpu_T0, rm); gen_helper_write_crN(cpu_env, tcg_const_i32(reg), cpu_T0); + if (s->tb->cflags & CF_USE_ICOUNT) { + gen_io_end(); + } gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { + if (s->tb->cflags & CF_USE_ICOUNT) { + gen_io_start(); + } gen_helper_read_crN(cpu_T0, cpu_env, tcg_const_i32(reg)); gen_op_mov_reg_v(ot, rm, cpu_T0); + if (s->tb->cflags & CF_USE_ICOUNT) { + gen_io_end(); + } } break; default: diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index fc3cb25..b34318f 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -184,6 +184,7 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, S390FeatBitmap features) { const S390CPUDef *last_compatible = NULL; + const S390CPUDef *matching_cpu_type = NULL; int i; if (!gen) { @@ -218,8 +219,16 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, if (def->type == type && def->ec_ga == ec_ga) { return def; } + /* remember if we've at least seen one with the same cpu type */ + if (def->type == type) { + matching_cpu_type = def; + } last_compatible = def; } + /* prefer the model with the same cpu type, esp. don't take the BC for EC */ + if (matching_cpu_type) { + return matching_cpu_type; + } return last_compatible; } @@ -767,6 +776,7 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp) /* copy over properties that can vary */ cpu->model->lowest_ibc = max_model->lowest_ibc; cpu->model->cpu_id = max_model->cpu_id; + cpu->model->cpu_id_format = max_model->cpu_id_format; cpu->model->cpu_ver = max_model->cpu_ver; check_consistency(cpu->model); diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h index 136a602..d41f8d6 100644 --- a/target/s390x/cpu_models.h +++ b/target/s390x/cpu_models.h @@ -46,6 +46,7 @@ typedef struct S390CPUModel { /* values copied from the "host" model, can change during migration */ uint16_t lowest_ibc; /* lowest IBC that the hardware supports */ uint32_t cpu_id; /* CPU id */ + uint8_t cpu_id_format; /* CPU id format bit */ uint8_t cpu_ver; /* CPU version, usually "ff" for kvm */ } S390CPUModel; @@ -54,12 +55,14 @@ typedef struct S390CPUModel { * * bits 0-7: Zeroes (ff for kvm) * bits 8-31: CPU ID (serial number) - * bits 32-48: Machine type - * bits 48-63: Zeroes + * bits 32-47: Machine type + * bit 48: CPU ID format + * bits 49-63: Zeroes */ #define cpuid_type(x) (((x) >> 16) & 0xffff) #define cpuid_id(x) (((x) >> 32) & 0xffffff) #define cpuid_ver(x) (((x) >> 56) & 0xff) +#define cpuid_format(x) (((x) >> 15) & 0x1) #define lowest_ibc(x) (((uint32_t)(x) >> 16) & 0xfff) #define unblocked_ibc(x) ((uint32_t)(x) & 0xfff) @@ -92,7 +95,8 @@ static inline uint64_t s390_cpuid_from_cpu_model(const S390CPUModel *model) { return ((uint64_t)model->cpu_ver << 56) | ((uint64_t)model->cpu_id << 32) | - ((uint64_t)model->def->type << 16); + ((uint64_t)model->def->type << 16) | + (model->def->gen == 7 ? 0 : (uint64_t)model->cpu_id_format << 15); } S390CPUDef const *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, S390FeatBitmap features); diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 62a7771..d5e6b80 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -201,6 +201,10 @@ static int ioinst_orb_valid(ORB *orb) (orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) { return 0; } + /* We don't support MIDA. */ + if (orb->ctrl1 & ORB_CTRL1_MASK_MIDAW) { + return 0; + } if ((orb->cpa & HIGH_ORDER_BIT) != 0) { return 0; } diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index ba1e60f..a3d0019 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -2580,6 +2580,7 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp) unblocked_ibc = unblocked_ibc(prop.ibc); } model->cpu_id = cpuid_id(prop.cpuid); + model->cpu_id_format = cpuid_format(prop.cpuid); model->cpu_ver = 0xff; /* get supported cpu features indicated via STFL(E) */ diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 5bdaf3d..9d381d9 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -70,7 +70,9 @@ class ImageCommitTestCase(iotests.QMPTestCase): self.wait_for_complete() class TestSingleDrive(ImageCommitTestCase): - image_len = 1 * 1024 * 1024 + # Need some space after the copied data so that throttling is effective in + # tests that use it rather than just completing the job immediately + image_len = 2 * 1024 * 1024 test_len = 1 * 1024 * 256 def setUp(self): @@ -79,7 +81,9 @@ class TestSingleDrive(ImageCommitTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img) qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img) - self.vm = iotests.VM().add_drive(test_img) + self.vm = iotests.VM().add_drive(test_img, interface="none") + self.vm.add_device("virtio-scsi-pci") + self.vm.add_device("scsi-hd,id=scsi0,drive=drive0") self.vm.launch() def tearDown(self): @@ -131,6 +135,33 @@ class TestSingleDrive(ImageCommitTestCase): self.assert_qmp(result, 'error/class', 'GenericError') self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img) + # When the job is running on a BB that is automatically deleted on hot + # unplug, the job is cancelled when the device disappears + def test_hot_unplug(self): + if self.image_len == 0: + return + + self.assert_no_active_block_jobs() + result = self.vm.qmp('block-commit', device='drive0', top=mid_img, + base=backing_img, speed=(self.image_len / 4)) + self.assert_qmp(result, 'return', {}) + result = self.vm.qmp('device_del', id='scsi0') + self.assert_qmp(result, 'return', {}) + + cancelled = False + deleted = False + while not cancelled or not deleted: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'DEVICE_DELETED': + self.assert_qmp(event, 'data/device', 'scsi0') + deleted = True + elif event['event'] == 'BLOCK_JOB_CANCELLED': + self.assert_qmp(event, 'data/device', 'drive0') + cancelled = True + else: + self.fail("Unexpected event %s" % (event['event'])) + + self.assert_no_active_block_jobs() class TestRelativePaths(ImageCommitTestCase): image_len = 1 * 1024 * 1024 diff --git a/tests/qemu-iotests/040.out b/tests/qemu-iotests/040.out index 4fd1c2d..6d9bee1 100644 --- a/tests/qemu-iotests/040.out +++ b/tests/qemu-iotests/040.out @@ -1,5 +1,5 @@ -......................... +........................... ---------------------------------------------------------------------- -Ran 25 tests +Ran 27 tests OK diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out index 0c13888..a24c6bf 100644 --- a/tests/qemu-iotests/083.out +++ b/tests/qemu-iotests/083.out @@ -69,10 +69,12 @@ read failed: Input/output error === Check disconnect 4 reply === +read failed read failed: Input/output error === Check disconnect 8 reply === +read failed read failed: Input/output error === Check disconnect before data === diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183 new file mode 100755 index 0000000..20268ff --- /dev/null +++ b/tests/qemu-iotests/183 @@ -0,0 +1,140 @@ +#!/bin/bash +# +# Test old-style block migration (migrate -b) +# +# Copyright (C) 2017 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=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +MIG_SOCKET="${TEST_DIR}/migrate" + +_cleanup() +{ + rm -f "${MIG_SOCKET}" + rm -f "${TEST_IMG}.dest" + _cleanup_test_img + _cleanup_qemu +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 raw qed dmg quorum +_supported_proto file +_supported_os Linux + +size=64M +_make_test_img $size +TEST_IMG="${TEST_IMG}.dest" _make_test_img $size + +echo +echo === Starting VMs === +echo + +qemu_comm_method="qmp" + +_launch_qemu \ + -drive file="${TEST_IMG}",cache=$CACHEMODE,driver=$IMGFMT,id=disk +src=$QEMU_HANDLE +_send_qemu_cmd $src "{ 'execute': 'qmp_capabilities' }" 'return' + +_launch_qemu \ + -drive file="${TEST_IMG}.dest",cache=$CACHEMODE,driver=$IMGFMT,id=disk \ + -incoming "unix:${MIG_SOCKET}" +dest=$QEMU_HANDLE +_send_qemu_cmd $dest "{ 'execute': 'qmp_capabilities' }" 'return' + +echo +echo === Write something on the source === +echo + +_send_qemu_cmd $src \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io disk \"write -P 0x55 0 64k\"' } }" \ + 'return' +_send_qemu_cmd $src \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io disk \"read -P 0x55 0 64k\"' } }" \ + 'return' + +echo +echo === Do block migration to destination === +echo + +reply="$(_send_qemu_cmd $src \ + "{ 'execute': 'migrate', + 'arguments': { 'uri': 'unix:${MIG_SOCKET}', 'blk': true } }" \ + 'return\|error')" +echo "$reply" +if echo "$reply" | grep "compiled without old-style" > /dev/null; then + _notrun "migrate -b support not compiled in" +fi + +QEMU_COMM_TIMEOUT=0.1 qemu_cmd_repeat=50 silent=yes \ + _send_qemu_cmd $src "{ 'execute': 'query-migrate' }" '"status": "completed"' +_send_qemu_cmd $src "{ 'execute': 'query-status' }" "return" + +echo +echo === Do some I/O on the destination === +echo + +# It is important that we use the BlockBackend of the guest device here instead +# of the node name, which would create a new BlockBackend and not test whether +# the guest has the necessary permissions to access the image now +silent=yes _send_qemu_cmd $dest "" "100 %" +_send_qemu_cmd $dest "{ 'execute': 'query-status' }" "return" +_send_qemu_cmd $dest \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io disk \"read -P 0x55 0 64k\"' } }" \ + 'return' +_send_qemu_cmd $dest \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io disk \"write -P 0x66 1M 64k\"' } }" \ + 'return' + +echo +echo === Shut down and check image === +echo + +_send_qemu_cmd $src '{"execute":"quit"}' 'return' +_send_qemu_cmd $dest '{"execute":"quit"}' 'return' +wait=1 _cleanup_qemu + +_check_test_img +TEST_IMG="${TEST_IMG}.dest" _check_test_img + +$QEMU_IO -c 'write -P 0x66 1M 64k' "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG compare "$TEST_IMG.dest" "$TEST_IMG" + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/183.out b/tests/qemu-iotests/183.out new file mode 100644 index 0000000..103fdc7 --- /dev/null +++ b/tests/qemu-iotests/183.out @@ -0,0 +1,46 @@ +QA output created by 183 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT.dest', fmt=IMGFMT size=67108864 + +=== Starting VMs === + +{"return": {}} +{"return": {}} + +=== Write something on the source === + +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} + +=== Do block migration to destination === + +{"return": {}} +{"return": {"status": "postmigrate", "singlestep": false, "running": false}} + +=== Do some I/O on the destination === + +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "RESUME"} +{"return": {"status": "running", "singlestep": false, "running": true}} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +wrote 65536/65536 bytes at offset 1048576 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} + +=== Shut down and check image === + +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} +No errors were found on the image. +No errors were found on the image. +wrote 65536/65536 bytes at offset 1048576 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Images are identical. +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 5c8ea0f..a6acaff 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -174,3 +174,4 @@ 179 rw auto quick 181 rw auto migration 182 rw auto quick +183 rw auto migration diff --git a/tests/rtc-test.c b/tests/rtc-test.c index a086efd..e78f701 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "libqtest.h" +#include "qemu/timer.h" #include "hw/timer/mc146818rtc_regs.h" static uint8_t base = 0x70; @@ -542,6 +543,52 @@ static void register_b_set_flag(void) g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20); } +#define RTC_PERIOD_CODE1 13 /* 8 Hz */ +#define RTC_PERIOD_CODE2 15 /* 2 Hz */ + +#define RTC_PERIOD_TEST_NR 50 + +static uint64_t wait_periodic_interrupt(uint64_t real_time) +{ + while (!get_irq(RTC_ISA_IRQ)) { + real_time = clock_step_next(); + } + + g_assert((cmos_read(RTC_REG_C) & REG_C_PF) != 0); + return real_time; +} + +static void periodic_timer(void) +{ + int i; + uint64_t period_clocks, period_time, start_time, real_time; + + /* disable all interrupts. */ + cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & + ~(REG_B_PIE | REG_B_AIE | REG_B_UIE)); + cmos_write(RTC_REG_A, RTC_PERIOD_CODE1); + /* enable periodic interrupt after properly configure the period. */ + cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_PIE); + + start_time = real_time = clock_step_next(); + + for (i = 0; i < RTC_PERIOD_TEST_NR; i++) { + cmos_write(RTC_REG_A, RTC_PERIOD_CODE1); + real_time = wait_periodic_interrupt(real_time); + cmos_write(RTC_REG_A, RTC_PERIOD_CODE2); + real_time = wait_periodic_interrupt(real_time); + } + + period_clocks = periodic_period_to_clock(RTC_PERIOD_CODE1) + + periodic_period_to_clock(RTC_PERIOD_CODE2); + period_clocks *= RTC_PERIOD_TEST_NR; + period_time = periodic_clock_to_ns(period_clocks); + + real_time -= start_time; + g_assert_cmpint(ABS((int64_t)(real_time - period_time)), <=, + NANOSECONDS_PER_SECOND * 0.5); +} + int main(int argc, char **argv) { QTestState *s = NULL; @@ -564,6 +611,8 @@ int main(int argc, char **argv) qtest_add_func("/rtc/set-year/1980", set_year_1980); qtest_add_func("/rtc/misc/register_b_set_flag", register_b_set_flag); qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers); + qtest_add_func("/rtc/periodic/interrupt", periodic_timer); + ret = g_test_run(); if (s) { diff --git a/tests/test-char.c b/tests/test-char.c index dfe856c..9e361c8 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -450,6 +450,32 @@ static void char_udp_test(void) g_free(tmp); } +#ifdef HAVE_CHARDEV_SERIAL +static void char_serial_test(void) +{ + QemuOpts *opts; + Chardev *chr; + + opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id", + 1, &error_abort); + qemu_opt_set(opts, "backend", "serial", &error_abort); + qemu_opt_set(opts, "path", "/dev/null", &error_abort); + + chr = qemu_chr_new_from_opts(opts, NULL); + g_assert_nonnull(chr); + /* TODO: add more tests with a pty */ + object_unparent(OBJECT(chr)); + + /* test tty alias */ + qemu_opt_set(opts, "backend", "tty", &error_abort); + chr = qemu_chr_new_from_opts(opts, NULL); + g_assert_nonnull(chr); + object_unparent(OBJECT(chr)); + + qemu_opts_del(opts); +} +#endif + static void char_file_test(void) { char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); @@ -597,6 +623,9 @@ int main(int argc, char **argv) g_test_add_func("/char/file", char_file_test); g_test_add_func("/char/socket", char_socket_test); g_test_add_func("/char/udp", char_udp_test); +#ifdef HAVE_CHARDEV_SERIAL + g_test_add_func("/char/serial", char_serial_test); +#endif return g_test_run(); } diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c index 8618c20..1e5b5ca 100644 --- a/tests/vhost-user-bridge.c +++ b/tests/vhost-user-bridge.c @@ -220,12 +220,18 @@ vubr_handle_tx(VuDev *dev, int qidx) free(elem); } + +/* this function reverse the effect of iov_discard_front() it must be + * called with 'front' being the original struct iovec and 'bytes' + * being the number of bytes you shaved off + */ static void iov_restore_front(struct iovec *front, struct iovec *iov, size_t bytes) { struct iovec *cur; - for (cur = front; front != iov; cur++) { + for (cur = front; cur != iov; cur++) { + assert(bytes >= cur->iov_len); bytes -= cur->iov_len; } @@ -302,7 +308,8 @@ vubr_backend_recv_cb(int sock, void *ctx) } iov_from_buf(sg, elem->in_num, 0, &hdr, sizeof hdr); total += hdrlen; - assert(iov_discard_front(&sg, &num, hdrlen) == hdrlen); + ret = iov_discard_front(&sg, &num, hdrlen); + assert(ret == hdrlen); } struct msghdr msg = { diff --git a/trace-events b/trace-events index d7a4d94..b496be9 100644 --- a/trace-events +++ b/trace-events @@ -62,8 +62,9 @@ kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p" kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s" kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s" kvm_irqchip_commit_routes(void) "" -kvm_irqchip_add_msi_route(int virq) "Adding MSI route virq=%d" +kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d" kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d" +kvm_irqchip_release_virq(int virq) "virq %d" # TCG related tracing (mostly disabled by default) # cpu-exec.c diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 7e28c16..5e8b4b3 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -182,7 +182,9 @@ void qemu_set_cloexec(int fd) { int f; f = fcntl(fd, F_GETFD); - fcntl(fd, F_SETFD, f | FD_CLOEXEC); + assert(f != -1); + f = fcntl(fd, F_SETFD, f | FD_CLOEXEC); + assert(f != -1); } /* @@ -400,7 +402,7 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, /* touch pages simultaneously */ if (touch_all_pages(area, hpagesize, numpages, smp_cpus)) { error_setg(errp, "os_mem_prealloc: Insufficient free host memory " - "pages available to allocate guest RAM\n"); + "pages available to allocate guest RAM"); } ret = sigaction(SIGBUS, &oldact, NULL); diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index 6328eed..b44b5d5 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -77,10 +77,25 @@ void coroutine_fn qemu_co_queue_wait(CoQueue *queue, CoMutex *mutex) void qemu_co_queue_run_restart(Coroutine *co) { Coroutine *next; + QSIMPLEQ_HEAD(, Coroutine) tmp_queue_wakeup = + QSIMPLEQ_HEAD_INITIALIZER(tmp_queue_wakeup); trace_qemu_co_queue_run_restart(co); - while ((next = QSIMPLEQ_FIRST(&co->co_queue_wakeup))) { - QSIMPLEQ_REMOVE_HEAD(&co->co_queue_wakeup, co_queue_next); + + /* Because "co" has yielded, any coroutine that we wakeup can resume it. + * If this happens and "co" terminates, co->co_queue_wakeup becomes + * invalid memory. Therefore, use a temporary queue and do not touch + * the "co" coroutine as soon as you enter another one. + * + * In its turn resumed "co" can pupulate "co_queue_wakeup" queue with + * new coroutines to be woken up. The caller, who has resumed "co", + * will be responsible for traversing the same queue, which may cause + * a different wakeup order but not any missing wakeups. + */ + QSIMPLEQ_CONCAT(&tmp_queue_wakeup, &co->co_queue_wakeup); + + while ((next = QSIMPLEQ_FIRST(&tmp_queue_wakeup))) { + QSIMPLEQ_REMOVE_HEAD(&tmp_queue_wakeup, co_queue_next); qemu_coroutine_enter(next); } } diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 486af9a..d6095c1 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -126,6 +126,11 @@ void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co) qemu_co_queue_run_restart(co); + /* Beware, if ret == COROUTINE_YIELD and qemu_co_queue_run_restart() + * has started any other coroutine, "co" might have been reentered + * and even freed by now! So be careful and do not touch it. + */ + switch (ret) { case COROUTINE_YIELD: return; diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index b39ae74..82290cb 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -845,6 +845,8 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, { struct sockaddr_un un; int sock, fd; + char *pathbuf = NULL; + const char *path; sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { @@ -852,20 +854,22 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, return -1; } - memset(&un, 0, sizeof(un)); - un.sun_family = AF_UNIX; - if (saddr->path && strlen(saddr->path)) { - snprintf(un.sun_path, sizeof(un.sun_path), "%s", saddr->path); + if (saddr->path && saddr->path[0]) { + path = saddr->path; } else { const char *tmpdir = getenv("TMPDIR"); tmpdir = tmpdir ? tmpdir : "/tmp"; - if (snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", - tmpdir) >= sizeof(un.sun_path)) { - error_setg_errno(errp, errno, - "TMPDIR environment variable (%s) too large", tmpdir); - goto err; - } + path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", tmpdir); + } + if (strlen(path) > sizeof(un.sun_path)) { + error_setg(errp, "UNIX socket path '%s' is too long", path); + error_append_hint(errp, "Path must be less than %zu bytes\n", + sizeof(un.sun_path)); + goto err; + } + + if (pathbuf != NULL) { /* * This dummy fd usage silences the mktemp() unsecure warning. * Using mkstemp() doesn't make things more secure here @@ -873,24 +877,25 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, * to unlink first and thus re-open the race window. The * worst case possible is bind() failing, i.e. a DoS attack. */ - fd = mkstemp(un.sun_path); + fd = mkstemp(pathbuf); if (fd < 0) { error_setg_errno(errp, errno, - "Failed to make a temporary socket name in %s", tmpdir); + "Failed to make a temporary socket %s", pathbuf); goto err; } close(fd); - if (update_addr) { - g_free(saddr->path); - saddr->path = g_strdup(un.sun_path); - } } - if (unlink(un.sun_path) < 0 && errno != ENOENT) { + if (unlink(path) < 0 && errno != ENOENT) { error_setg_errno(errp, errno, - "Failed to unlink socket %s", un.sun_path); + "Failed to unlink socket %s", path); goto err; } + + memset(&un, 0, sizeof(un)); + un.sun_family = AF_UNIX; + strncpy(un.sun_path, path, sizeof(un.sun_path)); + if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { error_setg_errno(errp, errno, "Failed to bind socket to %s", un.sun_path); goto err; @@ -900,9 +905,16 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, goto err; } + if (update_addr && pathbuf) { + g_free(saddr->path); + saddr->path = pathbuf; + } else { + g_free(pathbuf); + } return sock; err: + g_free(pathbuf); closesocket(sock); return -1; } @@ -932,9 +944,16 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, qemu_set_nonblock(sock); } + if (strlen(saddr->path) > sizeof(un.sun_path)) { + error_setg(errp, "UNIX socket path '%s' is too long", saddr->path); + error_append_hint(errp, "Path must be less than %zu bytes\n", + sizeof(un.sun_path)); + goto err; + } + memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; - snprintf(un.sun_path, sizeof(un.sun_path), "%s", saddr->path); + strncpy(un.sun_path, saddr->path, sizeof(un.sun_path)); /* connect to peer */ do { @@ -956,13 +975,18 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, } if (rc < 0) { - error_setg_errno(errp, -rc, "Failed to connect socket"); - close(sock); - sock = -1; + error_setg_errno(errp, -rc, "Failed to connect socket %s", + saddr->path); + goto err; } g_free(connect_state); return sock; + + err: + close(sock); + g_free(connect_state); + return -1; } #else |