diff options
-rw-r--r-- | MAINTAINERS | 14 | ||||
-rw-r--r-- | Makefile.objs | 10 | ||||
-rw-r--r-- | cputlb.c | 3 | ||||
-rw-r--r-- | exec.c | 10 | ||||
-rw-r--r-- | hw/display/qxl-render.c | 2 | ||||
-rw-r--r-- | hw/display/qxl.c | 8 | ||||
-rw-r--r-- | include/exec/cpu-all.h | 7 | ||||
-rw-r--r-- | include/qemu/log.h | 1 | ||||
-rw-r--r-- | include/ui/spice-display.h | 3 | ||||
-rw-r--r-- | migration/Makefile.objs | 10 | ||||
-rw-r--r-- | migration/block.c (renamed from block-migration.c) | 0 | ||||
-rw-r--r-- | migration/exec.c (renamed from migration-exec.c) | 0 | ||||
-rw-r--r-- | migration/fd.c (renamed from migration-fd.c) | 0 | ||||
-rw-r--r-- | migration/migration.c (renamed from migration.c) | 0 | ||||
-rw-r--r-- | migration/qemu-file-buf.c (renamed from qemu-file.c) | 511 | ||||
-rw-r--r-- | migration/qemu-file-internal.h | 53 | ||||
-rw-r--r-- | migration/qemu-file-stdio.c (renamed from qemu-file-stdio.c) | 0 | ||||
-rw-r--r-- | migration/qemu-file-unix.c (renamed from qemu-file-unix.c) | 0 | ||||
-rw-r--r-- | migration/qemu-file.c | 519 | ||||
-rw-r--r-- | migration/rdma.c (renamed from migration-rdma.c) | 0 | ||||
-rw-r--r-- | migration/tcp.c (renamed from migration-tcp.c) | 0 | ||||
-rw-r--r-- | migration/unix.c (renamed from migration-unix.c) | 0 | ||||
-rw-r--r-- | migration/vmstate.c (renamed from vmstate.c) | 0 | ||||
-rw-r--r-- | migration/xbzrle.c (renamed from xbzrle.c) | 0 | ||||
-rw-r--r-- | qemu-log.c | 2 | ||||
-rw-r--r-- | qmp-commands.hx | 6 | ||||
-rw-r--r-- | spice-qemu-char.c | 1 | ||||
-rw-r--r-- | target-cris/helper.c | 11 | ||||
-rw-r--r-- | target-i386/helper.c | 15 | ||||
-rw-r--r-- | target-microblaze/helper.c | 8 | ||||
-rw-r--r-- | target-mips/helper.c | 6 | ||||
-rw-r--r-- | target-ppc/mmu-hash32.c | 18 | ||||
-rw-r--r-- | target-ppc/mmu-hash64.c | 18 | ||||
-rw-r--r-- | target-ppc/mmu_helper.c | 26 | ||||
-rw-r--r-- | target-s390x/helper.c | 4 | ||||
-rw-r--r-- | target-sparc/mmu_helper.c | 7 | ||||
-rw-r--r-- | tests/Makefile | 11 | ||||
-rw-r--r-- | ui/spice-core.c | 10 | ||||
-rw-r--r-- | ui/spice-display.c | 45 |
39 files changed, 728 insertions, 611 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index bcb69e80d2..d72d6e37d0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -696,6 +696,14 @@ M: Amit Shah <amit.shah@redhat.com> S: Supported F: hw/char/virtio-serial-bus.c F: hw/char/virtio-console.c +F: include/hw/virtio/virtio-serial.h + +virtio-rng +M: Amit Shah <amit.shah@redhat.com> +S: Supported +F: hw/virtio/virtio-rng.c +F: include/hw/virtio/virtio-rng.h +F: backends/rng*.c nvme M: Keith Busch <keith.busch@intel.com> @@ -928,12 +936,14 @@ F: scripts/checkpatch.pl Migration M: Juan Quintela <quintela@redhat.com> +M: Amit Shah <amit.shah@redhat.com> S: Maintained F: include/migration/ -F: migration* +F: migration/ F: savevm.c F: arch_init.c -F: vmstate.c +F: scripts/vmstate-static-checker.py +F: tests/vmstate-static-checker-data/ Seccomp M: Eduardo Otubo <eduardo.otubo@profitbricks.com> diff --git a/Makefile.objs b/Makefile.objs index 18fd35cf15..abeb902b58 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -48,15 +48,9 @@ common-obj-$(CONFIG_POSIX) += os-posix.o common-obj-$(CONFIG_LINUX) += fsdev/ -common-obj-y += migration.o migration-tcp.o -common-obj-y += vmstate.o -common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o -common-obj-$(CONFIG_RDMA) += migration-rdma.o +common-obj-y += migration/ common-obj-y += qemu-char.o #aio.o -common-obj-y += block-migration.o -common-obj-y += page_cache.o xbzrle.o - -common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o +common-obj-y += page_cache.o common-obj-$(CONFIG_SPICE) += spice-qemu-char.o @@ -270,7 +270,8 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr, assert(sz >= TARGET_PAGE_SIZE); #if defined(DEBUG_TLB) - printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, + "tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx " prot=%x idx=%d\n", vaddr, paddr, prot, mmu_idx); #endif @@ -840,7 +840,7 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length) block = qemu_get_ram_block(start); assert(block == qemu_get_ram_block(end - 1)); - start1 = (uintptr_t)block->host + (start - block->offset); + start1 = (uintptr_t)ramblock_ptr(block, start - block->offset); cpu_tlb_reset_dirty_all(start1, length); } @@ -1500,7 +1500,7 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length) QTAILQ_FOREACH(block, &ram_list.blocks, next) { offset = addr - block->offset; if (offset < block->length) { - vaddr = block->host + offset; + vaddr = ramblock_ptr(block, offset); if (block->flags & RAM_PREALLOC) { ; } else if (xen_enabled()) { @@ -1551,7 +1551,7 @@ void *qemu_get_ram_block_host_ptr(ram_addr_t addr) { RAMBlock *block = qemu_get_ram_block(addr); - return block->host; + return ramblock_ptr(block, 0); } /* Return a host pointer to ram allocated with qemu_ram_alloc. @@ -1578,7 +1578,7 @@ void *qemu_get_ram_ptr(ram_addr_t addr) xen_map_cache(block->offset, block->length, 1); } } - return block->host + (addr - block->offset); + return ramblock_ptr(block, addr - block->offset); } /* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr @@ -1597,7 +1597,7 @@ static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size) if (addr - block->offset < block->length) { if (addr - block->offset + *size > block->length) *size = block->length - addr + block->offset; - return block->host + (addr - block->offset); + return ramblock_ptr(block, addr - block->offset); } } diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c index e812ddd6e7..a542087fcc 100644 --- a/hw/display/qxl-render.c +++ b/hw/display/qxl-render.c @@ -283,12 +283,14 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) qxl->ssd.mouse_x = cmd->u.set.position.x; qxl->ssd.mouse_y = cmd->u.set.position.y; qemu_mutex_unlock(&qxl->ssd.lock); + qemu_bh_schedule(qxl->ssd.cursor_bh); break; case QXL_CURSOR_MOVE: qemu_mutex_lock(&qxl->ssd.lock); qxl->ssd.mouse_x = cmd->u.position.x; qxl->ssd.mouse_y = cmd->u.position.y; qemu_mutex_unlock(&qxl->ssd.lock); + qemu_bh_schedule(qxl->ssd.cursor_bh); break; } return 0; diff --git a/hw/display/qxl.c b/hw/display/qxl.c index b540dd656c..61df477264 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1092,6 +1092,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) spice_qxl_driver_unload(&d->ssd.qxl); #endif graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga); + update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT); qemu_spice_create_host_primary(&d->ssd); d->mode = QXL_MODE_VGA; vga_dirty_log_start(&d->vga); @@ -1105,6 +1106,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d) } trace_qxl_exit_vga_mode(d->id); graphic_console_set_hwops(d->ssd.dcl.con, &qxl_ops, d); + update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE); vga_dirty_log_stop(&d->vga); qxl_destroy_primary(d, QXL_SYNC); } @@ -1153,6 +1155,7 @@ static void qxl_soft_reset(PCIQXLDevice *d) qxl_enter_vga_mode(d); } else { d->mode = QXL_MODE_UNDEFINED; + update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE); } } @@ -1861,10 +1864,6 @@ static void display_refresh(DisplayChangeListener *dcl) if (qxl->mode == QXL_MODE_VGA) { qemu_spice_display_refresh(&qxl->ssd); - } else { - qemu_mutex_lock(&qxl->ssd.lock); - qemu_spice_cursor_refresh_unlocked(&qxl->ssd); - qemu_mutex_unlock(&qxl->ssd.lock); } } @@ -2025,6 +2024,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) qxl_reset_state(qxl); qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl); + qxl->ssd.cursor_bh = qemu_bh_new(qemu_spice_cursor_refresh_bh, &qxl->ssd); return 0; } diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index c085804aed..62f558103d 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -313,6 +313,13 @@ typedef struct RAMBlock { int fd; } RAMBlock; +static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset) +{ + assert(offset < block->length); + assert(block->host); + return (char *)block->host + offset; +} + typedef struct RAMList { QemuMutex mutex; /* Protected by the iothread lock. */ diff --git a/include/qemu/log.h b/include/qemu/log.h index d5154246e6..195f665c4b 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -40,6 +40,7 @@ static inline bool qemu_log_enabled(void) #define CPU_LOG_RESET (1 << 9) #define LOG_UNIMP (1 << 10) #define LOG_GUEST_ERROR (1 << 11) +#define CPU_LOG_MMU (1 << 12) /* Returns true if a bit is set in the current loglevel mask */ diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 4252ab856f..53883a17fc 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -102,6 +102,7 @@ struct SimpleSpiceDisplay { /* cursor (with qxl): qxl local renderer -> displaychangelistener */ QEMUCursor *cursor; int mouse_x, mouse_y; + QEMUBH *cursor_bh; }; struct SimpleSpiceUpdate { @@ -134,7 +135,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, DisplaySurface *surface); void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); -void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd); +void qemu_spice_cursor_refresh_bh(void *opaque); void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, qxl_async_io async); diff --git a/migration/Makefile.objs b/migration/Makefile.objs new file mode 100644 index 0000000000..d929e969ae --- /dev/null +++ b/migration/Makefile.objs @@ -0,0 +1,10 @@ +common-obj-y += migration.o tcp.o +common-obj-y += vmstate.o +common-obj-y += qemu-file.o qemu-file-buf.o qemu-file-unix.o qemu-file-stdio.o +common-obj-y += xbzrle.o + +common-obj-$(CONFIG_RDMA) += rdma.o +common-obj-$(CONFIG_POSIX) += exec.o unix.o fd.o + +common-obj-y += block.o + diff --git a/block-migration.c b/migration/block.c index 74d9eb125c..74d9eb125c 100644 --- a/block-migration.c +++ b/migration/block.c diff --git a/migration-exec.c b/migration/exec.c index 479024752f..479024752f 100644 --- a/migration-exec.c +++ b/migration/exec.c diff --git a/migration-fd.c b/migration/fd.c index d2e523af74..d2e523af74 100644 --- a/migration-fd.c +++ b/migration/fd.c diff --git a/migration.c b/migration/migration.c index c49a05a165..c49a05a165 100644 --- a/migration.c +++ b/migration/migration.c diff --git a/qemu-file.c b/migration/qemu-file-buf.c index f938e36fe8..d33dd44747 100644 --- a/qemu-file.c +++ b/migration/qemu-file-buf.c @@ -27,518 +27,9 @@ #include "block/coroutine.h" #include "migration/migration.h" #include "migration/qemu-file.h" +#include "migration/qemu-file-internal.h" #include "trace.h" -#define IO_BUF_SIZE 32768 -#define MAX_IOV_SIZE MIN(IOV_MAX, 64) - -struct QEMUFile { - const QEMUFileOps *ops; - void *opaque; - - int64_t bytes_xfer; - int64_t xfer_limit; - - int64_t pos; /* start of buffer when writing, end of buffer - when reading */ - int buf_index; - int buf_size; /* 0 when writing */ - uint8_t buf[IO_BUF_SIZE]; - - struct iovec iov[MAX_IOV_SIZE]; - unsigned int iovcnt; - - int last_error; -}; - -bool qemu_file_mode_is_not_valid(const char *mode) -{ - if (mode == NULL || - (mode[0] != 'r' && mode[0] != 'w') || - mode[1] != 'b' || mode[2] != 0) { - fprintf(stderr, "qemu_fopen: Argument validity check failed\n"); - return true; - } - - return false; -} - -QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops) -{ - QEMUFile *f; - - f = g_malloc0(sizeof(QEMUFile)); - - f->opaque = opaque; - f->ops = ops; - return f; -} - -/* - * Get last error for stream f - * - * Return negative error value if there has been an error on previous - * operations, return 0 if no error happened. - * - */ -int qemu_file_get_error(QEMUFile *f) -{ - return f->last_error; -} - -void qemu_file_set_error(QEMUFile *f, int ret) -{ - if (f->last_error == 0) { - f->last_error = ret; - } -} - -bool qemu_file_is_writable(QEMUFile *f) -{ - return f->ops->writev_buffer || f->ops->put_buffer; -} - -/** - * Flushes QEMUFile buffer - * - * If there is writev_buffer QEMUFileOps it uses it otherwise uses - * put_buffer ops. - */ -void qemu_fflush(QEMUFile *f) -{ - ssize_t ret = 0; - - if (!qemu_file_is_writable(f)) { - return; - } - - if (f->ops->writev_buffer) { - if (f->iovcnt > 0) { - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos); - } - } else { - if (f->buf_index > 0) { - ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index); - } - } - if (ret >= 0) { - f->pos += ret; - } - f->buf_index = 0; - f->iovcnt = 0; - if (ret < 0) { - qemu_file_set_error(f, ret); - } -} - -void ram_control_before_iterate(QEMUFile *f, uint64_t flags) -{ - int ret = 0; - - if (f->ops->before_ram_iterate) { - ret = f->ops->before_ram_iterate(f, f->opaque, flags); - if (ret < 0) { - qemu_file_set_error(f, ret); - } - } -} - -void ram_control_after_iterate(QEMUFile *f, uint64_t flags) -{ - int ret = 0; - - if (f->ops->after_ram_iterate) { - ret = f->ops->after_ram_iterate(f, f->opaque, flags); - if (ret < 0) { - qemu_file_set_error(f, ret); - } - } -} - -void ram_control_load_hook(QEMUFile *f, uint64_t flags) -{ - int ret = -EINVAL; - - if (f->ops->hook_ram_load) { - ret = f->ops->hook_ram_load(f, f->opaque, flags); - if (ret < 0) { - qemu_file_set_error(f, ret); - } - } else { - qemu_file_set_error(f, ret); - } -} - -size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, - ram_addr_t offset, size_t size, int *bytes_sent) -{ - if (f->ops->save_page) { - int ret = f->ops->save_page(f, f->opaque, block_offset, - offset, size, bytes_sent); - - if (ret != RAM_SAVE_CONTROL_DELAYED) { - if (bytes_sent && *bytes_sent > 0) { - qemu_update_position(f, *bytes_sent); - } else if (ret < 0) { - qemu_file_set_error(f, ret); - } - } - - return ret; - } - - return RAM_SAVE_CONTROL_NOT_SUPP; -} - -/* - * Attempt to fill the buffer from the underlying file - * Returns the number of bytes read, or negative value for an error. - * - * Note that it can return a partially full buffer even in a not error/not EOF - * case if the underlying file descriptor gives a short read, and that can - * happen even on a blocking fd. - */ -static ssize_t qemu_fill_buffer(QEMUFile *f) -{ - int len; - int pending; - - assert(!qemu_file_is_writable(f)); - - pending = f->buf_size - f->buf_index; - if (pending > 0) { - memmove(f->buf, f->buf + f->buf_index, pending); - } - f->buf_index = 0; - f->buf_size = pending; - - len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos, - IO_BUF_SIZE - pending); - if (len > 0) { - f->buf_size += len; - f->pos += len; - } else if (len == 0) { - qemu_file_set_error(f, -EIO); - } else if (len != -EAGAIN) { - qemu_file_set_error(f, len); - } - - return len; -} - -int qemu_get_fd(QEMUFile *f) -{ - if (f->ops->get_fd) { - return f->ops->get_fd(f->opaque); - } - return -1; -} - -void qemu_update_position(QEMUFile *f, size_t size) -{ - f->pos += size; -} - -/** Closes the file - * - * Returns negative error value if any error happened on previous operations or - * while closing the file. Returns 0 or positive number on success. - * - * The meaning of return value on success depends on the specific backend - * being used. - */ -int qemu_fclose(QEMUFile *f) -{ - int ret; - qemu_fflush(f); - ret = qemu_file_get_error(f); - - if (f->ops->close) { - int ret2 = f->ops->close(f->opaque); - if (ret >= 0) { - ret = ret2; - } - } - /* If any error was spotted before closing, we should report it - * instead of the close() return value. - */ - if (f->last_error) { - ret = f->last_error; - } - g_free(f); - trace_qemu_file_fclose(); - return ret; -} - -static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size) -{ - /* check for adjacent buffer and coalesce them */ - if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base + - f->iov[f->iovcnt - 1].iov_len) { - f->iov[f->iovcnt - 1].iov_len += size; - } else { - f->iov[f->iovcnt].iov_base = (uint8_t *)buf; - f->iov[f->iovcnt++].iov_len = size; - } - - if (f->iovcnt >= MAX_IOV_SIZE) { - qemu_fflush(f); - } -} - -void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size) -{ - if (!f->ops->writev_buffer) { - qemu_put_buffer(f, buf, size); - return; - } - - if (f->last_error) { - return; - } - - f->bytes_xfer += size; - add_to_iovec(f, buf, size); -} - -void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) -{ - int l; - - if (f->last_error) { - return; - } - - while (size > 0) { - l = IO_BUF_SIZE - f->buf_index; - if (l > size) { - l = size; - } - memcpy(f->buf + f->buf_index, buf, l); - f->bytes_xfer += l; - if (f->ops->writev_buffer) { - add_to_iovec(f, f->buf + f->buf_index, l); - } - f->buf_index += l; - if (f->buf_index == IO_BUF_SIZE) { - qemu_fflush(f); - } - if (qemu_file_get_error(f)) { - break; - } - buf += l; - size -= l; - } -} - -void qemu_put_byte(QEMUFile *f, int v) -{ - if (f->last_error) { - return; - } - - f->buf[f->buf_index] = v; - f->bytes_xfer++; - if (f->ops->writev_buffer) { - add_to_iovec(f, f->buf + f->buf_index, 1); - } - f->buf_index++; - if (f->buf_index == IO_BUF_SIZE) { - qemu_fflush(f); - } -} - -void qemu_file_skip(QEMUFile *f, int size) -{ - if (f->buf_index + size <= f->buf_size) { - f->buf_index += size; - } -} - -/* - * Read 'size' bytes from file (at 'offset') into buf without moving the - * pointer. - * - * It will return size bytes unless there was an error, in which case it will - * return as many as it managed to read (assuming blocking fd's which - * all current QEMUFile are) - */ -int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) -{ - int pending; - int index; - - assert(!qemu_file_is_writable(f)); - assert(offset < IO_BUF_SIZE); - assert(size <= IO_BUF_SIZE - offset); - - /* The 1st byte to read from */ - index = f->buf_index + offset; - /* The number of available bytes starting at index */ - pending = f->buf_size - index; - - /* - * qemu_fill_buffer might return just a few bytes, even when there isn't - * an error, so loop collecting them until we get enough. - */ - while (pending < size) { - int received = qemu_fill_buffer(f); - - if (received <= 0) { - break; - } - - index = f->buf_index + offset; - pending = f->buf_size - index; - } - - if (pending <= 0) { - return 0; - } - if (size > pending) { - size = pending; - } - - memcpy(buf, f->buf + index, size); - return size; -} - -/* - * Read 'size' bytes of data from the file into buf. - * 'size' can be larger than the internal buffer. - * - * It will return size bytes unless there was an error, in which case it will - * return as many as it managed to read (assuming blocking fd's which - * all current QEMUFile are) - */ -int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) -{ - int pending = size; - int done = 0; - - while (pending > 0) { - int res; - - res = qemu_peek_buffer(f, buf, MIN(pending, IO_BUF_SIZE), 0); - if (res == 0) { - return done; - } - qemu_file_skip(f, res); - buf += res; - pending -= res; - done += res; - } - return done; -} - -/* - * Peeks a single byte from the buffer; this isn't guaranteed to work if - * offset leaves a gap after the previous read/peeked data. - */ -int qemu_peek_byte(QEMUFile *f, int offset) -{ - int index = f->buf_index + offset; - - assert(!qemu_file_is_writable(f)); - assert(offset < IO_BUF_SIZE); - - if (index >= f->buf_size) { - qemu_fill_buffer(f); - index = f->buf_index + offset; - if (index >= f->buf_size) { - return 0; - } - } - return f->buf[index]; -} - -int qemu_get_byte(QEMUFile *f) -{ - int result; - - result = qemu_peek_byte(f, 0); - qemu_file_skip(f, 1); - return result; -} - -int64_t qemu_ftell(QEMUFile *f) -{ - qemu_fflush(f); - return f->pos; -} - -int qemu_file_rate_limit(QEMUFile *f) -{ - if (qemu_file_get_error(f)) { - return 1; - } - if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) { - return 1; - } - return 0; -} - -int64_t qemu_file_get_rate_limit(QEMUFile *f) -{ - return f->xfer_limit; -} - -void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit) -{ - f->xfer_limit = limit; -} - -void qemu_file_reset_rate_limit(QEMUFile *f) -{ - f->bytes_xfer = 0; -} - -void qemu_put_be16(QEMUFile *f, unsigned int v) -{ - qemu_put_byte(f, v >> 8); - qemu_put_byte(f, v); -} - -void qemu_put_be32(QEMUFile *f, unsigned int v) -{ - qemu_put_byte(f, v >> 24); - qemu_put_byte(f, v >> 16); - qemu_put_byte(f, v >> 8); - qemu_put_byte(f, v); -} - -void qemu_put_be64(QEMUFile *f, uint64_t v) -{ - qemu_put_be32(f, v >> 32); - qemu_put_be32(f, v); -} - -unsigned int qemu_get_be16(QEMUFile *f) -{ - unsigned int v; - v = qemu_get_byte(f) << 8; - v |= qemu_get_byte(f); - return v; -} - -unsigned int qemu_get_be32(QEMUFile *f) -{ - unsigned int v; - v = qemu_get_byte(f) << 24; - v |= qemu_get_byte(f) << 16; - v |= qemu_get_byte(f) << 8; - v |= qemu_get_byte(f); - return v; -} - -uint64_t qemu_get_be64(QEMUFile *f) -{ - uint64_t v; - v = (uint64_t)qemu_get_be32(f) << 32; - v |= qemu_get_be32(f); - return v; -} - #define QSB_CHUNK_SIZE (1 << 10) #define QSB_MAX_CHUNK_SIZE (16 * QSB_CHUNK_SIZE) diff --git a/migration/qemu-file-internal.h b/migration/qemu-file-internal.h new file mode 100644 index 0000000000..d95e8538e7 --- /dev/null +++ b/migration/qemu-file-internal.h @@ -0,0 +1,53 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef QEMU_FILE_INTERNAL_H +#define QEMU_FILE_INTERNAL_H 1 + +#include "qemu-common.h" +#include "qemu/iov.h" + +#define IO_BUF_SIZE 32768 +#define MAX_IOV_SIZE MIN(IOV_MAX, 64) + +struct QEMUFile { + const QEMUFileOps *ops; + void *opaque; + + int64_t bytes_xfer; + int64_t xfer_limit; + + int64_t pos; /* start of buffer when writing, end of buffer + when reading */ + int buf_index; + int buf_size; /* 0 when writing */ + uint8_t buf[IO_BUF_SIZE]; + + struct iovec iov[MAX_IOV_SIZE]; + unsigned int iovcnt; + + int last_error; +}; + +#endif diff --git a/qemu-file-stdio.c b/migration/qemu-file-stdio.c index 285068b303..285068b303 100644 --- a/qemu-file-stdio.c +++ b/migration/qemu-file-stdio.c diff --git a/qemu-file-unix.c b/migration/qemu-file-unix.c index 9682396d97..9682396d97 100644 --- a/qemu-file-unix.c +++ b/migration/qemu-file-unix.c diff --git a/migration/qemu-file.c b/migration/qemu-file.c new file mode 100644 index 0000000000..d2d40073f0 --- /dev/null +++ b/migration/qemu-file.c @@ -0,0 +1,519 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include "qemu/iov.h" +#include "qemu/sockets.h" +#include "block/coroutine.h" +#include "migration/migration.h" +#include "migration/qemu-file.h" +#include "migration/qemu-file-internal.h" +#include "trace.h" + +bool qemu_file_mode_is_not_valid(const char *mode) +{ + if (mode == NULL || + (mode[0] != 'r' && mode[0] != 'w') || + mode[1] != 'b' || mode[2] != 0) { + fprintf(stderr, "qemu_fopen: Argument validity check failed\n"); + return true; + } + + return false; +} + +QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops) +{ + QEMUFile *f; + + f = g_malloc0(sizeof(QEMUFile)); + + f->opaque = opaque; + f->ops = ops; + return f; +} + +/* + * Get last error for stream f + * + * Return negative error value if there has been an error on previous + * operations, return 0 if no error happened. + * + */ +int qemu_file_get_error(QEMUFile *f) +{ + return f->last_error; +} + +void qemu_file_set_error(QEMUFile *f, int ret) +{ + if (f->last_error == 0) { + f->last_error = ret; + } +} + +bool qemu_file_is_writable(QEMUFile *f) +{ + return f->ops->writev_buffer || f->ops->put_buffer; +} + +/** + * Flushes QEMUFile buffer + * + * If there is writev_buffer QEMUFileOps it uses it otherwise uses + * put_buffer ops. + */ +void qemu_fflush(QEMUFile *f) +{ + ssize_t ret = 0; + + if (!qemu_file_is_writable(f)) { + return; + } + + if (f->ops->writev_buffer) { + if (f->iovcnt > 0) { + ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos); + } + } else { + if (f->buf_index > 0) { + ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index); + } + } + if (ret >= 0) { + f->pos += ret; + } + f->buf_index = 0; + f->iovcnt = 0; + if (ret < 0) { + qemu_file_set_error(f, ret); + } +} + +void ram_control_before_iterate(QEMUFile *f, uint64_t flags) +{ + int ret = 0; + + if (f->ops->before_ram_iterate) { + ret = f->ops->before_ram_iterate(f, f->opaque, flags); + if (ret < 0) { + qemu_file_set_error(f, ret); + } + } +} + +void ram_control_after_iterate(QEMUFile *f, uint64_t flags) +{ + int ret = 0; + + if (f->ops->after_ram_iterate) { + ret = f->ops->after_ram_iterate(f, f->opaque, flags); + if (ret < 0) { + qemu_file_set_error(f, ret); + } + } +} + +void ram_control_load_hook(QEMUFile *f, uint64_t flags) +{ + int ret = -EINVAL; + + if (f->ops->hook_ram_load) { + ret = f->ops->hook_ram_load(f, f->opaque, flags); + if (ret < 0) { + qemu_file_set_error(f, ret); + } + } else { + qemu_file_set_error(f, ret); + } +} + +size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, + ram_addr_t offset, size_t size, int *bytes_sent) +{ + if (f->ops->save_page) { + int ret = f->ops->save_page(f, f->opaque, block_offset, + offset, size, bytes_sent); + + if (ret != RAM_SAVE_CONTROL_DELAYED) { + if (bytes_sent && *bytes_sent > 0) { + qemu_update_position(f, *bytes_sent); + } else if (ret < 0) { + qemu_file_set_error(f, ret); + } + } + + return ret; + } + + return RAM_SAVE_CONTROL_NOT_SUPP; +} + +/* + * Attempt to fill the buffer from the underlying file + * Returns the number of bytes read, or negative value for an error. + * + * Note that it can return a partially full buffer even in a not error/not EOF + * case if the underlying file descriptor gives a short read, and that can + * happen even on a blocking fd. + */ +static ssize_t qemu_fill_buffer(QEMUFile *f) +{ + int len; + int pending; + + assert(!qemu_file_is_writable(f)); + + pending = f->buf_size - f->buf_index; + if (pending > 0) { + memmove(f->buf, f->buf + f->buf_index, pending); + } + f->buf_index = 0; + f->buf_size = pending; + + len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos, + IO_BUF_SIZE - pending); + if (len > 0) { + f->buf_size += len; + f->pos += len; + } else if (len == 0) { + qemu_file_set_error(f, -EIO); + } else if (len != -EAGAIN) { + qemu_file_set_error(f, len); + } + + return len; +} + +int qemu_get_fd(QEMUFile *f) +{ + if (f->ops->get_fd) { + return f->ops->get_fd(f->opaque); + } + return -1; +} + +void qemu_update_position(QEMUFile *f, size_t size) +{ + f->pos += size; +} + +/** Closes the file + * + * Returns negative error value if any error happened on previous operations or + * while closing the file. Returns 0 or positive number on success. + * + * The meaning of return value on success depends on the specific backend + * being used. + */ +int qemu_fclose(QEMUFile *f) +{ + int ret; + qemu_fflush(f); + ret = qemu_file_get_error(f); + + if (f->ops->close) { + int ret2 = f->ops->close(f->opaque); + if (ret >= 0) { + ret = ret2; + } + } + /* If any error was spotted before closing, we should report it + * instead of the close() return value. + */ + if (f->last_error) { + ret = f->last_error; + } + g_free(f); + trace_qemu_file_fclose(); + return ret; +} + +static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size) +{ + /* check for adjacent buffer and coalesce them */ + if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base + + f->iov[f->iovcnt - 1].iov_len) { + f->iov[f->iovcnt - 1].iov_len += size; + } else { + f->iov[f->iovcnt].iov_base = (uint8_t *)buf; + f->iov[f->iovcnt++].iov_len = size; + } + + if (f->iovcnt >= MAX_IOV_SIZE) { + qemu_fflush(f); + } +} + +void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size) +{ + if (!f->ops->writev_buffer) { + qemu_put_buffer(f, buf, size); + return; + } + + if (f->last_error) { + return; + } + + f->bytes_xfer += size; + add_to_iovec(f, buf, size); +} + +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) +{ + int l; + + if (f->last_error) { + return; + } + + while (size > 0) { + l = IO_BUF_SIZE - f->buf_index; + if (l > size) { + l = size; + } + memcpy(f->buf + f->buf_index, buf, l); + f->bytes_xfer += l; + if (f->ops->writev_buffer) { + add_to_iovec(f, f->buf + f->buf_index, l); + } + f->buf_index += l; + if (f->buf_index == IO_BUF_SIZE) { + qemu_fflush(f); + } + if (qemu_file_get_error(f)) { + break; + } + buf += l; + size -= l; + } +} + +void qemu_put_byte(QEMUFile *f, int v) +{ + if (f->last_error) { + return; + } + + f->buf[f->buf_index] = v; + f->bytes_xfer++; + if (f->ops->writev_buffer) { + add_to_iovec(f, f->buf + f->buf_index, 1); + } + f->buf_index++; + if (f->buf_index == IO_BUF_SIZE) { + qemu_fflush(f); + } +} + +void qemu_file_skip(QEMUFile *f, int size) +{ + if (f->buf_index + size <= f->buf_size) { + f->buf_index += size; + } +} + +/* + * Read 'size' bytes from file (at 'offset') into buf without moving the + * pointer. + * + * It will return size bytes unless there was an error, in which case it will + * return as many as it managed to read (assuming blocking fd's which + * all current QEMUFile are) + */ +int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) +{ + int pending; + int index; + + assert(!qemu_file_is_writable(f)); + assert(offset < IO_BUF_SIZE); + assert(size <= IO_BUF_SIZE - offset); + + /* The 1st byte to read from */ + index = f->buf_index + offset; + /* The number of available bytes starting at index */ + pending = f->buf_size - index; + + /* + * qemu_fill_buffer might return just a few bytes, even when there isn't + * an error, so loop collecting them until we get enough. + */ + while (pending < size) { + int received = qemu_fill_buffer(f); + + if (received <= 0) { + break; + } + + index = f->buf_index + offset; + pending = f->buf_size - index; + } + + if (pending <= 0) { + return 0; + } + if (size > pending) { + size = pending; + } + + memcpy(buf, f->buf + index, size); + return size; +} + +/* + * Read 'size' bytes of data from the file into buf. + * 'size' can be larger than the internal buffer. + * + * It will return size bytes unless there was an error, in which case it will + * return as many as it managed to read (assuming blocking fd's which + * all current QEMUFile are) + */ +int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) +{ + int pending = size; + int done = 0; + + while (pending > 0) { + int res; + + res = qemu_peek_buffer(f, buf, MIN(pending, IO_BUF_SIZE), 0); + if (res == 0) { + return done; + } + qemu_file_skip(f, res); + buf += res; + pending -= res; + done += res; + } + return done; +} + +/* + * Peeks a single byte from the buffer; this isn't guaranteed to work if + * offset leaves a gap after the previous read/peeked data. + */ +int qemu_peek_byte(QEMUFile *f, int offset) +{ + int index = f->buf_index + offset; + + assert(!qemu_file_is_writable(f)); + assert(offset < IO_BUF_SIZE); + + if (index >= f->buf_size) { + qemu_fill_buffer(f); + index = f->buf_index + offset; + if (index >= f->buf_size) { + return 0; + } + } + return f->buf[index]; +} + +int qemu_get_byte(QEMUFile *f) +{ + int result; + + result = qemu_peek_byte(f, 0); + qemu_file_skip(f, 1); + return result; +} + +int64_t qemu_ftell(QEMUFile *f) +{ + qemu_fflush(f); + return f->pos; +} + +int qemu_file_rate_limit(QEMUFile *f) +{ + if (qemu_file_get_error(f)) { + return 1; + } + if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) { + return 1; + } + return 0; +} + +int64_t qemu_file_get_rate_limit(QEMUFile *f) +{ + return f->xfer_limit; +} + +void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit) +{ + f->xfer_limit = limit; +} + +void qemu_file_reset_rate_limit(QEMUFile *f) +{ + f->bytes_xfer = 0; +} + +void qemu_put_be16(QEMUFile *f, unsigned int v) +{ + qemu_put_byte(f, v >> 8); + qemu_put_byte(f, v); +} + +void qemu_put_be32(QEMUFile *f, unsigned int v) +{ + qemu_put_byte(f, v >> 24); + qemu_put_byte(f, v >> 16); + qemu_put_byte(f, v >> 8); + qemu_put_byte(f, v); +} + +void qemu_put_be64(QEMUFile *f, uint64_t v) +{ + qemu_put_be32(f, v >> 32); + qemu_put_be32(f, v); +} + +unsigned int qemu_get_be16(QEMUFile *f) +{ + unsigned int v; + v = qemu_get_byte(f) << 8; + v |= qemu_get_byte(f); + return v; +} + +unsigned int qemu_get_be32(QEMUFile *f) +{ + unsigned int v; + v = qemu_get_byte(f) << 24; + v |= qemu_get_byte(f) << 16; + v |= qemu_get_byte(f) << 8; + v |= qemu_get_byte(f); + return v; +} + +uint64_t qemu_get_be64(QEMUFile *f) +{ + uint64_t v; + v = (uint64_t)qemu_get_be32(f) << 32; + v |= qemu_get_be32(f); + return v; +} diff --git a/migration-rdma.c b/migration/rdma.c index b32dbdfccd..b32dbdfccd 100644 --- a/migration-rdma.c +++ b/migration/rdma.c diff --git a/migration-tcp.c b/migration/tcp.c index 91c9cf381e..91c9cf381e 100644 --- a/migration-tcp.c +++ b/migration/tcp.c diff --git a/migration-unix.c b/migration/unix.c index 1cdadfbc83..1cdadfbc83 100644 --- a/migration-unix.c +++ b/migration/unix.c diff --git a/vmstate.c b/migration/vmstate.c index 3dde574c0f..3dde574c0f 100644 --- a/vmstate.c +++ b/migration/vmstate.c diff --git a/xbzrle.c b/migration/xbzrle.c index 8e220bf25b..8e220bf25b 100644 --- a/xbzrle.c +++ b/migration/xbzrle.c diff --git a/qemu-log.c b/qemu-log.c index 797f2af983..05b5493e0c 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -106,6 +106,8 @@ const QEMULogItem qemu_log_items[] = { "show trace before each executed TB (lots of logs)" }, { CPU_LOG_TB_CPU, "cpu", "show CPU state before block translation" }, + { CPU_LOG_MMU, "mmu", + "log MMU-related activities" }, { CPU_LOG_PCALL, "pcall", "x86 only: show protected mode far calls/returns/exceptions" }, { CPU_LOG_RESET, "cpu_reset", diff --git a/qmp-commands.hx b/qmp-commands.hx index 33487820a4..6945d30198 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -3184,6 +3184,9 @@ migrate-set-capabilities Enable/Disable migration capabilities - "xbzrle": XBZRLE support +- "rdma-pin-all": pin all pages when using RDMA during migration +- "auto-converge": throttle down guest to help convergence of migration +- "zero-blocks": compress zero blocks during block migration Arguments: @@ -3208,6 +3211,9 @@ Query current migration capabilities - "capabilities": migration capabilities state - "xbzrle" : XBZRLE state (json-bool) + - "rdma-pin-all" : RDMA Pin Page state (json-bool) + - "auto-converge" : Auto Converge state (json-bool) + - "zero-blocks" : Zero Blocks state (json-bool) Arguments: diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 8106e063c0..7e0d300777 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -3,7 +3,6 @@ #include "ui/qemu-spice.h" #include "sysemu/char.h" #include <spice.h> -#include <spice-experimental.h> #include <spice/protocol.h> #include "qemu/osdep.h" diff --git a/target-cris/helper.c b/target-cris/helper.c index e901c3a008..df6c9fdcb5 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -84,8 +84,8 @@ int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int r = -1; target_ulong phy; - D(printf("%s addr=%" VADDR_PRIx " pc=%x rw=%x\n", - __func__, address, env->pc, rw)); + qemu_log_mask(CPU_LOG_MMU, "%s addr=%" VADDR_PRIx " pc=%x rw=%x\n", + __func__, address, env->pc, rw); miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, rw, mmu_idx, 0); if (miss) { @@ -112,9 +112,10 @@ int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, r = 0; } if (r > 0) { - D_LOG("%s returns %d irqreq=%x addr=%" VADDR_PRIx " phy=%x vec=%x" - " pc=%x\n", __func__, r, cs->interrupt_request, address, res.phy, - res.bf_vec, env->pc); + qemu_log_mask(CPU_LOG_MMU, + "%s returns %d irqreq=%x addr=%" VADDR_PRIx " phy=%x vec=%x" + " pc=%x\n", __func__, r, cs->interrupt_request, address, + res.phy, res.bf_vec, env->pc); } return r; } diff --git a/target-i386/helper.c b/target-i386/helper.c index 345bda188d..4f1ddf701e 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -25,8 +25,6 @@ #include "monitor/monitor.h" #endif -//#define DEBUG_MMU - static void cpu_x86_version(CPUX86State *env, int *family, int *model) { int cpuver = env->cpuid_version; @@ -388,9 +386,7 @@ void x86_cpu_set_a20(X86CPU *cpu, int a20_state) if (a20_state != ((env->a20_mask >> 20) & 1)) { CPUState *cs = CPU(cpu); -#if defined(DEBUG_MMU) - printf("A20 update: a20=%d\n", a20_state); -#endif + qemu_log_mask(CPU_LOG_MMU, "A20 update: a20=%d\n", a20_state); /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); @@ -407,9 +403,7 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) X86CPU *cpu = x86_env_get_cpu(env); int pe_state; -#if defined(DEBUG_MMU) - printf("CR0 update: CR0=0x%08x\n", new_cr0); -#endif + qemu_log_mask(CPU_LOG_MMU, "CR0 update: CR0=0x%08x\n", new_cr0); if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) != (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) { tlb_flush(CPU(cpu), 1); @@ -452,9 +446,8 @@ void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3) env->cr[3] = new_cr3; if (env->cr[0] & CR0_PG_MASK) { -#if defined(DEBUG_MMU) - printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3); -#endif + qemu_log_mask(CPU_LOG_MMU, + "CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3); tlb_flush(CPU(cpu), 0); } } diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c index 59466c9742..32896f446a 100644 --- a/target-microblaze/helper.c +++ b/target-microblaze/helper.c @@ -22,7 +22,6 @@ #include "qemu/host-utils.h" #define D(x) -#define DMMU(x) #if defined(CONFIG_USER_ONLY) @@ -75,13 +74,14 @@ int mb_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, vaddr = address & TARGET_PAGE_MASK; paddr = lu.paddr + vaddr - lu.vaddr; - DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n", - mmu_idx, vaddr, paddr, lu.prot)); + qemu_log_mask(CPU_LOG_MMU, "MMU map mmu=%d v=%x p=%x prot=%x\n", + mmu_idx, vaddr, paddr, lu.prot); tlb_set_page(cs, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE); r = 0; } else { env->sregs[SR_EAR] = address; - DMMU(qemu_log("mmu=%d miss v=%x\n", mmu_idx, address)); + qemu_log_mask(CPU_LOG_MMU, "mmu=%d miss v=%" VADDR_PRIx "\n", + mmu_idx, address); switch (lu.err) { case ERR_PROT: diff --git a/target-mips/helper.c b/target-mips/helper.c index 7d26705cb5..8e3204a3a0 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -341,7 +341,8 @@ int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, #if 0 log_cpu_state(cs, 0); #endif - qemu_log("%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx %d\n", + qemu_log_mask(CPU_LOG_MMU, + "%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx %d\n", __func__, env->active_tc.PC, address, rw, mmu_idx); /* data access */ @@ -351,7 +352,8 @@ int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, access_type = ACCESS_INT; ret = get_physical_address(env, &physical, &prot, address, rw, access_type); - qemu_log("%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, + "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx " prot %d\n", __func__, address, ret, physical, prot); if (ret == TLBRET_MATCH) { diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c index 0a13a81dba..dfee358d6a 100644 --- a/target-ppc/mmu-hash32.c +++ b/target-ppc/mmu-hash32.c @@ -28,10 +28,8 @@ //#define DEBUG_BAT #ifdef DEBUG_MMU -# define LOG_MMU(...) qemu_log(__VA_ARGS__) # define LOG_MMU_STATE(cpu) log_cpu_state((cpu), 0) #else -# define LOG_MMU(...) do { } while (0) # define LOG_MMU_STATE(cpu) do { } while (0) #endif @@ -225,7 +223,7 @@ static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr, CPUState *cs = CPU(ppc_env_get_cpu(env)); int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS)); - LOG_MMU("direct store...\n"); + qemu_log_mask(CPU_LOG_MMU, "direct store...\n"); if ((sr & 0x1FF00000) >> 20 == 0x07f) { /* Memory-forced I/O controller interface access */ @@ -348,12 +346,13 @@ static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env, ptem = (vsid << 7) | (pgidx >> 10); /* Page address translation */ - LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx + " htab_mask " TARGET_FMT_plx " hash " TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, hash); /* Primary PTEG lookup */ - LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx " vsid=%" PRIx32 " ptem=%" PRIx32 " hash=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, ptem, hash); @@ -361,7 +360,7 @@ static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env, pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte); if (pte_offset == -1) { /* Secondary PTEG lookup */ - LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx " vsid=%" PRIx32 " api=%" PRIx32 " hash=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, ptem, ~hash); @@ -476,7 +475,8 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr, int rwx, return 1; } - LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset); + qemu_log_mask(CPU_LOG_MMU, + "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset); /* 7. Check access permissions */ @@ -484,7 +484,7 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr, int rwx, if (need_prot[rwx] & ~prot) { /* Access right violation */ - LOG_MMU("PTE access rejected\n"); + qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); if (rwx == 2) { cs->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x08000000; @@ -501,7 +501,7 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr, int rwx, return 1; } - LOG_MMU("PTE access granted !\n"); + qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); /* 8. Update PTE referenced and changed bits if necessary */ diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index c72198abde..b0278c95e1 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -27,10 +27,8 @@ //#define DEBUG_SLB #ifdef DEBUG_MMU -# define LOG_MMU(...) qemu_log(__VA_ARGS__) # define LOG_MMU_STATE(cpu) log_cpu_state((cpu), 0) #else -# define LOG_MMU(...) do { } while (0) # define LOG_MMU_STATE(cpu) do { } while (0) #endif @@ -420,12 +418,14 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env, ptem = (slb->vsid & SLB_VSID_PTEM) | ((epn >> 16) & HPTE64_V_AVPN); /* Page address translation */ - LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, + "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx " hash " TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, hash); /* Primary PTEG lookup */ - LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, + "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx " hash=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, ptem, hash); @@ -433,7 +433,8 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env, if (pte_offset == -1) { /* Secondary PTEG lookup */ - LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, + "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, vsid, ptem, ~hash); @@ -522,7 +523,8 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr, } return 1; } - LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset); + qemu_log_mask(CPU_LOG_MMU, + "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset); /* 5. Check access permissions */ @@ -532,7 +534,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr, if ((need_prot[rwx] & ~prot) != 0) { /* Access right violation */ - LOG_MMU("PTE access rejected\n"); + qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); if (rwx == 2) { cs->exception_index = POWERPC_EXCP_ISI; env->error_code = 0x08000000; @@ -556,7 +558,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr, return 1; } - LOG_MMU("PTE access granted !\n"); + qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); /* 6. Update PTE referenced and changed bits if necessary */ diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 4a34a73ad4..660be7f18c 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -32,10 +32,8 @@ //#define FLUSH_ALL_TLBS #ifdef DEBUG_MMU -# define LOG_MMU(...) qemu_log(__VA_ARGS__) # define LOG_MMU_STATE(cpu) log_cpu_state((cpu), 0) #else -# define LOG_MMU(...) do { } while (0) # define LOG_MMU_STATE(cpu) do { } while (0) #endif @@ -176,10 +174,10 @@ static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0, ret = check_prot(ctx->prot, rw, type); if (ret == 0) { /* Access granted */ - LOG_MMU("PTE access granted !\n"); + qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); } else { /* Access right violation */ - LOG_MMU("PTE access rejected\n"); + qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); } } } @@ -480,8 +478,9 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, ctx->nx = sr & 0x10000000 ? 1 : 0; vsid = sr & 0x00FFFFFF; target_page_bits = TARGET_PAGE_BITS; - LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" - TARGET_FMT_lx " lr=" TARGET_FMT_lx + qemu_log_mask(CPU_LOG_MMU, + "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx + " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx " ir=%d dr=%d pr=%d %d t=%d\n", eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir, (int)msr_dr, pr != 0 ? 1 : 0, rw, type); @@ -489,14 +488,16 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, hash = vsid ^ pgidx; ctx->ptem = (vsid << 7) | (pgidx >> 10); - LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n", + qemu_log_mask(CPU_LOG_MMU, + "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid); ret = -1; if (!ds) { /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || ctx->nx == 0) { /* Page address translation */ - LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx + " htab_mask " TARGET_FMT_plx " hash " TARGET_FMT_plx "\n", env->htab_base, env->htab_mask, hash); ctx->hash[0] = hash; @@ -527,13 +528,13 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx, } #endif } else { - LOG_MMU("No access allowed\n"); + qemu_log_mask(CPU_LOG_MMU, "No access allowed\n"); ret = -3; } } else { target_ulong sr; - LOG_MMU("direct store...\n"); + qemu_log_mask(CPU_LOG_MMU, "direct store...\n"); /* Direct-store segment : absolutely *BUGGY* for now */ /* Direct-store implies a 32-bit MMU. @@ -2037,7 +2038,7 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value) { PowerPCCPU *cpu = ppc_env_get_cpu(env); - LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value); + qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); assert(!env->external_htab); if (env->spr[SPR_SDR1] != value) { env->spr[SPR_SDR1] = value; @@ -2079,7 +2080,8 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value) { PowerPCCPU *cpu = ppc_env_get_cpu(env); - LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, + qemu_log_mask(CPU_LOG_MMU, + "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, (int)srnum, value, env->sr[srnum]); #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 96a4f22734..59583433fb 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -461,8 +461,8 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, return 1; } - DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __func__, - (uint64_t)vaddr, (uint64_t)raddr, prot); + qemu_log_mask(CPU_LOG_MMU, "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", + __func__, (uint64_t)vaddr, (uint64_t)raddr, prot); tlb_set_page(cs, orig_vaddr, raddr, prot, mmu_idx, TARGET_PAGE_SIZE); diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c index 61afbcf048..2a0c6f0d3d 100644 --- a/target-sparc/mmu_helper.c +++ b/target-sparc/mmu_helper.c @@ -213,10 +213,9 @@ int sparc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, address, rw, mmu_idx, &page_size); vaddr = address; if (error_code == 0) { -#ifdef DEBUG_MMU - printf("Translate at %" VADDR_PRIx " -> " TARGET_FMT_plx ", vaddr " - TARGET_FMT_lx "\n", address, paddr, vaddr); -#endif + qemu_log_mask(CPU_LOG_MMU, + "Translate at %" VADDR_PRIx " -> " TARGET_FMT_plx ", vaddr " + TARGET_FMT_lx "\n", address, paddr, vaddr); tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size); return 0; } diff --git a/tests/Makefile b/tests/Makefile index 16f0e4c805..e4ddb6a8c1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -48,8 +48,11 @@ check-unit-y += tests/test-hbitmap$(EXESUF) check-unit-y += tests/test-x86-cpuid$(EXESUF) # all code tested by test-x86-cpuid is inside topology.h gcov-files-test-x86-cpuid-y = +ifeq ($(CONFIG_SOFTMMU),y) check-unit-y += tests/test-xbzrle$(EXESUF) -gcov-files-test-xbzrle-y = xbzrle.c +gcov-files-test-xbzrle-y = migration/xbzrle.c +check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF) +endif check-unit-y += tests/test-cutils$(EXESUF) gcov-files-test-cutils-y += util/cutils.c check-unit-y += tests/test-mul64$(EXESUF) @@ -61,7 +64,6 @@ check-unit-y += tests/test-bitops$(EXESUF) check-unit-$(CONFIG_HAS_GLIB_SUBPROCESS_TESTS) += tests/test-qdev-global-props$(EXESUF) check-unit-y += tests/check-qom-interface$(EXESUF) gcov-files-check-qom-interface-y = qom/object.c -check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF) check-unit-y += tests/test-qemu-opts$(EXESUF) gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c @@ -247,7 +249,7 @@ tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemu tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o -tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o xbzrle.o page_cache.o libqemuutil.a +tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o page_cache.o libqemuutil.a tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o tests/test-int128$(EXESUF): tests/test-int128.o tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ @@ -258,7 +260,8 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ $(test-qapi-obj-y) \ libqemuutil.a libqemustub.a tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ - vmstate.o qemu-file.o qemu-file-unix.o \ + migration/vmstate.o migration/qemu-file.o migration/qemu-file-buf.o \ + migration/qemu-file-unix.o \ libqemuutil.a libqemustub.a tests/test-qapi-types.c tests/test-qapi-types.h :\ diff --git a/ui/spice-core.c b/ui/spice-core.c index 6467fa4776..fe705c1ae2 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -16,7 +16,6 @@ */ #include <spice.h> -#include <spice-experimental.h> #include <netdb.h> #include "sysemu/sysemu.h" @@ -386,10 +385,7 @@ static SpiceChannelList *qmp_query_spice_channels(void) struct sockaddr *paddr; socklen_t plen; - if (!(item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT)) { - error_report("invalid channel event"); - return NULL; - } + assert(item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT); chan = g_malloc0(sizeof(*chan)); chan->value = g_malloc0(sizeof(*chan->value)); @@ -661,10 +657,6 @@ void qemu_spice_init(void) } port = qemu_opt_get_number(opts, "port", 0); tls_port = qemu_opt_get_number(opts, "tls-port", 0); - if (!port && !tls_port) { - error_report("neither port nor tls-port specified for spice"); - exit(1); - } if (port < 0 || port > 65535) { error_report("spice port is out of range"); exit(1); diff --git a/ui/spice-display.c b/ui/spice-display.c index def7b52e9c..d2e379379f 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -207,12 +207,6 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) return; }; - if (ssd->surface == NULL) { - ssd->surface = pixman_image_ref(ssd->ds->image); - ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, - ssd->ds->image); - } - for (blk = 0; blk < blocks; blk++) { dirty_top[blk] = -1; } @@ -409,7 +403,29 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, SimpleSpiceUpdate *update; bool need_destroy; - dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); + if (surface && ssd->surface && + surface_width(surface) == pixman_image_get_width(ssd->surface) && + surface_height(surface) == pixman_image_get_height(ssd->surface)) { + /* no-resize fast path: just swap backing store */ + dprint(1, "%s/%d: fast (%dx%d)\n", __func__, ssd->qxl.id, + surface_width(surface), surface_height(surface)); + qemu_mutex_lock(&ssd->lock); + ssd->ds = surface; + pixman_image_unref(ssd->surface); + ssd->surface = pixman_image_ref(ssd->ds->image); + qemu_mutex_unlock(&ssd->lock); + qemu_spice_display_update(ssd, 0, 0, + surface_width(surface), + surface_height(surface)); + return; + } + + /* full mode switch */ + dprint(1, "%s/%d: full (%dx%d -> %dx%d)\n", __func__, ssd->qxl.id, + ssd->surface ? pixman_image_get_width(ssd->surface) : 0, + ssd->surface ? pixman_image_get_height(ssd->surface) : 0, + surface ? surface_width(surface) : 0, + surface ? surface_height(surface) : 0); memset(&ssd->dirty, 0, sizeof(ssd->dirty)); if (ssd->surface) { @@ -422,6 +438,9 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, qemu_mutex_lock(&ssd->lock); need_destroy = (ssd->ds != NULL); ssd->ds = surface; + ssd->surface = pixman_image_ref(ssd->ds->image); + ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, + ssd->ds->image); while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { QTAILQ_REMOVE(&ssd->updates, update, next); qemu_spice_destroy_update(ssd, update); @@ -438,7 +457,7 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, ssd->notify++; } -void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) +static void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) { if (ssd->cursor) { assert(ssd->dcl.con); @@ -454,6 +473,15 @@ void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) } } +void qemu_spice_cursor_refresh_bh(void *opaque) +{ + SimpleSpiceDisplay *ssd = opaque; + + qemu_mutex_lock(&ssd->lock); + qemu_spice_cursor_refresh_unlocked(ssd); + qemu_mutex_unlock(&ssd->lock); +} + void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) { dprint(3, "%s/%d:\n", __func__, ssd->qxl.id); @@ -464,7 +492,6 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) qemu_spice_create_update(ssd); ssd->notify++; } - qemu_spice_cursor_refresh_unlocked(ssd); qemu_mutex_unlock(&ssd->lock); if (ssd->notify) { |