diff options
110 files changed, 2349 insertions, 1712 deletions
diff --git a/.gitignore b/.gitignore index 3a417656e2..0e3816918c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,10 @@ config-all-devices.* config-all-disas.* config-host.* config-target.* -trace.h -trace.c -trace-dtrace.h -trace-dtrace.dtrace +trace/generated-tracers.h +trace/generated-tracers.c +trace/generated-tracers-dtrace.h +trace/generated-tracers-dtrace.dtrace *-timestamp *-softmmu *-darwin-user diff --git a/MAINTAINERS b/MAINTAINERS index c1b16c5fe4..cf39e5a00a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -132,7 +132,7 @@ Guest CPU Cores (KVM): ---------------------- Overall -M: Avi Kivity <avi@redhat.com> +M: Gleb Natapov <gleb@redhat.com> M: Marcelo Tosatti <mtosatti@redhat.com> L: kvm@vger.kernel.org S: Supported @@ -150,7 +150,7 @@ S: Maintained F: target-s390x/kvm.c X86 -M: Avi Kivity <avi@redhat.com> +M: Gleb Natapov <gleb@redhat.com> M: Marcelo Tosatti <mtosatti@redhat.com> L: kvm@vger.kernel.org S: Supported @@ -600,6 +600,7 @@ M: Andreas Färber <afaerber@suse.de> S: Supported F: qom/cpu.c F: include/qemu/cpu.h +F: target-i386/cpu.c Device Tree M: Peter Crosthwaite <peter.crosthwaite@petalogix.com> diff --git a/Makefile b/Makefile index a0321dd7f0..a7ac04b9ae 100644 --- a/Makefile +++ b/Makefile @@ -31,12 +31,15 @@ ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail)) endif endif -GENERATED_HEADERS = config-host.h trace.h qemu-options.def +GENERATED_HEADERS = config-host.h qemu-options.def +GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h +GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c + +GENERATED_HEADERS += trace/generated-tracers.h ifeq ($(TRACE_BACKEND),dtrace) -GENERATED_HEADERS += trace-dtrace.h +GENERATED_HEADERS += trace/generated-tracers-dtrace.h endif -GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h -GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c trace.c +GENERATED_SOURCES += trace/generated-tracers.c # Don't try to regenerate Makefile or configure # We don't generate any of them @@ -233,9 +236,9 @@ clean: rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -Rf .libs rm -f qemu-img-cmds.h - rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp @# May not be present in GENERATED_HEADERS - rm -f trace-dtrace.h trace-dtrace.h-timestamp + rm -f trace/generated-tracers-dtrace.dtrace* + rm -f trace/generated-tracers-dtrace.h* rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp) rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp) rm -rf qapi-generated diff --git a/Makefile.objs b/Makefile.objs index a637a4a8f0..3a3a4028c5 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -77,7 +77,8 @@ common-obj-$(CONFIG_LINUX) += fsdev/ extra-obj-$(CONFIG_LINUX) += fsdev/ common-obj-y += tcg-runtime.o host-utils.o main-loop.o -common-obj-y += buffered_file.o migration.o migration-tcp.o +common-obj-y += migration.o migration-tcp.o +common-obj-y += migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o common-obj-y += block-migration.o iohandler.o common-obj-y += bitmap.o bitops.o @@ -132,66 +133,7 @@ universal-obj-y += disas/ ###################################################################### # trace -ifeq ($(TRACE_BACKEND),dtrace) -TRACE_H_EXTRA_DEPS=trace-dtrace.h -endif -trace.h: trace.h-timestamp $(TRACE_H_EXTRA_DEPS) -trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak - $(call quiet-command,$(TRACETOOL) \ - --format=h \ - --backend=$(TRACE_BACKEND) \ - < $< > $@," GEN trace.h") - @cmp -s $@ trace.h || cp $@ trace.h - -trace.c: trace.c-timestamp -trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak - $(call quiet-command,$(TRACETOOL) \ - --format=c \ - --backend=$(TRACE_BACKEND) \ - < $< > $@," GEN trace.c") - @cmp -s $@ trace.c || cp $@ trace.c - -trace.o: trace.c $(GENERATED_HEADERS) - -trace-dtrace.h: trace-dtrace.dtrace - $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h") - -# Normal practice is to name DTrace probe file with a '.d' extension -# but that gets picked up by QEMU's Makefile as an external dependency -# rule file. So we use '.dtrace' instead -trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp -trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak - $(call quiet-command,$(TRACETOOL) \ - --format=d \ - --backend=$(TRACE_BACKEND) \ - < $< > $@," GEN trace-dtrace.dtrace") - @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace - -trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) - $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o") - -ifeq ($(LIBTOOL),) -trace-dtrace.lo: trace-dtrace.dtrace - @echo "missing libtool. please install and rerun configure."; exit 1 -else -trace-dtrace.lo: trace-dtrace.dtrace - $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN trace-dtrace.o") -endif - -trace/simple.o: trace/simple.c $(GENERATED_HEADERS) - -trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace.o -ifneq ($(TRACE_BACKEND),dtrace) -trace-obj-y = trace.o -endif - -trace-obj-$(CONFIG_TRACE_DEFAULT) += trace/default.o -trace-obj-$(CONFIG_TRACE_SIMPLE) += trace/simple.o -trace-obj-$(CONFIG_TRACE_SIMPLE) += qemu-timer-common.o -trace-obj-$(CONFIG_TRACE_STDERR) += trace/stderr.o -trace-obj-y += trace/control.o - -$(trace-obj-y): $(GENERATED_HEADERS) +trace-obj-y += trace/ universal-obj-y += $(trace-obj-y) @@ -238,5 +180,6 @@ nested-vars += \ user-obj-y \ common-obj-y \ universal-obj-y \ - extra-obj-y + extra-obj-y \ + trace-obj-y dummy := $(call unnest-vars) diff --git a/Makefile.target b/Makefile.target index 8bbad380c2..be8b8b86a5 100644 --- a/Makefile.target +++ b/Makefile.target @@ -120,11 +120,6 @@ obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o LIBS+=-lz -QEMU_CFLAGS += $(VNC_TLS_CFLAGS) -QEMU_CFLAGS += $(VNC_SASL_CFLAGS) -QEMU_CFLAGS += $(VNC_JPEG_CFLAGS) -QEMU_CFLAGS += $(VNC_PNG_CFLAGS) - # xen support obj-$(CONFIG_XEN) += xen-all.o xen-mapcache.o obj-$(CONFIG_NO_XEN) += xen-stub.o diff --git a/arch_init.c b/arch_init.c index a8b65416da..86f85443d7 100644 --- a/arch_init.c +++ b/arch_init.c @@ -48,6 +48,7 @@ #include "qemu/config-file.h" #include "qmp-commands.h" #include "trace.h" +#include "exec/cpu-all.h" #ifdef DEBUG_ARCH_INIT #define DPRINTF(fmt, ...) \ @@ -264,16 +265,21 @@ uint64_t xbzrle_mig_pages_overflow(void) return acct_info.xbzrle_overflows; } -static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset, - int cont, int flag) +static size_t save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset, + int cont, int flag) { - qemu_put_be64(f, offset | cont | flag); - if (!cont) { - qemu_put_byte(f, strlen(block->idstr)); - qemu_put_buffer(f, (uint8_t *)block->idstr, - strlen(block->idstr)); - } + size_t size; + + qemu_put_be64(f, offset | cont | flag); + size = 8; + if (!cont) { + qemu_put_byte(f, strlen(block->idstr)); + qemu_put_buffer(f, (uint8_t *)block->idstr, + strlen(block->idstr)); + size += 1 + strlen(block->idstr); + } + return size; } #define ENCODING_FLAG_XBZRLE 0x1 @@ -320,34 +326,43 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, } /* Send XBZRLE based compressed page */ - save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE); + bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE); qemu_put_byte(f, ENCODING_FLAG_XBZRLE); qemu_put_be16(f, encoded_len); qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len); - bytes_sent = encoded_len + 1 + 2; + bytes_sent += encoded_len + 1 + 2; acct_info.xbzrle_pages++; acct_info.xbzrle_bytes += bytes_sent; return bytes_sent; } -static RAMBlock *last_block; + +/* This is the last block that we have visited serching for dirty pages + */ +static RAMBlock *last_seen_block; +/* This is the last block from where we have sent data */ +static RAMBlock *last_sent_block; static ram_addr_t last_offset; static unsigned long *migration_bitmap; static uint64_t migration_dirty_pages; +static uint32_t last_version; -static inline bool migration_bitmap_test_and_reset_dirty(MemoryRegion *mr, - ram_addr_t offset) +static inline +ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr, + ram_addr_t start) { - bool ret; - int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS; + unsigned long base = mr->ram_addr >> TARGET_PAGE_BITS; + unsigned long nr = base + (start >> TARGET_PAGE_BITS); + unsigned long size = base + (int128_get64(mr->size) >> TARGET_PAGE_BITS); - ret = test_and_clear_bit(nr, migration_bitmap); + unsigned long next = find_next_bit(migration_bitmap, size, nr); - if (ret) { + if (next < size) { + clear_bit(next, migration_bitmap); migration_dirty_pages--; } - return ret; + return (next - base) << TARGET_PAGE_BITS; } static inline bool migration_bitmap_set_dirty(MemoryRegion *mr, @@ -381,15 +396,14 @@ static void migration_bitmap_sync(void) trace_migration_bitmap_sync_start(); memory_global_sync_dirty_bitmap(get_system_memory()); - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) { - if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION)) { + if (memory_region_test_and_clear_dirty(block->mr, + addr, TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION)) { migration_bitmap_set_dirty(block->mr, addr); } } - memory_region_reset_dirty(block->mr, 0, block->length, - DIRTY_MEMORY_MIGRATION); } trace_migration_bitmap_sync_end(migration_dirty_pages - num_dirty_pages_init); @@ -405,39 +419,54 @@ static void migration_bitmap_sync(void) } } - /* * ram_save_block: Writes a page of memory to the stream f * - * Returns: 0: if the page hasn't changed - * -1: if there are no more dirty pages - * n: the amount of bytes written in other case + * Returns: The number of bytes written. + * 0 means no dirty pages */ static int ram_save_block(QEMUFile *f, bool last_stage) { - RAMBlock *block = last_block; + RAMBlock *block = last_seen_block; ram_addr_t offset = last_offset; - int bytes_sent = -1; + bool complete_round = false; + int bytes_sent = 0; MemoryRegion *mr; ram_addr_t current_addr; if (!block) - block = QLIST_FIRST(&ram_list.blocks); + block = QTAILQ_FIRST(&ram_list.blocks); - do { + while (true) { mr = block->mr; - if (migration_bitmap_test_and_reset_dirty(mr, offset)) { + offset = migration_bitmap_find_and_reset_dirty(mr, offset); + if (complete_round && block == last_seen_block && + offset >= last_offset) { + break; + } + if (offset >= block->length) { + offset = 0; + block = QTAILQ_NEXT(block, next); + if (!block) { + block = QTAILQ_FIRST(&ram_list.blocks); + complete_round = true; + } + } else { uint8_t *p; - int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0; + int cont = (block == last_sent_block) ? + RAM_SAVE_FLAG_CONTINUE : 0; p = memory_region_get_ram_ptr(mr) + offset; + /* In doubt sent page as normal */ + bytes_sent = -1; if (is_dup_page(p)) { acct_info.dup_pages++; - save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS); + bytes_sent = save_block_hdr(f, block, offset, cont, + RAM_SAVE_FLAG_COMPRESS); qemu_put_byte(f, *p); - bytes_sent = 1; + bytes_sent += 1; } else if (migrate_use_xbzrle()) { current_addr = block->offset + offset; bytes_sent = save_xbzrle_page(f, p, current_addr, block, @@ -447,30 +476,22 @@ static int ram_save_block(QEMUFile *f, bool last_stage) } } - /* either we didn't send yet (we may have had XBZRLE overflow) */ + /* XBZRLE overflow or normal page */ if (bytes_sent == -1) { - save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE); + bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE); qemu_put_buffer(f, p, TARGET_PAGE_SIZE); - bytes_sent = TARGET_PAGE_SIZE; + bytes_sent += TARGET_PAGE_SIZE; acct_info.norm_pages++; } /* if page is unmodified, continue to the next */ - if (bytes_sent != 0) { + if (bytes_sent > 0) { + last_sent_block = block; break; } } - - offset += TARGET_PAGE_SIZE; - if (offset >= block->length) { - offset = 0; - block = QLIST_NEXT(block, next); - if (!block) - block = QLIST_FIRST(&ram_list.blocks); - } - } while (block != last_block || offset != last_offset); - - last_block = block; + } + last_seen_block = block; last_offset = offset; return bytes_sent; @@ -498,46 +519,21 @@ uint64_t ram_bytes_total(void) RAMBlock *block; uint64_t total = 0; - QLIST_FOREACH(block, &ram_list.blocks, next) + QTAILQ_FOREACH(block, &ram_list.blocks, next) total += block->length; return total; } -static int block_compar(const void *a, const void *b) -{ - RAMBlock * const *ablock = a; - RAMBlock * const *bblock = b; - - return strcmp((*ablock)->idstr, (*bblock)->idstr); -} - -static void sort_ram_list(void) -{ - RAMBlock *block, *nblock, **blocks; - int n; - n = 0; - QLIST_FOREACH(block, &ram_list.blocks, next) { - ++n; - } - blocks = g_malloc(n * sizeof *blocks); - n = 0; - QLIST_FOREACH_SAFE(block, &ram_list.blocks, next, nblock) { - blocks[n++] = block; - QLIST_REMOVE(block, next); - } - qsort(blocks, n, sizeof *blocks, block_compar); - while (--n >= 0) { - QLIST_INSERT_HEAD(&ram_list.blocks, blocks[n], next); - } - g_free(blocks); -} - static void migration_end(void) { - memory_global_dirty_log_stop(); + if (migration_bitmap) { + memory_global_dirty_log_stop(); + g_free(migration_bitmap); + migration_bitmap = NULL; + } - if (migrate_use_xbzrle()) { + if (XBZRLE.cache) { cache_fini(XBZRLE.cache); g_free(XBZRLE.cache); g_free(XBZRLE.encoded_buf); @@ -552,12 +548,12 @@ static void ram_migration_cancel(void *opaque) migration_end(); } - static void reset_ram_globals(void) { - last_block = NULL; + last_seen_block = NULL; + last_sent_block = NULL; last_offset = 0; - sort_ram_list(); + last_version = ram_list.version; } #define MAX_WAIT 50 /* ms, half buffered_file limit */ @@ -571,6 +567,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) bitmap_set(migration_bitmap, 0, ram_pages); migration_dirty_pages = ram_pages; + qemu_mutex_lock_ramlist(); bytes_transferred = 0; reset_ram_globals(); @@ -592,12 +589,13 @@ static int ram_save_setup(QEMUFile *f, void *opaque) qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE); - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { qemu_put_byte(f, strlen(block->idstr)); qemu_put_buffer(f, (uint8_t *)block->idstr, strlen(block->idstr)); qemu_put_be64(f, block->length); } + qemu_mutex_unlock_ramlist(); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); return 0; @@ -605,26 +603,28 @@ static int ram_save_setup(QEMUFile *f, void *opaque) static int ram_save_iterate(QEMUFile *f, void *opaque) { - uint64_t bytes_transferred_last; - double bwidth = 0; int ret; int i; - uint64_t expected_downtime; - MigrationState *s = migrate_get_current(); + int64_t t0; + int total_sent = 0; - bytes_transferred_last = bytes_transferred; - bwidth = qemu_get_clock_ns(rt_clock); + qemu_mutex_lock_ramlist(); + if (ram_list.version != last_version) { + reset_ram_globals(); + } + + t0 = qemu_get_clock_ns(rt_clock); i = 0; while ((ret = qemu_file_rate_limit(f)) == 0) { int bytes_sent; bytes_sent = ram_save_block(f, false); /* no more blocks to sent */ - if (bytes_sent < 0) { + if (bytes_sent == 0) { break; } - bytes_transferred += bytes_sent; + total_sent += bytes_sent; acct_info.iterations++; /* we want to check in the 1st loop, just in case it was the 1st time and we had to sync the dirty bitmap. @@ -632,7 +632,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) iterations */ if ((i & 63) == 0) { - uint64_t t1 = (qemu_get_clock_ns(rt_clock) - bwidth) / 1000000; + uint64_t t1 = (qemu_get_clock_ns(rt_clock) - t0) / 1000000; if (t1 > MAX_WAIT) { DPRINTF("big wait: %" PRIu64 " milliseconds, %d iterations\n", t1, i); @@ -643,39 +643,24 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) } if (ret < 0) { + bytes_transferred += total_sent; return ret; } - bwidth = qemu_get_clock_ns(rt_clock) - bwidth; - bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; - - /* if we haven't transferred anything this round, force - * expected_downtime to a very high value, but without - * crashing */ - if (bwidth == 0) { - bwidth = 0.000001; - } - + qemu_mutex_unlock_ramlist(); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + total_sent += 8; + bytes_transferred += total_sent; - expected_downtime = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; - DPRINTF("ram_save_live: expected(%" PRIu64 ") <= max(" PRIu64 ")?\n", - expected_downtime, migrate_max_downtime()); - - if (expected_downtime <= migrate_max_downtime()) { - migration_bitmap_sync(); - expected_downtime = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; - s->expected_downtime = expected_downtime / 1000000; /* ns -> ms */ - - return expected_downtime <= migrate_max_downtime(); - } - return 0; + return total_sent; } static int ram_save_complete(QEMUFile *f, void *opaque) { migration_bitmap_sync(); + qemu_mutex_lock_ramlist(); + /* try transferring iterative blocks of memory */ /* flush all remaining blocks regardless of rate limiting */ @@ -684,21 +669,32 @@ static int ram_save_complete(QEMUFile *f, void *opaque) bytes_sent = ram_save_block(f, true); /* no more blocks to sent */ - if (bytes_sent < 0) { + if (bytes_sent == 0) { break; } bytes_transferred += bytes_sent; } - memory_global_dirty_log_stop(); + migration_end(); + qemu_mutex_unlock_ramlist(); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - g_free(migration_bitmap); - migration_bitmap = NULL; - return 0; } +static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) +{ + uint64_t remaining_size; + + remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE; + + if (remaining_size < max_size) { + migration_bitmap_sync(); + remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE; + } + return remaining_size; +} + static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host) { int ret, rc = 0; @@ -761,7 +757,7 @@ static inline void *host_from_stream_offset(QEMUFile *f, qemu_get_buffer(f, (uint8_t *)id, len); id[len] = 0; - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (!strncmp(id, block->idstr, sizeof(id))) return memory_region_get_ram_ptr(block->mr) + offset; } @@ -805,7 +801,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) id[len] = 0; length = qemu_get_be64(f); - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (!strncmp(id, block->idstr, sizeof(id))) { if (block->length != length) { ret = -EINVAL; @@ -885,6 +881,7 @@ SaveVMHandlers savevm_ram_handlers = { .save_live_setup = ram_save_setup, .save_live_iterate = ram_save_iterate, .save_live_complete = ram_save_complete, + .save_live_pending = ram_save_pending, .load_state = ram_load, .cancel = ram_migration_cancel, }; diff --git a/block-migration.c b/block-migration.c index ca4ba3fffb..6acf3e1682 100644 --- a/block-migration.c +++ b/block-migration.c @@ -77,9 +77,7 @@ typedef struct BlkMigState { int64_t total_sector_sum; int prev_progress; int bulk_completed; - long double total_time; long double prev_time_offset; - int reads; } BlkMigState; static BlkMigState block_mig_state; @@ -132,12 +130,6 @@ uint64_t blk_mig_bytes_total(void) return sum << BDRV_SECTOR_BITS; } -static inline long double compute_read_bwidth(void) -{ - assert(block_mig_state.total_time != 0); - return (block_mig_state.reads / block_mig_state.total_time) * BLOCK_SIZE; -} - static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector) { int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK; @@ -191,8 +183,6 @@ static void blk_mig_read_cb(void *opaque, int ret) blk->ret = ret; - block_mig_state.reads++; - block_mig_state.total_time += (curr_time - block_mig_state.prev_time_offset); block_mig_state.prev_time_offset = curr_time; QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); @@ -310,8 +300,6 @@ static void init_blk_migration(QEMUFile *f) block_mig_state.total_sector_sum = 0; block_mig_state.prev_progress = -1; block_mig_state.bulk_completed = 0; - block_mig_state.total_time = 0; - block_mig_state.reads = 0; bdrv_iterate(init_blk_migration_it, NULL); } @@ -493,32 +481,6 @@ static int64_t get_remaining_dirty(void) return dirty * BLOCK_SIZE; } -static int is_stage2_completed(void) -{ - int64_t remaining_dirty; - long double bwidth; - - if (block_mig_state.bulk_completed == 1) { - - remaining_dirty = get_remaining_dirty(); - if (remaining_dirty == 0) { - return 1; - } - - bwidth = compute_read_bwidth(); - - if ((remaining_dirty / bwidth) <= - migrate_max_downtime()) { - /* finish stage2 because we think that we can finish remaining work - below max_downtime */ - - return 1; - } - } - - return 0; -} - static void blk_mig_cleanup(void) { BlkMigDevState *bmds; @@ -619,7 +581,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque) qemu_put_be64(f, BLK_MIG_FLAG_EOS); - return is_stage2_completed(); + return 0; } static int block_save_complete(QEMUFile *f, void *opaque) @@ -659,6 +621,14 @@ static int block_save_complete(QEMUFile *f, void *opaque) return 0; } +static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) +{ + + DPRINTF("Enter save live pending %ld\n", get_remaining_dirty()); + + return get_remaining_dirty(); +} + static int block_load(QEMUFile *f, void *opaque, int version_id) { static int banner_printed; @@ -755,6 +725,7 @@ SaveVMHandlers savevm_block_handlers = { .save_live_setup = block_save_setup, .save_live_iterate = block_save_iterate, .save_live_complete = block_save_complete, + .save_live_pending = block_save_pending, .load_state = block_load, .cancel = block_migration_cancel, .is_active = block_is_active, diff --git a/buffered_file.c b/buffered_file.c deleted file mode 100644 index 27627a1b71..0000000000 --- a/buffered_file.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * QEMU buffered QEMUFile - * - * Copyright IBM, Corp. 2008 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu-common.h" -#include "hw/hw.h" -#include "qemu/timer.h" -#include "buffered_file.h" - -//#define DEBUG_BUFFERED_FILE - -typedef struct QEMUFileBuffered -{ - MigrationState *migration_state; - QEMUFile *file; - int freeze_output; - size_t bytes_xfer; - size_t xfer_limit; - uint8_t *buffer; - size_t buffer_size; - size_t buffer_capacity; - QEMUTimer *timer; -} QEMUFileBuffered; - -#ifdef DEBUG_BUFFERED_FILE -#define DPRINTF(fmt, ...) \ - do { printf("buffered-file: " fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - -static void buffered_append(QEMUFileBuffered *s, - const uint8_t *buf, size_t size) -{ - if (size > (s->buffer_capacity - s->buffer_size)) { - DPRINTF("increasing buffer capacity from %zu by %zu\n", - s->buffer_capacity, size + 1024); - - s->buffer_capacity += size + 1024; - - s->buffer = g_realloc(s->buffer, s->buffer_capacity); - } - - memcpy(s->buffer + s->buffer_size, buf, size); - s->buffer_size += size; -} - -static ssize_t buffered_flush(QEMUFileBuffered *s) -{ - size_t offset = 0; - ssize_t ret = 0; - - DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); - - while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { - - ret = migrate_fd_put_buffer(s->migration_state, s->buffer + offset, - s->buffer_size - offset); - if (ret == -EAGAIN) { - DPRINTF("backend not ready, freezing\n"); - ret = 0; - s->freeze_output = 1; - break; - } - - if (ret <= 0) { - DPRINTF("error flushing data, %zd\n", ret); - break; - } else { - DPRINTF("flushed %zd byte(s)\n", ret); - offset += ret; - s->bytes_xfer += ret; - } - } - - DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size); - memmove(s->buffer, s->buffer + offset, s->buffer_size - offset); - s->buffer_size -= offset; - - if (ret < 0) { - return ret; - } - return offset; -} - -static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) -{ - QEMUFileBuffered *s = opaque; - ssize_t error; - - DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); - - error = qemu_file_get_error(s->file); - if (error) { - DPRINTF("flush when error, bailing: %s\n", strerror(-error)); - return error; - } - - DPRINTF("unfreezing output\n"); - s->freeze_output = 0; - - if (size > 0) { - DPRINTF("buffering %d bytes\n", size - offset); - buffered_append(s, buf, size); - } - - error = buffered_flush(s); - if (error < 0) { - DPRINTF("buffered flush error. bailing: %s\n", strerror(-error)); - return error; - } - - if (pos == 0 && size == 0) { - DPRINTF("file is ready\n"); - if (!s->freeze_output && s->bytes_xfer < s->xfer_limit) { - DPRINTF("notifying client\n"); - migrate_fd_put_ready(s->migration_state); - } - } - - return size; -} - -static int buffered_close(void *opaque) -{ - QEMUFileBuffered *s = opaque; - ssize_t ret = 0; - int ret2; - - DPRINTF("closing\n"); - - s->xfer_limit = INT_MAX; - while (!qemu_file_get_error(s->file) && s->buffer_size) { - ret = buffered_flush(s); - if (ret < 0) { - break; - } - if (s->freeze_output) { - ret = migrate_fd_wait_for_unfreeze(s->migration_state); - if (ret < 0) { - break; - } - } - } - - ret2 = migrate_fd_close(s->migration_state); - if (ret >= 0) { - ret = ret2; - } - qemu_del_timer(s->timer); - qemu_free_timer(s->timer); - g_free(s->buffer); - g_free(s); - - return ret; -} - -/* - * The meaning of the return values is: - * 0: We can continue sending - * 1: Time to stop - * negative: There has been an error - */ -static int buffered_get_fd(void *opaque) -{ - QEMUFileBuffered *s = opaque; - - return qemu_get_fd(s->file); -} - -static int buffered_rate_limit(void *opaque) -{ - QEMUFileBuffered *s = opaque; - int ret; - - ret = qemu_file_get_error(s->file); - if (ret) { - return ret; - } - if (s->freeze_output) - return 1; - - if (s->bytes_xfer > s->xfer_limit) - return 1; - - return 0; -} - -static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate) -{ - QEMUFileBuffered *s = opaque; - if (qemu_file_get_error(s->file)) { - goto out; - } - if (new_rate > SIZE_MAX) { - new_rate = SIZE_MAX; - } - - s->xfer_limit = new_rate / 10; - -out: - return s->xfer_limit; -} - -static int64_t buffered_get_rate_limit(void *opaque) -{ - QEMUFileBuffered *s = opaque; - - return s->xfer_limit; -} - -static void buffered_rate_tick(void *opaque) -{ - QEMUFileBuffered *s = opaque; - - if (qemu_file_get_error(s->file)) { - buffered_close(s); - return; - } - - qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100); - - if (s->freeze_output) - return; - - s->bytes_xfer = 0; - - buffered_put_buffer(s, NULL, 0, 0); -} - -static const QEMUFileOps buffered_file_ops = { - .get_fd = buffered_get_fd, - .put_buffer = buffered_put_buffer, - .close = buffered_close, - .rate_limit = buffered_rate_limit, - .get_rate_limit = buffered_get_rate_limit, - .set_rate_limit = buffered_set_rate_limit, -}; - -QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state) -{ - QEMUFileBuffered *s; - - s = g_malloc0(sizeof(*s)); - - s->migration_state = migration_state; - s->xfer_limit = migration_state->bandwidth_limit / 10; - - s->file = qemu_fopen_ops(s, &buffered_file_ops); - - s->timer = qemu_new_timer_ms(rt_clock, buffered_rate_tick, s); - - qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100); - - return s->file; -} diff --git a/buffered_file.h b/buffered_file.h deleted file mode 100644 index 86a7075246..0000000000 --- a/buffered_file.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * QEMU buffered QEMUFile - * - * Copyright IBM, Corp. 2008 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#ifndef QEMU_BUFFERED_FILE_H -#define QEMU_BUFFERED_FILE_H - -#include "hw/hw.h" -#include "migration/migration.h" - -QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state); - -#endif diff --git a/configure b/configure index b101d5c1b7..b0c7e542c6 100755 --- a/configure +++ b/configure @@ -656,6 +656,8 @@ for opt do ;; --without-system-pixman) pixman="internal" ;; + --without-pixman) pixman="none" + ;; --disable-sdl) sdl="no" ;; --enable-sdl) sdl="yes" @@ -1712,6 +1714,7 @@ EOF if compile_prog "$vnc_tls_cflags" "$vnc_tls_libs" ; then vnc_tls=yes libs_softmmu="$vnc_tls_libs $libs_softmmu" + QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags" else if test "$vnc_tls" = "yes" ; then feature_not_found "vnc-tls" @@ -1734,6 +1737,7 @@ EOF if compile_prog "$vnc_sasl_cflags" "$vnc_sasl_libs" ; then vnc_sasl=yes libs_softmmu="$vnc_sasl_libs $libs_softmmu" + QEMU_CFLAGS="$QEMU_CFLAGS $vnc_sasl_cflags" else if test "$vnc_sasl" = "yes" ; then feature_not_found "vnc-sasl" @@ -1755,6 +1759,7 @@ EOF if compile_prog "$vnc_jpeg_cflags" "$vnc_jpeg_libs" ; then vnc_jpeg=yes libs_softmmu="$vnc_jpeg_libs $libs_softmmu" + QEMU_CFLAGS="$QEMU_CFLAGS $vnc_jpeg_cflags" else if test "$vnc_jpeg" = "yes" ; then feature_not_found "vnc-jpeg" @@ -2127,13 +2132,25 @@ fi # pixman support probe if test "$pixman" = ""; then - if $pkg_config pixman-1 > /dev/null 2>&1; then + if test "$want_tools" = "no" -a "$softmmu" = "no"; then + pixman="none" + elif $pkg_config pixman-1 > /dev/null 2>&1; then pixman="system" else pixman="internal" fi fi -if test "$pixman" = "system"; then +if test "$pixman" = "none"; then + if test "$want_tools" != "no" -o "$softmmu" != "no"; then + echo "ERROR: pixman disabled but system emulation or tools build" + echo " enabled. You can turn off pixman only if you also" + echo " disable all system emulation targets and the tools" + echo " build with '--disable-tools --disable-system'." + exit 1 + fi + pixman_cflags= + pixman_libs= +elif test "$pixman" = "system"; then pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null` pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null` else @@ -3069,6 +3086,21 @@ if compile_prog "" "" ; then has_environ=yes fi +######################################## +# check if cpuid.h is usable. + +cpuid_h=no +cat > $TMPC << EOF +#include <cpuid.h> +int main(void) { + return 0; +} +EOF +if compile_prog "" "" ; then + cpuid_h=yes +fi + + ########################################## # End of CC checks # After here, no more $cc or $ld runs @@ -3377,19 +3409,15 @@ if test "$vnc" = "yes" ; then fi if test "$vnc_tls" = "yes" ; then echo "CONFIG_VNC_TLS=y" >> $config_host_mak - echo "VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_host_mak fi if test "$vnc_sasl" = "yes" ; then echo "CONFIG_VNC_SASL=y" >> $config_host_mak - echo "VNC_SASL_CFLAGS=$vnc_sasl_cflags" >> $config_host_mak fi if test "$vnc_jpeg" = "yes" ; then echo "CONFIG_VNC_JPEG=y" >> $config_host_mak - echo "VNC_JPEG_CFLAGS=$vnc_jpeg_cflags" >> $config_host_mak fi if test "$vnc_png" = "yes" ; then echo "CONFIG_VNC_PNG=y" >> $config_host_mak - echo "VNC_PNG_CFLAGS=$vnc_png_cflags" >> $config_host_mak fi if test "$fnmatch" = "yes" ; then echo "CONFIG_FNMATCH=y" >> $config_host_mak @@ -3598,6 +3626,10 @@ if test "$has_environ" = "yes" ; then echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak fi +if test "$cpuid_h" = "yes" ; then + echo "CONFIG_CPUID_H=y" >> $config_host_mak +fi + if test "$glusterfs" = "yes" ; then echo "CONFIG_GLUSTERFS=y" >> $config_host_mak fi diff --git a/dump.c b/dump.c index a26b1a5e1a..4ed1fa8622 100644 --- a/dump.c +++ b/dump.c @@ -427,7 +427,7 @@ static hwaddr get_offset(hwaddr phys_addr, } } - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (s->has_filter) { if (block->offset >= s->begin + s->length || block->offset + block->length <= s->begin) { @@ -594,7 +594,7 @@ static int dump_completed(DumpState *s) static int get_next_block(DumpState *s, RAMBlock *block) { while (1) { - block = QLIST_NEXT(block, next); + block = QTAILQ_NEXT(block, next); if (!block) { /* no more block */ return 1; @@ -670,11 +670,11 @@ static ram_addr_t get_start_block(DumpState *s) RAMBlock *block; if (!s->has_filter) { - s->block = QLIST_FIRST(&ram_list.blocks); + s->block = QTAILQ_FIRST(&ram_list.blocks); return 0; } - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (block->offset >= s->begin + s->length || block->offset + block->length <= s->begin) { /* This block is out of the range */ diff --git a/exec.c b/exec.c index 28abd7e710..a6923addd4 100644 --- a/exec.c +++ b/exec.c @@ -43,6 +43,7 @@ #include "sysemu/xen-mapcache.h" #include "trace.h" #endif +#include "exec/cpu-all.h" #include "exec/cputlb.h" #include "translate-all.h" @@ -56,7 +57,7 @@ int phys_ram_fd; static int in_migration; -RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) }; +RAMList ram_list = { .blocks = QTAILQ_HEAD_INITIALIZER(ram_list.blocks) }; static MemoryRegion *system_memory; static MemoryRegion *system_io; @@ -212,6 +213,7 @@ bool memory_region_is_unassigned(MemoryRegion *mr) void cpu_exec_init_all(void) { #if !defined(CONFIG_USER_ONLY) + qemu_mutex_init(&ram_list.mutex); memory_map_init(); io_mem_init(); #endif @@ -800,6 +802,16 @@ void qemu_flush_coalesced_mmio_buffer(void) kvm_flush_coalesced_mmio_buffer(); } +void qemu_mutex_lock_ramlist(void) +{ + qemu_mutex_lock(&ram_list.mutex); +} + +void qemu_mutex_unlock_ramlist(void) +{ + qemu_mutex_unlock(&ram_list.mutex); +} + #if defined(__linux__) && !defined(TARGET_S390X) #include <sys/vfs.h> @@ -901,15 +913,15 @@ static ram_addr_t find_ram_offset(ram_addr_t size) RAMBlock *block, *next_block; ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX; - if (QLIST_EMPTY(&ram_list.blocks)) + if (QTAILQ_EMPTY(&ram_list.blocks)) return 0; - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { ram_addr_t end, next = RAM_ADDR_MAX; end = block->offset + block->length; - QLIST_FOREACH(next_block, &ram_list.blocks, next) { + QTAILQ_FOREACH(next_block, &ram_list.blocks, next) { if (next_block->offset >= end) { next = MIN(next, next_block->offset); } @@ -934,7 +946,7 @@ ram_addr_t last_ram_offset(void) RAMBlock *block; ram_addr_t last = 0; - QLIST_FOREACH(block, &ram_list.blocks, next) + QTAILQ_FOREACH(block, &ram_list.blocks, next) last = MAX(last, block->offset + block->length); return last; @@ -963,7 +975,7 @@ void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev) RAMBlock *new_block, *block; new_block = NULL; - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (block->offset == addr) { new_block = block; break; @@ -981,13 +993,16 @@ void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev) } pstrcat(new_block->idstr, sizeof(new_block->idstr), name); - QLIST_FOREACH(block, &ram_list.blocks, next) { + /* This assumes the iothread lock is taken here too. */ + qemu_mutex_lock_ramlist(); + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (block != new_block && !strcmp(block->idstr, new_block->idstr)) { fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n", new_block->idstr); abort(); } } + qemu_mutex_unlock_ramlist(); } static int memory_try_enable_merging(void *addr, size_t len) @@ -1006,11 +1021,13 @@ static int memory_try_enable_merging(void *addr, size_t len) ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, MemoryRegion *mr) { - RAMBlock *new_block; + RAMBlock *block, *new_block; size = TARGET_PAGE_ALIGN(size); new_block = g_malloc0(sizeof(*new_block)); + /* This assumes the iothread lock is taken here too. */ + qemu_mutex_lock_ramlist(); new_block->mr = mr; new_block->offset = find_ram_offset(size); if (host) { @@ -1042,7 +1059,21 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, } new_block->length = size; - QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next); + /* Keep the list sorted from biggest to smallest block. */ + QTAILQ_FOREACH(block, &ram_list.blocks, next) { + if (block->length < new_block->length) { + break; + } + } + if (block) { + QTAILQ_INSERT_BEFORE(block, new_block, next); + } else { + QTAILQ_INSERT_TAIL(&ram_list.blocks, new_block, next); + } + ram_list.mru_block = NULL; + + ram_list.version++; + qemu_mutex_unlock_ramlist(); ram_list.phys_dirty = g_realloc(ram_list.phys_dirty, last_ram_offset() >> TARGET_PAGE_BITS); @@ -1068,22 +1099,31 @@ void qemu_ram_free_from_ptr(ram_addr_t addr) { RAMBlock *block; - QLIST_FOREACH(block, &ram_list.blocks, next) { + /* This assumes the iothread lock is taken here too. */ + qemu_mutex_lock_ramlist(); + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (addr == block->offset) { - QLIST_REMOVE(block, next); + QTAILQ_REMOVE(&ram_list.blocks, block, next); + ram_list.mru_block = NULL; + ram_list.version++; g_free(block); - return; + break; } } + qemu_mutex_unlock_ramlist(); } void qemu_ram_free(ram_addr_t addr) { RAMBlock *block; - QLIST_FOREACH(block, &ram_list.blocks, next) { + /* This assumes the iothread lock is taken here too. */ + qemu_mutex_lock_ramlist(); + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (addr == block->offset) { - QLIST_REMOVE(block, next); + QTAILQ_REMOVE(&ram_list.blocks, block, next); + ram_list.mru_block = NULL; + ram_list.version++; if (block->flags & RAM_PREALLOC_MASK) { ; } else if (mem_path) { @@ -1109,9 +1149,10 @@ void qemu_ram_free(ram_addr_t addr) #endif } g_free(block); - return; + break; } } + qemu_mutex_unlock_ramlist(); } @@ -1123,7 +1164,7 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length) int flags; void *area, *vaddr; - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { offset = addr - block->offset; if (offset < block->length) { vaddr = block->host + offset; @@ -1189,43 +1230,48 @@ void *qemu_get_ram_ptr(ram_addr_t addr) { RAMBlock *block; - QLIST_FOREACH(block, &ram_list.blocks, next) { + /* The list is protected by the iothread lock here. */ + block = ram_list.mru_block; + if (block && addr - block->offset < block->length) { + goto found; + } + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (addr - block->offset < block->length) { - /* Move this entry to to start of the list. */ - if (block != QLIST_FIRST(&ram_list.blocks)) { - QLIST_REMOVE(block, next); - QLIST_INSERT_HEAD(&ram_list.blocks, block, next); - } - if (xen_enabled()) { - /* We need to check if the requested address is in the RAM - * because we don't want to map the entire memory in QEMU. - * In that case just map until the end of the page. - */ - if (block->offset == 0) { - return xen_map_cache(addr, 0, 0); - } else if (block->host == NULL) { - block->host = - xen_map_cache(block->offset, block->length, 1); - } - } - return block->host + (addr - block->offset); + goto found; } } fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); abort(); - return NULL; +found: + ram_list.mru_block = block; + if (xen_enabled()) { + /* We need to check if the requested address is in the RAM + * because we don't want to map the entire memory in QEMU. + * In that case just map until the end of the page. + */ + if (block->offset == 0) { + return xen_map_cache(addr, 0, 0); + } else if (block->host == NULL) { + block->host = + xen_map_cache(block->offset, block->length, 1); + } + } + return block->host + (addr - block->offset); } -/* Return a host pointer to ram allocated with qemu_ram_alloc. - * Same as qemu_get_ram_ptr but avoid reordering ramblocks. +/* Return a host pointer to ram allocated with qemu_ram_alloc. Same as + * qemu_get_ram_ptr but do not touch ram_list.mru_block. + * + * ??? Is this still necessary? */ static void *qemu_safe_ram_ptr(ram_addr_t addr) { RAMBlock *block; - QLIST_FOREACH(block, &ram_list.blocks, next) { + /* The list is protected by the iothread lock here. */ + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (addr - block->offset < block->length) { if (xen_enabled()) { /* We need to check if the requested address is in the RAM @@ -1261,7 +1307,7 @@ static void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size) } else { RAMBlock *block; - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (addr - block->offset < block->length) { if (addr - block->offset + *size > block->length) *size = block->length - addr + block->offset; @@ -1289,7 +1335,7 @@ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr) return 0; } - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { /* This case append when the block is not mapped. */ if (block->host == NULL) { continue; diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 2778035b1c..d75f2f0bd7 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -181,6 +181,7 @@ common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += msmouse.o ps2.o common-obj-y += qdev.o qdev-properties.o qdev-monitor.o +common-obj-y += qdev-properties-system.o common-obj-$(CONFIG_BRLAPI) += baum.o # xen backend driver support diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index e7e52c1f1c..e2980e9893 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -50,7 +50,7 @@ static void clipper_init(QEMUMachineInitArgs *args) const char *kernel_filename = args->kernel_filename; const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; - CPUAlphaState *cpus[4]; + AlphaCPU *cpus[4]; PCIBus *pci_bus; ISABus *isa_bus; qemu_irq rtc_irq; @@ -62,12 +62,12 @@ static void clipper_init(QEMUMachineInitArgs *args) /* Create up to 4 cpus. */ memset(cpus, 0, sizeof(cpus)); for (i = 0; i < smp_cpus; ++i) { - cpus[i] = cpu_init(cpu_model ? cpu_model : "ev67"); + cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67"); } - cpus[0]->trap_arg0 = ram_size; - cpus[0]->trap_arg1 = 0; - cpus[0]->trap_arg2 = smp_cpus; + cpus[0]->env.trap_arg0 = ram_size; + cpus[0]->env.trap_arg1 = 0; + cpus[0]->env.trap_arg2 = smp_cpus; /* Init the chipset. */ pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, @@ -119,9 +119,9 @@ static void clipper_init(QEMUMachineInitArgs *args) /* Start all cpus at the PALcode RESET entry point. */ for (i = 0; i < smp_cpus; ++i) { - cpus[i]->pal_mode = 1; - cpus[i]->pc = palcode_entry; - cpus[i]->palbr = palcode_entry; + cpus[i]->env.pal_mode = 1; + cpus[i]->env.pc = palcode_entry; + cpus[i]->env.palbr = palcode_entry; } /* Load a kernel. */ @@ -136,7 +136,7 @@ static void clipper_init(QEMUMachineInitArgs *args) exit(1); } - cpus[0]->trap_arg1 = kernel_entry; + cpus[0]->env.trap_arg1 = kernel_entry; param_offset = kernel_low - 0x6000; diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index 348f55c27e..233a71ecdb 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -10,7 +10,7 @@ #include "irq.h" -PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, CPUAlphaState *[4], +PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4], pci_map_irq_fn); /* alpha_pci.c. */ diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 9f233d99f5..dafb35ddd1 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -23,7 +23,7 @@ typedef struct TyphoonCchip { uint64_t drir; uint64_t dim[4]; uint32_t iic[4]; - CPUAlphaState *cpu[4]; + AlphaCPU *cpu[4]; } TyphoonCchip; typedef struct TyphoonWindow { @@ -58,10 +58,11 @@ typedef struct TyphoonState { } TyphoonState; /* Called when one of DRIR or DIM changes. */ -static void cpu_irq_change(CPUAlphaState *env, uint64_t req) +static void cpu_irq_change(AlphaCPU *cpu, uint64_t req) { /* If there are any non-masked interrupts, tell the cpu. */ - if (env) { + if (cpu != NULL) { + CPUAlphaState *env = &cpu->env; if (req) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { @@ -353,8 +354,9 @@ static void cchip_write(void *opaque, hwaddr addr, if ((newval ^ oldval) & 0xff0) { int i; for (i = 0; i < 4; ++i) { - CPUAlphaState *env = s->cchip.cpu[i]; - if (env) { + AlphaCPU *cpu = s->cchip.cpu[i]; + if (cpu != NULL) { + CPUAlphaState *env = &cpu->env; /* IPI can be either cleared or set by the write. */ if (newval & (1 << (i + 8))) { cpu_interrupt(env, CPU_INTERRUPT_SMP); @@ -661,8 +663,8 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level) /* Deliver the interrupt to each CPU, considering each CPU's IIC. */ for (i = 0; i < 4; ++i) { - CPUAlphaState *env = s->cchip.cpu[i]; - if (env) { + AlphaCPU *cpu = s->cchip.cpu[i]; + if (cpu != NULL) { uint32_t iic = s->cchip.iic[i]; /* ??? The verbage in Section 10.2.2.10 isn't 100% clear. @@ -681,7 +683,7 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level) /* Set the ITI bit for this cpu. */ s->cchip.misc |= 1 << (i + 4); /* And signal the interrupt. */ - cpu_interrupt(env, CPU_INTERRUPT_TIMER); + cpu_interrupt(&cpu->env, CPU_INTERRUPT_TIMER); } } } @@ -694,12 +696,12 @@ static void typhoon_alarm_timer(void *opaque) /* Set the ITI bit for this cpu. */ s->cchip.misc |= 1 << (cpu + 4); - cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER); + cpu_interrupt(&s->cchip.cpu[cpu]->env, CPU_INTERRUPT_TIMER); } PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, qemu_irq *p_rtc_irq, - CPUAlphaState *cpus[4], pci_map_irq_fn sys_map_irq) + AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq) { const uint64_t MB = 1024 * 1024; const uint64_t GB = 1024 * MB; @@ -719,10 +721,10 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, /* Remember the CPUs so that we can deliver interrupts to them. */ for (i = 0; i < 4; i++) { - CPUAlphaState *env = cpus[i]; - s->cchip.cpu[i] = env; - if (env) { - env->alarm_timer = qemu_new_timer_ns(rtc_clock, + AlphaCPU *cpu = cpus[i]; + s->cchip.cpu[i] = cpu; + if (cpu != NULL) { + cpu->alarm_timer = qemu_new_timer_ns(rtc_clock, typhoon_alarm_timer, (void *)((uintptr_t)s + i)); } diff --git a/hw/i2c.h b/hw/i2c.h index 0f5682b4b0..883b5c588d 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -73,9 +73,6 @@ void *wm8750_dac_buffer(void *opaque, int samples); void wm8750_dac_commit(void *opaque); void wm8750_set_bclk_in(void *opaque, int new_hz); -/* tmp105.c */ -void tmp105_set(I2CSlave *i2c, int temp); - /* lm832x.c */ void lm832x_key_event(DeviceState *dev, int key, int state); diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c index dad2f21c18..a4e834744b 100644 --- a/hw/kvm/apic.c +++ b/hw/kvm/apic.c @@ -104,7 +104,7 @@ static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable) .enabled = enable }; - kvm_vcpu_ioctl(&s->cpu->env, KVM_TPR_ACCESS_REPORTING, &ctl); + kvm_vcpu_ioctl(CPU(s->cpu), KVM_TPR_ACCESS_REPORTING, &ctl); } static void kvm_apic_vapic_base_update(APICCommonState *s) @@ -114,7 +114,7 @@ static void kvm_apic_vapic_base_update(APICCommonState *s) }; int ret; - ret = kvm_vcpu_ioctl(&s->cpu->env, KVM_SET_VAPIC_ADDR, &vapid_addr); + ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_VAPIC_ADDR, &vapid_addr); if (ret < 0) { fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n", strerror(-ret)); @@ -125,15 +125,15 @@ static void kvm_apic_vapic_base_update(APICCommonState *s) static void do_inject_external_nmi(void *data) { APICCommonState *s = data; - CPUX86State *env = &s->cpu->env; + CPUState *cpu = CPU(s->cpu); uint32_t lvt; int ret; - cpu_synchronize_state(env); + cpu_synchronize_state(&s->cpu->env); lvt = s->lvt[APIC_LVT_LINT1]; if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) { - ret = kvm_vcpu_ioctl(env, KVM_NMI); + ret = kvm_vcpu_ioctl(cpu, KVM_NMI); if (ret < 0) { fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", strerror(-ret)); diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c index 6fcca95ada..be24973df9 100644 --- a/hw/kvm/clock.c +++ b/hw/kvm/clock.c @@ -76,7 +76,7 @@ static void kvmclock_vm_state_change(void *opaque, int running, return; } for (penv = first_cpu; penv != NULL; penv = penv->next_cpu) { - ret = kvm_vcpu_ioctl(penv, KVM_KVMCLOCK_CTRL, 0); + ret = kvm_vcpu_ioctl(ENV_GET_CPU(penv), KVM_KVMCLOCK_CTRL, 0); if (ret) { if (ret != -EINVAL) { fprintf(stderr, "%s: %s\n", __func__, strerror(-ret)); diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 95e07e7cdb..aadedefb25 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -319,6 +319,9 @@ static void pflash_write(pflash_t *pfl, hwaddr offset, DPRINTF("%s: Write to buffer\n", __func__); pfl->status |= 0x80; /* Ready! */ break; + case 0xf0: /* Probe for AMD flash */ + DPRINTF("%s: Probe for AMD flash\n", __func__); + goto reset_flash; case 0xff: /* Read array mode */ DPRINTF("%s: Read array mode\n", __func__); goto reset_flash; diff --git a/hw/ppc.c b/hw/ppc.c index 1559982625..e473f9e962 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -50,8 +50,9 @@ static void cpu_ppc_tb_stop (CPUPPCState *env); static void cpu_ppc_tb_start (CPUPPCState *env); -void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level) +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) { + CPUPPCState *env = &cpu->env; unsigned int old_pending = env->pending_interrupts; if (level) { @@ -65,7 +66,7 @@ void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level) if (old_pending != env->pending_interrupts) { #ifdef CONFIG_KVM - kvmppc_set_interrupt(env, n_IRQ, level); + kvmppc_set_interrupt(cpu, n_IRQ, level); #endif } @@ -100,13 +101,13 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC6xx_INPUT_SMI: /* Level sensitive - active high */ LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_SMI, level); + ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); break; case PPC6xx_INPUT_MCP: /* Negative edge sensitive */ @@ -116,7 +117,7 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) if (cur_level == 1 && level == 0) { LOG_IRQ("%s: raise machine check state\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); } break; case PPC6xx_INPUT_CKSTP_IN: @@ -138,7 +139,7 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) case PPC6xx_INPUT_SRESET: LOG_IRQ("%s: set the RESET IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); break; default: /* Unknown pin - do nothing */ @@ -178,13 +179,13 @@ static void ppc970_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC970_INPUT_THINT: /* Level sensitive - active high */ LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_THERM, level); + ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); break; case PPC970_INPUT_MCP: /* Negative edge sensitive */ @@ -194,7 +195,7 @@ static void ppc970_set_irq(void *opaque, int pin, int level) if (cur_level == 1 && level == 0) { LOG_IRQ("%s: raise machine check state\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); } break; case PPC970_INPUT_CKSTP: @@ -218,7 +219,7 @@ static void ppc970_set_irq(void *opaque, int pin, int level) case PPC970_INPUT_SRESET: LOG_IRQ("%s: set the RESET IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); break; case PPC970_INPUT_TBEN: LOG_IRQ("%s: set the TBEN state to %d\n", __func__, @@ -259,7 +260,7 @@ static void power7_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; default: /* Unknown pin - do nothing */ @@ -319,13 +320,13 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the critical IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_CEXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); break; case PPC40x_INPUT_INT: /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC40x_INPUT_HALT: /* Level sensitive - active low */ @@ -342,7 +343,7 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the debug pin state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level); + ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); break; default: /* Unknown pin - do nothing */ @@ -387,26 +388,26 @@ static void ppce500_set_irq(void *opaque, int pin, int level) case PPCE500_INPUT_RESET_CORE: if (level) { LOG_IRQ("%s: reset the PowerPC core\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, level); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); } break; case PPCE500_INPUT_CINT: /* Level sensitive - active high */ LOG_IRQ("%s: set the critical IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_CEXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); break; case PPCE500_INPUT_INT: /* Level sensitive - active high */ LOG_IRQ("%s: set the core IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPCE500_INPUT_DEBUG: /* Level sensitive - active high */ LOG_IRQ("%s: set the debug pin state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level); + ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); break; default: /* Unknown pin - do nothing */ @@ -643,26 +644,27 @@ uint64_t cpu_ppc_load_purr (CPUPPCState *env) /* When decrementer expires, * all we need to do is generate or queue a CPU exception */ -static inline void cpu_ppc_decr_excp(CPUPPCState *env) +static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) { /* Raise it */ LOG_TB("raise decrementer exception\n"); - ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); } -static inline void cpu_ppc_hdecr_excp(CPUPPCState *env) +static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) { /* Raise it */ LOG_TB("raise decrementer exception\n"); - ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); } -static void __cpu_ppc_store_decr (CPUPPCState *env, uint64_t *nextp, - struct QEMUTimer *timer, - void (*raise_excp)(CPUPPCState *), - uint32_t decr, uint32_t value, - int is_excp) +static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, + struct QEMUTimer *timer, + void (*raise_excp)(PowerPCCPU *), + uint32_t decr, uint32_t value, + int is_excp) { + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env = env->tb_env; uint64_t now, next; @@ -692,53 +694,61 @@ static void __cpu_ppc_store_decr (CPUPPCState *env, uint64_t *nextp, if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000) && !(decr & 0x80000000)) { - (*raise_excp)(env); + (*raise_excp)(cpu); } } -static inline void _cpu_ppc_store_decr(CPUPPCState *env, uint32_t decr, +static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr, uint32_t value, int is_excp) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; - __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer, + __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, &cpu_ppc_decr_excp, decr, value, is_excp); } void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value) { - _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0); + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0); } -static void cpu_ppc_decr_cb (void *opaque) +static void cpu_ppc_decr_cb(void *opaque) { - _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); + PowerPCCPU *cpu = opaque; + + _cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1); } -static inline void _cpu_ppc_store_hdecr(CPUPPCState *env, uint32_t hdecr, +static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr, uint32_t value, int is_excp) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; if (tb_env->hdecr_timer != NULL) { - __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer, + __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, &cpu_ppc_hdecr_excp, hdecr, value, is_excp); } } void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value) { - _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0); + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0); } -static void cpu_ppc_hdecr_cb (void *opaque) +static void cpu_ppc_hdecr_cb(void *opaque) { - _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1); + PowerPCCPU *cpu = opaque; + + _cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1); } -static void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) +static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; tb_env->purr_load = value; tb_env->purr_start = qemu_get_clock_ns(vm_clock); @@ -747,6 +757,7 @@ static void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) { CPUPPCState *env = opaque; + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env = env->tb_env; tb_env->tb_freq = freq; @@ -755,25 +766,27 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) * if a decrementer exception is pending when it enables msr_ee at startup, * it's not ready to handle it... */ - _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); - _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); - cpu_ppc_store_purr(env, 0x0000000000000000ULL); + _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); + _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); + cpu_ppc_store_purr(cpu, 0x0000000000000000ULL); } /* Set up (once) timebase frequency (in Hz) */ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env; tb_env = g_malloc0(sizeof(ppc_tb_t)); env->tb_env = tb_env; tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; /* Create new timer */ - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, env); + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu); if (0) { /* XXX: find a suitable condition to enable the hypervisor decrementer */ - tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, env); + tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, + cpu); } else { tb_env->hdecr_timer = NULL; } @@ -829,12 +842,14 @@ struct ppc40x_timer_t { /* Fixed interval timer */ static void cpu_4xx_fit_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; uint64_t now, next; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; now = qemu_get_clock_ns(vm_clock); @@ -860,8 +875,9 @@ static void cpu_4xx_fit_cb (void *opaque) next++; qemu_mod_timer(ppc40x_timer->fit_timer, next); env->spr[SPR_40x_TSR] |= 1 << 26; - if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) - ppc_set_irq(env, PPC_INTERRUPT_FIT, 1); + if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { + ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); + } LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); @@ -897,16 +913,19 @@ static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) static void cpu_4xx_pit_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; env->spr[SPR_40x_TSR] |= 1 << 27; - if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) - ppc_set_irq(env, ppc40x_timer->decr_excp, 1); + if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { + ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); + } start_stop_pit(env, tb_env, 1); LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " "%016" PRIx64 "\n", __func__, @@ -919,12 +938,14 @@ static void cpu_4xx_pit_cb (void *opaque) /* Watchdog timer */ static void cpu_4xx_wdt_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; uint64_t now, next; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; now = qemu_get_clock_ns(vm_clock); @@ -961,8 +982,9 @@ static void cpu_4xx_wdt_cb (void *opaque) qemu_mod_timer(ppc40x_timer->wdt_timer, next); ppc40x_timer->wdt_next = next; env->spr[SPR_40x_TSR] |= 1 << 30; - if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) - ppc_set_irq(env, PPC_INTERRUPT_WDT, 1); + if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { + ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); + } break; case 0x3: env->spr[SPR_40x_TSR] &= ~0x30000000; diff --git a/hw/ppc.h b/hw/ppc.h index 17005c795a..e73ae83b52 100644 --- a/hw/ppc.h +++ b/hw/ppc.h @@ -1,7 +1,7 @@ #ifndef HW_PPC_H #define HW_PPC_H 1 -void ppc_set_irq (CPUPPCState *env, int n_IRQ, int level); +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); /* PowerPC hardware exceptions management helpers */ typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); @@ -92,6 +92,6 @@ enum { #define PPC_SERIAL_MM_BAUDBASE 399193 /* ppc_booke.c */ -void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags); +void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags); #endif diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index aa54fd84d7..b262f31e5a 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -496,7 +496,7 @@ void ppce500_init(PPCE500Params *params) env->mpic_cpu_base = MPC8544_CCSRBAR_BASE + MPC8544_MPIC_REGS_OFFSET + 0x20000; - ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500); + ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); /* Register reset handler */ if (!i) { diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 7e56ecb4af..c96d103d1c 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -2111,12 +2111,14 @@ CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem, { clk_setup_t clk_setup[PPC405CR_CLK_NB]; qemu_irq dma_irqs[4]; + PowerPCCPU *cpu; CPUPPCState *env; qemu_irq *pic, *irqs; memset(clk_setup, 0, sizeof(clk_setup)); - env = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], + cpu = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], &clk_setup[PPC405CR_TMR_CLK], sysclk); + env = &cpu->env; /* Memory mapped devices registers */ /* PLB arbitrer */ ppc4xx_plb_init(env); @@ -2460,13 +2462,15 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, { clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup; qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4]; + PowerPCCPU *cpu; CPUPPCState *env; qemu_irq *pic, *irqs; memset(clk_setup, 0, sizeof(clk_setup)); /* init CPUs */ - env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], + cpu = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], &tlb_clk_setup, sysclk); + env = &cpu->env; clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; /* Internal devices init */ @@ -2478,7 +2482,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, /* OBP arbitrer */ ppc4xx_opba_init(0xef600600); /* Initialize timers */ - ppc_booke_timers_init(env, sysclk, 0); + ppc_booke_timers_init(cpu, sysclk, 0); /* Universal interrupt controller */ irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); irqs[PPCUIC_OUTPUT_INT] = diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 4f1b734c22..d1e4f0e811 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -195,7 +195,7 @@ static void bamboo_init(QEMUMachineInitArgs *args) env = &cpu->env; qemu_register_reset(main_cpu_reset, cpu); - ppc_booke_timers_init(env, 400000000, 0); + ppc_booke_timers_init(cpu, 400000000, 0); ppc_dcr_init(env, NULL, NULL); /* interrupt controller */ diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h index 2b96d47f36..59dba9e292 100644 --- a/hw/ppc4xx.h +++ b/hw/ppc4xx.h @@ -28,9 +28,9 @@ #include "pci/pci.h" /* PowerPC 4xx core initialization */ -CPUPPCState *ppc4xx_init (const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk); +PowerPCCPU *ppc4xx_init(const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk); /* PowerPC 4xx universal interrupt controller */ enum { diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index d1fb1576b0..5e491bc0b4 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -47,9 +47,9 @@ static void ppc4xx_reset(void *opaque) /*****************************************************************************/ /* Generic PowerPC 4xx processor instantiation */ -CPUPPCState *ppc4xx_init (const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk) +PowerPCCPU *ppc4xx_init(const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk) { PowerPCCPU *cpu; CPUPPCState *env; @@ -72,7 +72,7 @@ CPUPPCState *ppc4xx_init (const char *cpu_model, /* Register qemu callbacks */ qemu_register_reset(ppc4xx_reset, cpu); - return env; + return cpu; } /*****************************************************************************/ diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index 5c89fc313d..4483b8d292 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -71,17 +71,19 @@ struct booke_timer_t { uint32_t flags; }; -static void booke_update_irq(CPUPPCState *env) +static void booke_update_irq(PowerPCCPU *cpu) { - ppc_set_irq(env, PPC_INTERRUPT_DECR, + CPUPPCState *env = &cpu->env; + + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, (env->spr[SPR_BOOKE_TSR] & TSR_DIS && env->spr[SPR_BOOKE_TCR] & TCR_DIE)); - ppc_set_irq(env, PPC_INTERRUPT_WDT, + ppc_set_irq(cpu, PPC_INTERRUPT_WDT, (env->spr[SPR_BOOKE_TSR] & TSR_WIS && env->spr[SPR_BOOKE_TCR] & TCR_WIE)); - ppc_set_irq(env, PPC_INTERRUPT_FIT, + ppc_set_irq(cpu, PPC_INTERRUPT_FIT, (env->spr[SPR_BOOKE_TSR] & TSR_FIS && env->spr[SPR_BOOKE_TCR] & TCR_FIE)); } @@ -153,10 +155,11 @@ static void booke_update_fixed_timer(CPUPPCState *env, static void booke_decr_cb(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; env->spr[SPR_BOOKE_TSR] |= TSR_DIS; - booke_update_irq(env); + booke_update_irq(cpu); if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) { /* Auto Reload */ @@ -166,16 +169,16 @@ static void booke_decr_cb(void *opaque) static void booke_fit_cb(void *opaque) { - CPUPPCState *env; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env; booke_timer_t *booke_timer; - env = opaque; tb_env = env->tb_env; booke_timer = tb_env->opaque; env->spr[SPR_BOOKE_TSR] |= TSR_FIS; - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_fit_target(env, tb_env), @@ -185,17 +188,17 @@ static void booke_fit_cb(void *opaque) static void booke_wdt_cb(void *opaque) { - CPUPPCState *env; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env; booke_timer_t *booke_timer; - env = opaque; tb_env = env->tb_env; booke_timer = tb_env->opaque; /* TODO: There's lots of complicated stuff to do here */ - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_wdt_target(env, tb_env), @@ -205,19 +208,22 @@ static void booke_wdt_cb(void *opaque) void store_booke_tsr(CPUPPCState *env, target_ulong val) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->spr[SPR_BOOKE_TSR] &= ~val; - booke_update_irq(env); + booke_update_irq(cpu); } void store_booke_tcr(CPUPPCState *env, target_ulong val) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env = env->tb_env; booke_timer_t *booke_timer = tb_env->opaque; tb_env = env->tb_env; env->spr[SPR_BOOKE_TCR] = val; - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_fit_target(env, tb_env), @@ -231,7 +237,7 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) } -void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags) +void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) { ppc_tb_t *tb_env; booke_timer_t *booke_timer; @@ -239,16 +245,16 @@ void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags) tb_env = g_malloc0(sizeof(ppc_tb_t)); booke_timer = g_malloc0(sizeof(booke_timer_t)); - env->tb_env = tb_env; + cpu->env.tb_env = tb_env; tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED; tb_env->tb_freq = freq; tb_env->decr_freq = freq; tb_env->opaque = booke_timer; - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, env); + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu); booke_timer->fit_timer = - qemu_new_timer_ns(vm_clock, &booke_fit_cb, env); + qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); booke_timer->wdt_timer = - qemu_new_timer_ns(vm_clock, &booke_wdt_cb, env); + qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); } diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c new file mode 100644 index 0000000000..c73c713080 --- /dev/null +++ b/hw/qdev-properties-system.c @@ -0,0 +1,358 @@ +/* + * qdev property parsing and global properties + * (parts specific for qemu-system-*) + * + * This file is based on code from hw/qdev-properties.c from + * commit 074a86fccd185616469dfcdc0e157f438aebba18, + * Copyright (c) Gerd Hoffmann <kraxel@redhat.com> and other contributors. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "net/net.h" +#include "qdev.h" +#include "qapi/qmp/qerror.h" +#include "sysemu/blockdev.h" +#include "hw/block-common.h" +#include "net/hub.h" +#include "qapi/visitor.h" +#include "char/char.h" + +static void get_pointer(Object *obj, Visitor *v, Property *prop, + const char *(*print)(void *ptr), + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + void **ptr = qdev_get_prop_ptr(dev, prop); + char *p; + + p = (char *) (*ptr ? print(*ptr) : ""); + visit_type_str(v, &p, name, errp); +} + +static void set_pointer(Object *obj, Visitor *v, Property *prop, + int (*parse)(DeviceState *dev, const char *str, + void **ptr), + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Error *local_err = NULL; + void **ptr = qdev_get_prop_ptr(dev, prop); + char *str; + int ret; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (!*str) { + g_free(str); + *ptr = NULL; + return; + } + ret = parse(dev, str, ptr); + error_set_from_qdev_prop_error(errp, ret, dev, prop, str); + g_free(str); +} + +/* --- drive --- */ + +static int parse_drive(DeviceState *dev, const char *str, void **ptr) +{ + BlockDriverState *bs; + + bs = bdrv_find(str); + if (bs == NULL) { + return -ENOENT; + } + if (bdrv_attach_dev(bs, dev) < 0) { + return -EEXIST; + } + *ptr = bs; + return 0; +} + +static void release_drive(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + bdrv_detach_dev(*ptr, dev); + blockdev_auto_del(*ptr); + } +} + +static const char *print_drive(void *ptr) +{ + return bdrv_get_device_name(ptr); +} + +static void get_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_drive, name, errp); +} + +static void set_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_drive, name, errp); +} + +PropertyInfo qdev_prop_drive = { + .name = "drive", + .get = get_drive, + .set = set_drive, + .release = release_drive, +}; + +/* --- character device --- */ + +static int parse_chr(DeviceState *dev, const char *str, void **ptr) +{ + CharDriverState *chr = qemu_chr_find(str); + if (chr == NULL) { + return -ENOENT; + } + if (chr->avail_connections < 1) { + return -EEXIST; + } + *ptr = chr; + --chr->avail_connections; + return 0; +} + +static void release_chr(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); + } +} + + +static const char *print_chr(void *ptr) +{ + CharDriverState *chr = ptr; + + return chr->label ? chr->label : ""; +} + +static void get_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_chr, name, errp); +} + +static void set_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_chr, name, errp); +} + +PropertyInfo qdev_prop_chr = { + .name = "chr", + .get = get_chr, + .set = set_chr, + .release = release_chr, +}; + +/* --- netdev device --- */ + +static int parse_netdev(DeviceState *dev, const char *str, void **ptr) +{ + NetClientState *netdev = qemu_find_netdev(str); + + if (netdev == NULL) { + return -ENOENT; + } + if (netdev->peer) { + return -EEXIST; + } + *ptr = netdev; + return 0; +} + +static const char *print_netdev(void *ptr) +{ + NetClientState *netdev = ptr; + + return netdev->name ? netdev->name : ""; +} + +static void get_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_netdev, name, errp); +} + +static void set_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_netdev, name, errp); +} + +PropertyInfo qdev_prop_netdev = { + .name = "netdev", + .get = get_netdev, + .set = set_netdev, +}; + +/* --- vlan --- */ + +static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + int id; + if (!net_hub_id_for_client(*ptr, &id)) { + return snprintf(dest, len, "%d", id); + } + } + + return snprintf(dest, len, "<null>"); +} + +static void get_vlan(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + int32_t id = -1; + + if (*ptr) { + int hub_id; + if (!net_hub_id_for_client(*ptr, &hub_id)) { + id = hub_id; + } + } + + visit_type_int32(v, &id, name, errp); +} + +static void set_vlan(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + int32_t id; + NetClientState *hubport; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_int32(v, &id, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (id == -1) { + *ptr = NULL; + return; + } + + hubport = net_hub_port_find(id); + if (!hubport) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, + name, prop->info->name); + return; + } + *ptr = hubport; +} + +PropertyInfo qdev_prop_vlan = { + .name = "vlan", + .print = print_vlan, + .get = get_vlan, + .set = set_vlan, +}; + +int qdev_prop_set_drive(DeviceState *dev, const char *name, + BlockDriverState *value) +{ + Error *errp = NULL; + const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; + object_property_set_str(OBJECT(dev), bdrv_name, + name, &errp); + if (errp) { + qerror_report_err(errp); + error_free(errp); + return -1; + } + return 0; +} + +void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, + BlockDriverState *value) +{ + if (qdev_prop_set_drive(dev, name, value) < 0) { + exit(1); + } +} +void qdev_prop_set_chr(DeviceState *dev, const char *name, + CharDriverState *value) +{ + Error *errp = NULL; + assert(!value || value->label); + object_property_set_str(OBJECT(dev), + value ? value->label : "", name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_netdev(DeviceState *dev, const char *name, + NetClientState *value) +{ + Error *errp = NULL; + assert(!value || value->name); + object_property_set_str(OBJECT(dev), + value ? value->name : "", name, &errp); + assert_no_error(errp); +} + +void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) +{ + qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); + if (nd->netdev) { + qdev_prop_set_netdev(dev, "netdev", nd->netdev); + } + if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && + object_property_find(OBJECT(dev), "vectors", NULL)) { + qdev_prop_set_uint32(dev, "vectors", nd->nvectors); + } + nd->instantiated = 1; +} + +static int qdev_add_one_global(QemuOpts *opts, void *opaque) +{ + GlobalProperty *g; + + g = g_malloc0(sizeof(*g)); + g->driver = qemu_opt_get(opts, "driver"); + g->property = qemu_opt_get(opts, "property"); + g->value = qemu_opt_get(opts, "value"); + qdev_prop_register_global(g); + return 0; +} + +void qemu_add_globals(void) +{ + qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); +} diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 04d605dd37..f724357ccb 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -14,49 +14,6 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) return ptr; } -static void get_pointer(Object *obj, Visitor *v, Property *prop, - const char *(*print)(void *ptr), - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - void **ptr = qdev_get_prop_ptr(dev, prop); - char *p; - - p = (char *) (*ptr ? print(*ptr) : ""); - visit_type_str(v, &p, name, errp); -} - -static void set_pointer(Object *obj, Visitor *v, Property *prop, - int (*parse)(DeviceState *dev, const char *str, - void **ptr), - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Error *local_err = NULL; - void **ptr = qdev_get_prop_ptr(dev, prop); - char *str; - int ret; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_str(v, &str, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (!*str) { - g_free(str); - *ptr = NULL; - return; - } - ret = parse(dev, str, ptr); - error_set_from_qdev_prop_error(errp, ret, dev, prop, str); - g_free(str); -} - static void get_enum(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -96,10 +53,11 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) { uint32_t *p = qdev_get_prop_ptr(dev, props); uint32_t mask = qdev_get_prop_mask(props); - if (val) + if (val) { *p |= mask; - else + } else { *p &= ~mask; + } } static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) @@ -421,11 +379,13 @@ static void release_string(Object *obj, const char *name, void *opaque) g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); } -static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) +static int print_string(DeviceState *dev, Property *prop, char *dest, + size_t len) { char **ptr = qdev_get_prop_ptr(dev, prop); - if (!*ptr) + if (!*ptr) { return snprintf(dest, len, "<null>"); + } return snprintf(dest, len, "\"%s\"", *ptr); } @@ -477,227 +437,6 @@ PropertyInfo qdev_prop_string = { .set = set_string, }; -/* --- drive --- */ - -static int parse_drive(DeviceState *dev, const char *str, void **ptr) -{ - BlockDriverState *bs; - - bs = bdrv_find(str); - if (bs == NULL) - return -ENOENT; - if (bdrv_attach_dev(bs, dev) < 0) - return -EEXIST; - *ptr = bs; - return 0; -} - -static void release_drive(Object *obj, const char *name, void *opaque) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - bdrv_detach_dev(*ptr, dev); - blockdev_auto_del(*ptr); - } -} - -static const char *print_drive(void *ptr) -{ - return bdrv_get_device_name(ptr); -} - -static void get_drive(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_drive, name, errp); -} - -static void set_drive(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_drive, name, errp); -} - -PropertyInfo qdev_prop_drive = { - .name = "drive", - .get = get_drive, - .set = set_drive, - .release = release_drive, -}; - -/* --- character device --- */ - -static int parse_chr(DeviceState *dev, const char *str, void **ptr) -{ - CharDriverState *chr = qemu_chr_find(str); - if (chr == NULL) { - return -ENOENT; - } - if (chr->avail_connections < 1) { - return -EEXIST; - } - *ptr = chr; - --chr->avail_connections; - return 0; -} - -static void release_chr(Object *obj, const char *name, void *opaque) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); - } -} - - -static const char *print_chr(void *ptr) -{ - CharDriverState *chr = ptr; - - return chr->label ? chr->label : ""; -} - -static void get_chr(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_chr, name, errp); -} - -static void set_chr(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_chr, name, errp); -} - -PropertyInfo qdev_prop_chr = { - .name = "chr", - .get = get_chr, - .set = set_chr, - .release = release_chr, -}; - -/* --- netdev device --- */ - -static int parse_netdev(DeviceState *dev, const char *str, void **ptr) -{ - NetClientState *netdev = qemu_find_netdev(str); - - if (netdev == NULL) { - return -ENOENT; - } - if (netdev->peer) { - return -EEXIST; - } - *ptr = netdev; - return 0; -} - -static const char *print_netdev(void *ptr) -{ - NetClientState *netdev = ptr; - - return netdev->name ? netdev->name : ""; -} - -static void get_netdev(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_netdev, name, errp); -} - -static void set_netdev(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_netdev, name, errp); -} - -PropertyInfo qdev_prop_netdev = { - .name = "netdev", - .get = get_netdev, - .set = set_netdev, -}; - -/* --- vlan --- */ - -static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - int id; - if (!net_hub_id_for_client(*ptr, &id)) { - return snprintf(dest, len, "%d", id); - } - } - - return snprintf(dest, len, "<null>"); -} - -static void get_vlan(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - int32_t id = -1; - - if (*ptr) { - int hub_id; - if (!net_hub_id_for_client(*ptr, &hub_id)) { - id = hub_id; - } - } - - visit_type_int32(v, &id, name, errp); -} - -static void set_vlan(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int32_t id; - NetClientState *hubport; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_int32(v, &id, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (id == -1) { - *ptr = NULL; - return; - } - - hubport = net_hub_port_find(id); - if (!hubport) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, - name, prop->info->name); - return; - } - *ptr = hubport; -} - -PropertyInfo qdev_prop_vlan = { - .name = "vlan", - .print = print_vlan, - .get = get_vlan, - .set = set_vlan, -}; - /* --- pointer --- */ /* Not a proper property, just for dirty hacks. TODO Remove it! */ @@ -750,16 +489,20 @@ static void set_mac(Object *obj, Visitor *v, void *opaque, } for (i = 0, pos = 0; i < 6; i++, pos += 3) { - if (!qemu_isxdigit(str[pos])) + if (!qemu_isxdigit(str[pos])) { goto inval; - if (!qemu_isxdigit(str[pos+1])) + } + if (!qemu_isxdigit(str[pos+1])) { goto inval; + } if (i == 5) { - if (str[pos+2] != '\0') + if (str[pos+2] != '\0') { goto inval; + } } else { - if (str[pos+2] != ':' && str[pos+2] != '-') + if (str[pos+2] != ':' && str[pos+2] != '-') { goto inval; + } } mac->a[i] = strtol(str+pos, &p, 16); } @@ -865,7 +608,8 @@ invalid: g_free(str); } -static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) +static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, + size_t len) { int32_t *ptr = qdev_get_prop_ptr(dev, prop); @@ -1039,11 +783,13 @@ PropertyInfo qdev_prop_pci_host_devaddr = { static Property *qdev_prop_walk(Property *props, const char *name) { - if (!props) + if (!props) { return NULL; + } while (props->name) { - if (strcmp(props->name, name) == 0) + if (strcmp(props->name, name) == 0) { return props; + } props++; } return NULL; @@ -1159,44 +905,6 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) assert_no_error(errp); } -int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) -{ - Error *errp = NULL; - const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; - object_property_set_str(OBJECT(dev), bdrv_name, - name, &errp); - if (errp) { - qerror_report_err(errp); - error_free(errp); - return -1; - } - return 0; -} - -void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value) -{ - if (qdev_prop_set_drive(dev, name, value) < 0) { - exit(1); - } -} -void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) -{ - Error *errp = NULL; - assert(!value || value->label); - object_property_set_str(OBJECT(dev), - value ? value->label : "", name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value) -{ - Error *errp = NULL; - assert(!value || value->name); - object_property_set_str(OBJECT(dev), - value ? value->name : "", name, &errp); - assert_no_error(errp); -} - void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) { Error *errp = NULL; @@ -1230,9 +938,10 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) *ptr = value; } -static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); +static QTAILQ_HEAD(, GlobalProperty) global_props = + QTAILQ_HEAD_INITIALIZER(global_props); -static void qdev_prop_register_global(GlobalProperty *prop) +void qdev_prop_register_global(GlobalProperty *prop) { QTAILQ_INSERT_TAIL(&global_props, prop, next); } @@ -1263,20 +972,3 @@ void qdev_prop_set_globals(DeviceState *dev) class = object_class_get_parent(class); } while (class); } - -static int qdev_add_one_global(QemuOpts *opts, void *opaque) -{ - GlobalProperty *g; - - g = g_malloc0(sizeof(*g)); - g->driver = qemu_opt_get(opts, "driver"); - g->property = qemu_opt_get(opts, "property"); - g->value = qemu_opt_get(opts, "value"); - qdev_prop_register_global(g); - return 0; -} - -void qemu_add_globals(void) -{ - qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); -} diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h index 5b046abb28..ddcf774506 100644 --- a/hw/qdev-properties.h +++ b/hw/qdev-properties.h @@ -116,6 +116,7 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); /* FIXME: Remove opaque pointer properties. */ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); +void qdev_prop_register_global(GlobalProperty *prop); void qdev_prop_register_global_list(GlobalProperty *props); void qdev_prop_set_globals(DeviceState *dev); void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, diff --git a/hw/qdev.c b/hw/qdev.c index c4a9857a05..f2c248451c 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -25,7 +25,6 @@ inherit from a particular bus (e.g. PCI or I2C) rather than this API directly. */ -#include "net/net.h" #include "qdev.h" #include "sysemu/sysemu.h" #include "qapi/error.h" @@ -312,18 +311,6 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) dev->gpio_out[n] = pin; } -void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) -{ - qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); - if (nd->netdev) - qdev_prop_set_netdev(dev, "netdev", nd->netdev); - if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && - object_property_find(OBJECT(dev), "vectors", NULL)) { - qdev_prop_set_uint32(dev, "vectors", nd->nvectors); - } - nd->instantiated = 1; -} - BusState *qdev_get_child_bus(DeviceState *dev, const char *name) { BusState *bus; diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 84fba9674c..7e991755b4 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -110,10 +110,12 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size) return bus; } -static void s390_virtio_irq(CPUS390XState *env, int config_change, uint64_t token) +static void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) { + CPUS390XState *env = &cpu->env; + if (kvm_enabled()) { - kvm_s390_virtio_irq(env, config_change, token); + kvm_s390_virtio_irq(cpu, config_change, token); } else { cpu_inject_ext(env, VIRTIO_EXT_CODE, config_change, token); } @@ -142,8 +144,7 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) s390_virtio_reset_idx(dev); if (dev->qdev.hotplugged) { S390CPU *cpu = s390_cpu_addr2state(0); - CPUS390XState *env = &cpu->env; - s390_virtio_irq(env, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); + s390_virtio_irq(cpu, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); } return 0; @@ -382,9 +383,8 @@ static void virtio_s390_notify(DeviceState *d, uint16_t vector) VirtIOS390Device *dev = to_virtio_s390_device_fast(d); uint64_t token = s390_virtio_device_vq_token(dev, vector); S390CPU *cpu = s390_cpu_addr2state(0); - CPUS390XState *env = &cpu->env; - s390_virtio_irq(env, 0, token); + s390_virtio_irq(cpu, 0, token); } static unsigned virtio_s390_get_features(DeviceState *d) diff --git a/hw/spapr.c b/hw/spapr.c index fdd1eb6925..b5e15b884a 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -798,7 +798,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) /* Tell KVM that we're in PAPR mode */ if (kvm_enabled()) { - kvmppc_set_papr(env); + kvmppc_set_papr(cpu); } qemu_register_reset(spapr_cpu_reset, cpu); diff --git a/hw/tmp105.c b/hw/tmp105.c index 8e8dbd94eb..9c67e644dd 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -20,6 +20,7 @@ #include "hw.h" #include "i2c.h" +#include "tmp105.h" typedef struct { I2CSlave i2c; @@ -92,22 +93,22 @@ static void tmp105_read(TMP105State *s) } switch (s->pointer & 3) { - case 0: /* Temperature */ + case TMP105_REG_TEMPERATURE: s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8); s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) & (0xf0 << ((~s->config >> 5) & 3)); /* R */ break; - case 1: /* Configuration */ + case TMP105_REG_CONFIG: s->buf[s->len ++] = s->config; break; - case 2: /* T_LOW */ + case TMP105_REG_T_LOW: s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8; s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0; break; - case 3: /* T_HIGH */ + case TMP105_REG_T_HIGH: s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8; s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0; break; @@ -117,10 +118,10 @@ static void tmp105_read(TMP105State *s) static void tmp105_write(TMP105State *s) { switch (s->pointer & 3) { - case 0: /* Temperature */ + case TMP105_REG_TEMPERATURE: break; - case 1: /* Configuration */ + case TMP105_REG_CONFIG: if (s->buf[0] & ~s->config & (1 << 0)) /* SD */ printf("%s: TMP105 shutdown\n", __FUNCTION__); s->config = s->buf[0]; @@ -128,8 +129,8 @@ static void tmp105_write(TMP105State *s) tmp105_alarm_update(s); break; - case 2: /* T_LOW */ - case 3: /* T_HIGH */ + case TMP105_REG_T_LOW: + case TMP105_REG_T_HIGH: if (s->len >= 3) s->limit[s->pointer & 1] = (int16_t) ((((uint16_t) s->buf[0]) << 8) | s->buf[1]); diff --git a/hw/tmp105.h b/hw/tmp105.h new file mode 100644 index 0000000000..51eff4be1c --- /dev/null +++ b/hw/tmp105.h @@ -0,0 +1,67 @@ +/* + * Texas Instruments TMP105 Temperature Sensor + * + * Browse the data sheet: + * + * http://www.ti.com/lit/gpn/tmp105 + * + * Copyright (C) 2012 Alex Horn <alex.horn@cs.ox.ac.uk> + * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ +#ifndef QEMU_TMP105_H +#define QEMU_TMP105_H + +#include "i2c.h" + +/** + * TMP105Reg: + * @TMP105_REG_TEMPERATURE: Temperature register + * @TMP105_REG_CONFIG: Configuration register + * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst) + * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS) + * + * The following temperature sensors are + * compatible with the TMP105 registers: + * - adt75 + * - ds1775 + * - ds75 + * - lm75 + * - lm75a + * - max6625 + * - max6626 + * - mcp980x + * - stds75 + * - tcn75 + * - tmp100 + * - tmp101 + * - tmp105 + * - tmp175 + * - tmp275 + * - tmp75 + **/ +typedef enum TMP105Reg { + TMP105_REG_TEMPERATURE = 0, + TMP105_REG_CONFIG, + TMP105_REG_T_LOW, + TMP105_REG_T_HIGH, +} TMP105Reg; + +/** + * tmp105_set: + * @i2c: dispatcher to TMP105 hardware model + * @temp: temperature with 0.001 centigrades units in the range -40 C to +125 C + * + * Sets the temperature of the TMP105 hardware model. + * + * Bits 5 and 6 (value 32 and 64) in the register indexed by TMP105_REG_CONFIG + * determine the precision of the temperature. See Table 8 in the data sheet. + * + * @see_also: I2C_SLAVE macro + * @see_also: http://www.ti.com/lit/gpn/tmp105 + */ +void tmp105_set(I2CSlave *i2c, int temp); + +#endif diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index b65e8682b6..0abe1ff4d1 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -30,6 +30,7 @@ #include "monitor/monitor.h" #include "sysemu/sysemu.h" #include "qemu/iov.h" +#include "char/char.h" #include <dirent.h> #include <sys/ioctl.h> diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index 5238c7cbd6..78450d7c40 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -93,7 +93,7 @@ static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size, } env = &cpu->env; - ppc_booke_timers_init(env, sysclk, 0/* no flags */); + ppc_booke_timers_init(cpu, sysclk, 0/* no flags */); ppc_dcr_init(env, NULL, NULL); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index c12e35f54d..439e88deb4 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -22,6 +22,7 @@ #include "qemu-common.h" #include "qemu/tls.h" #include "exec/cpu-common.h" +#include "qemu/thread.h" /* some important defines: * @@ -487,15 +488,23 @@ typedef struct RAMBlock { ram_addr_t length; uint32_t flags; char idstr[256]; - QLIST_ENTRY(RAMBlock) next; + /* Reads can take either the iothread or the ramlist lock. + * Writes must take both locks. + */ + QTAILQ_ENTRY(RAMBlock) next; #if defined(__linux__) && !defined(TARGET_S390X) int fd; #endif } RAMBlock; typedef struct RAMList { + QemuMutex mutex; + /* Protected by the iothread lock. */ uint8_t *phys_dirty; - QLIST_HEAD(, RAMBlock) blocks; + RAMBlock *mru_block; + /* Protected by the ramlist lock. */ + QTAILQ_HEAD(, RAMBlock) blocks; + uint32_t version; } RAMList; extern RAMList ram_list; @@ -514,6 +523,8 @@ extern int mem_prealloc; void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); ram_addr_t last_ram_offset(void); +void qemu_mutex_lock_ramlist(void); +void qemu_mutex_unlock_ramlist(void); #endif /* !CONFIG_USER_ONLY */ int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr, diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 4d4f8d4e98..2e5f11f47f 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -12,6 +12,18 @@ #include "qemu/bswap.h" #include "qemu/queue.h" +/** + * CPUListState: + * @cpu_fprintf: Print function. + * @file: File to print to using @cpu_fprint. + * + * State commonly used for iterating over CPU models. + */ +typedef struct CPUListState { + fprintf_function cpu_fprintf; + FILE *file; +} CPUListState; + #if !defined(CONFIG_USER_ONLY) enum device_endian { diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index aea0ece051..b22b4c6255 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -134,8 +134,6 @@ typedef struct icount_decr_u16 { } icount_decr_u16; #endif -struct kvm_run; -struct KVMState; struct qemu_work_item; typedef struct CPUBreakpoint { @@ -204,10 +202,6 @@ typedef struct CPUWatchpoint { /* user data */ \ void *opaque; \ \ - const char *cpu_model_str; \ - struct KVMState *kvm_state; \ - struct kvm_run *kvm_run; \ - int kvm_fd; \ - int kvm_vcpu_dirty; + const char *cpu_model_str; #endif diff --git a/include/exec/memory.h b/include/exec/memory.h index aada969628..2322732dce 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -454,6 +454,22 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr, hwaddr size); /** + * memory_region_test_and_clear_dirty: Check whether a range of bytes is dirty + * for a specified client. It clears them. + * + * Checks whether a range of bytes has been written to since the last + * call to memory_region_reset_dirty() with the same @client. Dirty logging + * must be enabled. + * + * @mr: the memory region being queried. + * @addr: the address (relative to the start of the region) being queried. + * @size: the size of the range being queried. + * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or + * %DIRTY_MEMORY_VGA. + */ +bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr, + hwaddr size, unsigned client); +/** * memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with * any external TLBs (e.g. kvm) * diff --git a/include/migration/migration.h b/include/migration/migration.h index 8b7af61e7e..2d5b630cce 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -16,6 +16,7 @@ #include "qapi/qmp/qdict.h" #include "qemu-common.h" +#include "qemu/thread.h" #include "qemu/notify.h" #include "qapi/error.h" #include "migration/vmstate.h" @@ -31,6 +32,13 @@ typedef struct MigrationState MigrationState; struct MigrationState { int64_t bandwidth_limit; + size_t bytes_xfer; + size_t xfer_limit; + uint8_t *buffer; + size_t buffer_size; + size_t buffer_capacity; + QemuThread thread; + QEMUFile *file; int fd; int state; @@ -45,6 +53,8 @@ struct MigrationState int64_t dirty_pages_rate; bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; + bool complete; + bool first_time; }; void process_incoming_migration(QEMUFile *f); @@ -79,8 +89,6 @@ void migrate_fd_connect(MigrationState *s); ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, size_t size); -void migrate_fd_put_ready(MigrationState *s); -int migrate_fd_wait_for_unfreeze(MigrationState *s); int migrate_fd_close(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); @@ -127,5 +135,4 @@ int migrate_use_xbzrle(void); int64_t migrate_xbzrle_cache_size(void); int64_t xbzrle_cache_resize(int64_t new_size); - #endif diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index d64bdbb19b..68deefbcfb 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -113,11 +113,6 @@ int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); int qemu_file_get_error(QEMUFile *f); -/* Try to send any outstanding data. This function is useful when output is - * halted due to rate limiting or EAGAIN errors occur as it can be used to - * resume output. */ -int qemu_file_put_notify(QEMUFile *f); - static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) { qemu_put_be64(f, *pv); diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 623af0a29a..f27276c2d8 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -35,6 +35,7 @@ typedef struct SaveVMHandlers { int (*save_live_setup)(QEMUFile *f, void *opaque); int (*save_live_iterate)(QEMUFile *f, void *opaque); int (*save_live_complete)(QEMUFile *f, void *opaque); + uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size); void (*cancel)(void *opaque); LoadStateHandler *load_state; bool (*is_active)(void *opaque); diff --git a/include/qemu/thread-posix.h b/include/qemu/thread-posix.h index 380bae209b..0f30dccb53 100644 --- a/include/qemu/thread-posix.h +++ b/include/qemu/thread-posix.h @@ -12,7 +12,7 @@ struct QemuCond { }; struct QemuSemaphore { -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_t lock; pthread_cond_t cond; int count; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 9e9d044bdf..3e9fc3aca5 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -52,11 +52,15 @@ typedef struct CPUClass { void (*reset)(CPUState *cpu); } CPUClass; +struct KVMState; +struct kvm_run; + /** * CPUState: * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. + * @kvm_fd: vCPU file descriptor for KVM. * * State of one CPU core or thread. */ @@ -77,6 +81,13 @@ struct CPUState { bool stop; bool stopped; +#if !defined(CONFIG_USER_ONLY) + int kvm_fd; + bool kvm_vcpu_dirty; +#endif + struct KVMState *kvm_state; + struct kvm_run *kvm_run; + /* TODO Move common fields from CPUArchState here. */ }; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 131d2bdc15..3db19ffdac 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -152,20 +152,20 @@ int kvm_ioctl(KVMState *s, int type, ...); int kvm_vm_ioctl(KVMState *s, int type, ...); -int kvm_vcpu_ioctl(CPUArchState *env, int type, ...); +int kvm_vcpu_ioctl(CPUState *cpu, int type, ...); /* Arch specific hooks */ extern const KVMCapabilityInfo kvm_arch_required_capabilities[]; -void kvm_arch_pre_run(CPUArchState *env, struct kvm_run *run); -void kvm_arch_post_run(CPUArchState *env, struct kvm_run *run); +void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run); +void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run); -int kvm_arch_handle_exit(CPUArchState *env, struct kvm_run *run); +int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run); -int kvm_arch_process_async_events(CPUArchState *env); +int kvm_arch_process_async_events(CPUState *cpu); -int kvm_arch_get_registers(CPUArchState *env); +int kvm_arch_get_registers(CPUState *cpu); /* state subset only touched by the VCPU itself during runtime */ #define KVM_PUT_RUNTIME_STATE 1 @@ -174,15 +174,15 @@ int kvm_arch_get_registers(CPUArchState *env); /* full state set, modified during initialization or on vmload */ #define KVM_PUT_FULL_STATE 3 -int kvm_arch_put_registers(CPUArchState *env, int level); +int kvm_arch_put_registers(CPUState *cpu, int level); int kvm_arch_init(KVMState *s); -int kvm_arch_init_vcpu(CPUArchState *env); +int kvm_arch_init_vcpu(CPUState *cpu); -void kvm_arch_reset_vcpu(CPUArchState *env); +void kvm_arch_reset_vcpu(CPUState *cpu); -int kvm_arch_on_sigbus_vcpu(CPUArchState *env, int code, void *addr); +int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); int kvm_arch_on_sigbus(int code, void *addr); void kvm_arch_init_irq_routing(KVMState *s); @@ -207,14 +207,14 @@ struct kvm_sw_breakpoint { QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint); -struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, +struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, target_ulong pc); -int kvm_sw_breakpoints_active(CPUArchState *env); +int kvm_sw_breakpoints_active(CPUState *cpu); -int kvm_arch_insert_sw_breakpoint(CPUArchState *current_env, +int kvm_arch_insert_sw_breakpoint(CPUState *current_cpu, struct kvm_sw_breakpoint *bp); -int kvm_arch_remove_sw_breakpoint(CPUArchState *current_env, +int kvm_arch_remove_sw_breakpoint(CPUState *current_cpu, struct kvm_sw_breakpoint *bp); int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type); @@ -222,9 +222,9 @@ int kvm_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type); void kvm_arch_remove_all_hw_breakpoints(void); -void kvm_arch_update_guest_debug(CPUArchState *env, struct kvm_guest_debug *dbg); +void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg); -bool kvm_arch_stop_on_emulation_error(CPUArchState *env); +bool kvm_arch_stop_on_emulation_error(CPUState *cpu); int kvm_check_extension(KVMState *s, unsigned int extension); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 8eaa4707a0..28a783e2be 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -78,6 +78,7 @@ int qemu_savevm_state_begin(QEMUFile *f, int qemu_savevm_state_iterate(QEMUFile *f); int qemu_savevm_state_complete(QEMUFile *f); void qemu_savevm_state_cancel(QEMUFile *f); +uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size); int qemu_loadvm_state(QEMUFile *f); /* SLIRP */ diff --git a/kvm-all.c b/kvm-all.c index 5aa65c4c15..fc0c6e7798 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -209,13 +209,14 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) static void kvm_reset_vcpu(void *opaque) { - CPUArchState *env = opaque; + CPUState *cpu = opaque; - kvm_arch_reset_vcpu(env); + kvm_arch_reset_vcpu(cpu); } int kvm_init_vcpu(CPUArchState *env) { + CPUState *cpu = ENV_GET_CPU(env); KVMState *s = kvm_state; long mmap_size; int ret; @@ -228,9 +229,9 @@ int kvm_init_vcpu(CPUArchState *env) goto err; } - env->kvm_fd = ret; - env->kvm_state = s; - env->kvm_vcpu_dirty = 1; + cpu->kvm_fd = ret; + cpu->kvm_state = s; + cpu->kvm_vcpu_dirty = true; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); if (mmap_size < 0) { @@ -239,9 +240,9 @@ int kvm_init_vcpu(CPUArchState *env) goto err; } - env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, - env->kvm_fd, 0); - if (env->kvm_run == MAP_FAILED) { + cpu->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, + cpu->kvm_fd, 0); + if (cpu->kvm_run == MAP_FAILED) { ret = -errno; DPRINTF("mmap'ing vcpu state failed\n"); goto err; @@ -249,13 +250,13 @@ int kvm_init_vcpu(CPUArchState *env) if (s->coalesced_mmio && !s->coalesced_mmio_ring) { s->coalesced_mmio_ring = - (void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE; + (void *)cpu->kvm_run + s->coalesced_mmio * PAGE_SIZE; } - ret = kvm_arch_init_vcpu(env); + ret = kvm_arch_init_vcpu(cpu); if (ret == 0) { - qemu_register_reset(kvm_reset_vcpu, env); - kvm_arch_reset_vcpu(env); + qemu_register_reset(kvm_reset_vcpu, cpu); + kvm_arch_reset_vcpu(cpu); } err: return ret; @@ -1435,6 +1436,8 @@ static void kvm_handle_io(uint16_t port, void *data, int direction, int size, static int kvm_handle_internal_error(CPUArchState *env, struct kvm_run *run) { + CPUState *cpu = ENV_GET_CPU(env); + fprintf(stderr, "KVM internal error."); if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) { int i; @@ -1449,7 +1452,7 @@ static int kvm_handle_internal_error(CPUArchState *env, struct kvm_run *run) } if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) { fprintf(stderr, "emulation failure\n"); - if (!kvm_arch_stop_on_emulation_error(env)) { + if (!kvm_arch_stop_on_emulation_error(cpu)) { cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); return EXCP_INTERRUPT; } @@ -1486,13 +1489,13 @@ void kvm_flush_coalesced_mmio_buffer(void) s->coalesced_flush_in_progress = false; } -static void do_kvm_cpu_synchronize_state(void *_env) +static void do_kvm_cpu_synchronize_state(void *arg) { - CPUArchState *env = _env; + CPUState *cpu = arg; - if (!env->kvm_vcpu_dirty) { - kvm_arch_get_registers(env); - env->kvm_vcpu_dirty = 1; + if (!cpu->kvm_vcpu_dirty) { + kvm_arch_get_registers(cpu); + cpu->kvm_vcpu_dirty = true; } } @@ -1500,42 +1503,47 @@ void kvm_cpu_synchronize_state(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); - if (!env->kvm_vcpu_dirty) { - run_on_cpu(cpu, do_kvm_cpu_synchronize_state, env); + if (!cpu->kvm_vcpu_dirty) { + run_on_cpu(cpu, do_kvm_cpu_synchronize_state, cpu); } } void kvm_cpu_synchronize_post_reset(CPUArchState *env) { - kvm_arch_put_registers(env, KVM_PUT_RESET_STATE); - env->kvm_vcpu_dirty = 0; + CPUState *cpu = ENV_GET_CPU(env); + + kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); + cpu->kvm_vcpu_dirty = false; } void kvm_cpu_synchronize_post_init(CPUArchState *env) { - kvm_arch_put_registers(env, KVM_PUT_FULL_STATE); - env->kvm_vcpu_dirty = 0; + CPUState *cpu = ENV_GET_CPU(env); + + kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); + cpu->kvm_vcpu_dirty = false; } int kvm_cpu_exec(CPUArchState *env) { - struct kvm_run *run = env->kvm_run; + CPUState *cpu = ENV_GET_CPU(env); + struct kvm_run *run = cpu->kvm_run; int ret, run_ret; DPRINTF("kvm_cpu_exec()\n"); - if (kvm_arch_process_async_events(env)) { + if (kvm_arch_process_async_events(cpu)) { env->exit_request = 0; return EXCP_HLT; } do { - if (env->kvm_vcpu_dirty) { - kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE); - env->kvm_vcpu_dirty = 0; + if (cpu->kvm_vcpu_dirty) { + kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE); + cpu->kvm_vcpu_dirty = false; } - kvm_arch_pre_run(env, run); + kvm_arch_pre_run(cpu, run); if (env->exit_request) { DPRINTF("interrupt exit requested\n"); /* @@ -1547,10 +1555,10 @@ int kvm_cpu_exec(CPUArchState *env) } qemu_mutex_unlock_iothread(); - run_ret = kvm_vcpu_ioctl(env, KVM_RUN, 0); + run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0); qemu_mutex_lock_iothread(); - kvm_arch_post_run(env, run); + kvm_arch_post_run(cpu, run); if (run_ret < 0) { if (run_ret == -EINTR || run_ret == -EAGAIN) { @@ -1600,7 +1608,7 @@ int kvm_cpu_exec(CPUArchState *env) break; default: DPRINTF("kvm_arch_handle_exit\n"); - ret = kvm_arch_handle_exit(env, run); + ret = kvm_arch_handle_exit(cpu, run); break; } } while (ret == 0); @@ -1648,7 +1656,7 @@ int kvm_vm_ioctl(KVMState *s, int type, ...) return ret; } -int kvm_vcpu_ioctl(CPUArchState *env, int type, ...) +int kvm_vcpu_ioctl(CPUState *cpu, int type, ...) { int ret; void *arg; @@ -1658,7 +1666,7 @@ int kvm_vcpu_ioctl(CPUArchState *env, int type, ...) arg = va_arg(ap, void *); va_end(ap); - ret = ioctl(env->kvm_fd, type, arg); + ret = ioctl(cpu->kvm_fd, type, arg); if (ret == -1) { ret = -errno; } @@ -1753,12 +1761,12 @@ void kvm_setup_guest_memory(void *start, size_t size) } #ifdef KVM_CAP_SET_GUEST_DEBUG -struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, +struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, target_ulong pc) { struct kvm_sw_breakpoint *bp; - QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) { + QTAILQ_FOREACH(bp, &cpu->kvm_state->kvm_sw_breakpoints, entry) { if (bp->pc == pc) { return bp; } @@ -1766,23 +1774,23 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, return NULL; } -int kvm_sw_breakpoints_active(CPUArchState *env) +int kvm_sw_breakpoints_active(CPUState *cpu) { - return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints); + return !QTAILQ_EMPTY(&cpu->kvm_state->kvm_sw_breakpoints); } struct kvm_set_guest_debug_data { struct kvm_guest_debug dbg; - CPUArchState *env; + CPUState *cpu; int err; }; static void kvm_invoke_set_guest_debug(void *data) { struct kvm_set_guest_debug_data *dbg_data = data; - CPUArchState *env = dbg_data->env; - dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); + dbg_data->err = kvm_vcpu_ioctl(dbg_data->cpu, KVM_SET_GUEST_DEBUG, + &dbg_data->dbg); } int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) @@ -1795,8 +1803,8 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) if (env->singlestep_enabled) { data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; } - kvm_arch_update_guest_debug(env, &data.dbg); - data.env = env; + kvm_arch_update_guest_debug(cpu, &data.dbg); + data.cpu = cpu; run_on_cpu(cpu, kvm_invoke_set_guest_debug, &data); return data.err; @@ -1805,12 +1813,13 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, target_ulong len, int type) { + CPUState *current_cpu = ENV_GET_CPU(current_env); struct kvm_sw_breakpoint *bp; CPUArchState *env; int err; if (type == GDB_BREAKPOINT_SW) { - bp = kvm_find_sw_breakpoint(current_env, addr); + bp = kvm_find_sw_breakpoint(current_cpu, addr); if (bp) { bp->use_count++; return 0; @@ -1823,13 +1832,13 @@ int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, bp->pc = addr; bp->use_count = 1; - err = kvm_arch_insert_sw_breakpoint(current_env, bp); + err = kvm_arch_insert_sw_breakpoint(current_cpu, bp); if (err) { g_free(bp); return err; } - QTAILQ_INSERT_HEAD(¤t_env->kvm_state->kvm_sw_breakpoints, + QTAILQ_INSERT_HEAD(¤t_cpu->kvm_state->kvm_sw_breakpoints, bp, entry); } else { err = kvm_arch_insert_hw_breakpoint(addr, len, type); @@ -1850,12 +1859,13 @@ int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, target_ulong len, int type) { + CPUState *current_cpu = ENV_GET_CPU(current_env); struct kvm_sw_breakpoint *bp; CPUArchState *env; int err; if (type == GDB_BREAKPOINT_SW) { - bp = kvm_find_sw_breakpoint(current_env, addr); + bp = kvm_find_sw_breakpoint(current_cpu, addr); if (!bp) { return -ENOENT; } @@ -1865,12 +1875,12 @@ int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, return 0; } - err = kvm_arch_remove_sw_breakpoint(current_env, bp); + err = kvm_arch_remove_sw_breakpoint(current_cpu, bp); if (err) { return err; } - QTAILQ_REMOVE(¤t_env->kvm_state->kvm_sw_breakpoints, bp, entry); + QTAILQ_REMOVE(¤t_cpu->kvm_state->kvm_sw_breakpoints, bp, entry); g_free(bp); } else { err = kvm_arch_remove_hw_breakpoint(addr, len, type); @@ -1890,15 +1900,18 @@ int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, void kvm_remove_all_breakpoints(CPUArchState *current_env) { + CPUState *current_cpu = ENV_GET_CPU(current_env); struct kvm_sw_breakpoint *bp, *next; - KVMState *s = current_env->kvm_state; + KVMState *s = current_cpu->kvm_state; CPUArchState *env; + CPUState *cpu; QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) { - if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) { + if (kvm_arch_remove_sw_breakpoint(current_cpu, bp) != 0) { /* Try harder to find a CPU that currently sees the breakpoint. */ for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (kvm_arch_remove_sw_breakpoint(env, bp) == 0) { + cpu = ENV_GET_CPU(env); + if (kvm_arch_remove_sw_breakpoint(cpu, bp) == 0) { break; } } @@ -1939,18 +1952,19 @@ void kvm_remove_all_breakpoints(CPUArchState *current_env) int kvm_set_signal_mask(CPUArchState *env, const sigset_t *sigset) { + CPUState *cpu = ENV_GET_CPU(env); struct kvm_signal_mask *sigmask; int r; if (!sigset) { - return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL); + return kvm_vcpu_ioctl(cpu, KVM_SET_SIGNAL_MASK, NULL); } sigmask = g_malloc(sizeof(*sigmask) + sizeof(*sigset)); sigmask->len = 8; memcpy(sigmask->sigset, sigset, sizeof(*sigset)); - r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask); + r = kvm_vcpu_ioctl(cpu, KVM_SET_SIGNAL_MASK, sigmask); g_free(sigmask); return r; @@ -2010,7 +2024,8 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign) int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr) { - return kvm_arch_on_sigbus_vcpu(env, code, addr); + CPUState *cpu = ENV_GET_CPU(env); + return kvm_arch_on_sigbus_vcpu(cpu, code, addr); } int kvm_on_sigbus(int code, void *addr) diff --git a/memory.c b/memory.c index 35e6122dd7..410c5f80b4 100644 --- a/memory.c +++ b/memory.c @@ -1081,6 +1081,22 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr, return cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size, -1); } +bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr, + hwaddr size, unsigned client) +{ + bool ret; + assert(mr->terminates); + ret = cpu_physical_memory_get_dirty(mr->ram_addr + addr, size, + 1 << client); + if (ret) { + cpu_physical_memory_reset_dirty(mr->ram_addr + addr, + mr->ram_addr + addr + size, + 1 << client); + } + return ret; +} + + void memory_region_sync_dirty_bitmap(MemoryRegion *mr) { AddressSpace *as; diff --git a/memory_mapping.c b/memory_mapping.c index 530f1d6793..ff45b3a239 100644 --- a/memory_mapping.c +++ b/memory_mapping.c @@ -200,7 +200,7 @@ int qemu_get_guest_memory_mapping(MemoryMappingList *list) * If the guest doesn't use paging, the virtual address is equal to physical * address. */ - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { offset = block->offset; length = block->length; create_new_memory_mapping(list, offset, offset, length); @@ -213,7 +213,7 @@ void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list) { RAMBlock *block; - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { create_new_memory_mapping(list, block->offset, 0, block->length); } } diff --git a/migration-exec.c b/migration-exec.c index 68f36f41f1..a051a6e668 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -18,7 +18,7 @@ #include "qemu-common.h" #include "qemu/sockets.h" #include "migration/migration.h" -#include "buffered_file.h" +#include "migration/qemu-file.h" #include "block/block.h" #include <sys/types.h> #include <sys/wait.h> @@ -69,7 +69,6 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error s->fd = fileno(f); assert(s->fd != -1); - socket_set_nonblock(s->fd); s->opaque = qemu_popen(f, "w"); diff --git a/migration-fd.c b/migration-fd.c index ea121bc0d6..a99e0e3971 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -17,9 +17,8 @@ #include "qemu/sockets.h" #include "migration/migration.h" #include "monitor/monitor.h" -#include "buffered_file.h" +#include "migration/qemu-file.h" #include "block/block.h" -#include "qemu/sockets.h" //#define DEBUG_MIGRATION_FD @@ -76,7 +75,6 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error ** return; } - fcntl(s->fd, F_SETFL, O_NONBLOCK); s->get_error = fd_errno; s->write = fd_write; s->close = fd_close; diff --git a/migration-tcp.c b/migration-tcp.c index 3c4c315052..e78a296137 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -16,7 +16,7 @@ #include "qemu-common.h" #include "qemu/sockets.h" #include "migration/migration.h" -#include "buffered_file.h" +#include "migration/qemu-file.h" #include "block/block.h" //#define DEBUG_MIGRATION_TCP @@ -60,6 +60,7 @@ static void tcp_wait_for_connect(int fd, void *opaque) } else { DPRINTF("migrate connect success\n"); s->fd = fd; + socket_set_block(s->fd); migrate_fd_connect(s); } } diff --git a/migration-unix.c b/migration-unix.c index d5f986853f..218835a7a4 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -16,7 +16,7 @@ #include "qemu-common.h" #include "qemu/sockets.h" #include "migration/migration.h" -#include "buffered_file.h" +#include "migration/qemu-file.h" #include "block/block.h" //#define DEBUG_MIGRATION_UNIX @@ -60,6 +60,7 @@ static void unix_wait_for_connect(int fd, void *opaque) } else { DPRINTF("migrate connect success\n"); s->fd = fd; + socket_set_block(s->fd); migrate_fd_connect(s); } } diff --git a/migration.c b/migration.c index 810f25e7eb..c69e864fcd 100644 --- a/migration.c +++ b/migration.c @@ -16,11 +16,12 @@ #include "qemu-common.h" #include "migration/migration.h" #include "monitor/monitor.h" -#include "buffered_file.h" +#include "migration/qemu-file.h" #include "sysemu/sysemu.h" #include "block/block.h" #include "qemu/sockets.h" #include "migration/block.h" +#include "qemu/thread.h" #include "qmp-commands.h" //#define DEBUG_MIGRATION @@ -43,6 +44,11 @@ enum { #define MAX_THROTTLE (32 << 20) /* Migration speed throttling */ +/* Amount of time to allocate to each "chunk" of bandwidth-throttled + * data. */ +#define BUFFER_DELAY 100 +#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY) + /* Migration XBZRLE default cache size */ #define DEFAULT_MIGRATE_CACHE_SIZE (64 * 1024 * 1024) @@ -272,7 +278,7 @@ static int migrate_fd_cleanup(MigrationState *s) s->file = NULL; } - migrate_fd_close(s); + assert(s->fd == -1); return ret; } @@ -296,18 +302,6 @@ static void migrate_fd_completed(MigrationState *s) notifier_list_notify(&migration_state_notifiers, s); } -static void migrate_fd_put_notify(void *opaque) -{ - MigrationState *s = opaque; - int ret; - - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); - ret = qemu_file_put_notify(s->file); - if (ret) { - migrate_fd_error(s); - } -} - ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, size_t size) { @@ -324,51 +318,9 @@ ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, if (ret == -1) ret = -(s->get_error(s)); - if (ret == -EAGAIN) { - qemu_set_fd_handler2(s->fd, NULL, NULL, migrate_fd_put_notify, s); - } - return ret; } -void migrate_fd_put_ready(MigrationState *s) -{ - int ret; - - if (s->state != MIG_STATE_ACTIVE) { - DPRINTF("put_ready returning because of non-active state\n"); - return; - } - - DPRINTF("iterate\n"); - ret = qemu_savevm_state_iterate(s->file); - if (ret < 0) { - migrate_fd_error(s); - } else if (ret == 1) { - int old_vm_running = runstate_is_running(); - int64_t start_time, end_time; - - DPRINTF("done iterating\n"); - start_time = qemu_get_clock_ms(rt_clock); - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - - if (qemu_savevm_state_complete(s->file) < 0) { - migrate_fd_error(s); - } else { - migrate_fd_completed(s); - } - end_time = qemu_get_clock_ms(rt_clock); - s->total_time = end_time - s->total_time; - s->downtime = end_time - start_time; - if (s->state != MIG_STATE_COMPLETED) { - if (old_vm_running) { - vm_start(); - } - } - } -} - static void migrate_fd_cancel(MigrationState *s) { if (s->state != MIG_STATE_ACTIVE) @@ -383,34 +335,10 @@ static void migrate_fd_cancel(MigrationState *s) migrate_fd_cleanup(s); } -int migrate_fd_wait_for_unfreeze(MigrationState *s) -{ - int ret; - - DPRINTF("wait for unfreeze\n"); - if (s->state != MIG_STATE_ACTIVE) - return -EINVAL; - - do { - fd_set wfds; - - FD_ZERO(&wfds); - FD_SET(s->fd, &wfds); - - ret = select(s->fd + 1, NULL, &wfds, NULL, NULL); - } while (ret == -1 && (s->get_error(s)) == EINTR); - - if (ret == -1) { - return -s->get_error(s); - } - return 0; -} - int migrate_fd_close(MigrationState *s) { int rc = 0; if (s->fd != -1) { - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); rc = s->close(s); s->fd = -1; } @@ -443,23 +371,6 @@ bool migration_has_failed(MigrationState *s) s->state == MIG_STATE_ERROR); } -void migrate_fd_connect(MigrationState *s) -{ - int ret; - - s->state = MIG_STATE_ACTIVE; - s->file = qemu_fopen_ops_buffered(s); - - DPRINTF("beginning savevm\n"); - ret = qemu_savevm_state_begin(s->file, &s->params); - if (ret < 0) { - DPRINTF("failed, %d\n", ret); - migrate_fd_error(s); - return; - } - migrate_fd_put_ready(s); -} - static MigrationState *migrate_init(const MigrationParams *params) { MigrationState *s = migrate_get_current(); @@ -544,8 +455,6 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, error_propagate(errp, local_err); return; } - - notifier_list_notify(&migration_state_notifiers, s); } void qmp_migrate_cancel(Error **errp) @@ -609,3 +518,286 @@ int64_t migrate_xbzrle_cache_size(void) return s->xbzrle_cache_size; } + +/* migration thread support */ + + +static ssize_t buffered_flush(MigrationState *s) +{ + size_t offset = 0; + ssize_t ret = 0; + + DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); + + while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { + size_t to_send = MIN(s->buffer_size - offset, s->xfer_limit - s->bytes_xfer); + ret = migrate_fd_put_buffer(s, s->buffer + offset, to_send); + if (ret <= 0) { + DPRINTF("error flushing data, %zd\n", ret); + break; + } else { + DPRINTF("flushed %zd byte(s)\n", ret); + offset += ret; + s->bytes_xfer += ret; + } + } + + DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size); + memmove(s->buffer, s->buffer + offset, s->buffer_size - offset); + s->buffer_size -= offset; + + if (ret < 0) { + return ret; + } + return offset; +} + +static int buffered_put_buffer(void *opaque, const uint8_t *buf, + int64_t pos, int size) +{ + MigrationState *s = opaque; + ssize_t error; + + DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); + + error = qemu_file_get_error(s->file); + if (error) { + DPRINTF("flush when error, bailing: %s\n", strerror(-error)); + return error; + } + + if (size <= 0) { + return size; + } + + if (size > (s->buffer_capacity - s->buffer_size)) { + DPRINTF("increasing buffer capacity from %zu by %zu\n", + s->buffer_capacity, size + 1024); + + s->buffer_capacity += size + 1024; + + s->buffer = g_realloc(s->buffer, s->buffer_capacity); + } + + memcpy(s->buffer + s->buffer_size, buf, size); + s->buffer_size += size; + + return size; +} + +static int buffered_close(void *opaque) +{ + MigrationState *s = opaque; + ssize_t ret = 0; + int ret2; + + DPRINTF("closing\n"); + + s->xfer_limit = INT_MAX; + while (!qemu_file_get_error(s->file) && s->buffer_size) { + ret = buffered_flush(s); + if (ret < 0) { + break; + } + } + + ret2 = migrate_fd_close(s); + if (ret >= 0) { + ret = ret2; + } + ret = migrate_fd_close(s); + s->complete = true; + return ret; +} + +static int buffered_get_fd(void *opaque) +{ + MigrationState *s = opaque; + + return s->fd; +} + +/* + * The meaning of the return values is: + * 0: We can continue sending + * 1: Time to stop + * negative: There has been an error + */ +static int buffered_rate_limit(void *opaque) +{ + MigrationState *s = opaque; + int ret; + + ret = qemu_file_get_error(s->file); + if (ret) { + return ret; + } + + if (s->bytes_xfer > s->xfer_limit) { + return 1; + } + + return 0; +} + +static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate) +{ + MigrationState *s = opaque; + if (qemu_file_get_error(s->file)) { + goto out; + } + if (new_rate > SIZE_MAX) { + new_rate = SIZE_MAX; + } + + s->xfer_limit = new_rate / 10; + +out: + return s->xfer_limit; +} + +static int64_t buffered_get_rate_limit(void *opaque) +{ + MigrationState *s = opaque; + + return s->xfer_limit; +} + +static bool migrate_fd_put_ready(MigrationState *s, uint64_t max_size) +{ + int ret; + uint64_t pending_size; + bool last_round = false; + + qemu_mutex_lock_iothread(); + if (s->state != MIG_STATE_ACTIVE) { + DPRINTF("put_ready returning because of non-active state\n"); + qemu_mutex_unlock_iothread(); + return false; + } + if (s->first_time) { + s->first_time = false; + DPRINTF("beginning savevm\n"); + ret = qemu_savevm_state_begin(s->file, &s->params); + if (ret < 0) { + DPRINTF("failed, %d\n", ret); + migrate_fd_error(s); + qemu_mutex_unlock_iothread(); + return false; + } + } + + DPRINTF("iterate\n"); + pending_size = qemu_savevm_state_pending(s->file, max_size); + DPRINTF("pending size %lu max %lu\n", pending_size, max_size); + if (pending_size >= max_size) { + ret = qemu_savevm_state_iterate(s->file); + if (ret < 0) { + migrate_fd_error(s); + } + } else { + int old_vm_running = runstate_is_running(); + int64_t start_time, end_time; + + DPRINTF("done iterating\n"); + start_time = qemu_get_clock_ms(rt_clock); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + if (old_vm_running) { + vm_stop(RUN_STATE_FINISH_MIGRATE); + } else { + vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + } + + if (qemu_savevm_state_complete(s->file) < 0) { + migrate_fd_error(s); + } else { + migrate_fd_completed(s); + } + end_time = qemu_get_clock_ms(rt_clock); + s->total_time = end_time - s->total_time; + s->downtime = end_time - start_time; + if (s->state != MIG_STATE_COMPLETED) { + if (old_vm_running) { + vm_start(); + } + } + last_round = true; + } + qemu_mutex_unlock_iothread(); + + return last_round; +} + +static void *buffered_file_thread(void *opaque) +{ + MigrationState *s = opaque; + int64_t initial_time = qemu_get_clock_ms(rt_clock); + int64_t max_size = 0; + bool last_round = false; + + while (true) { + int64_t current_time = qemu_get_clock_ms(rt_clock); + + if (s->complete) { + break; + } + if (current_time >= initial_time + BUFFER_DELAY) { + uint64_t transferred_bytes = s->bytes_xfer; + uint64_t time_spent = current_time - initial_time; + double bandwidth = transferred_bytes / time_spent; + max_size = bandwidth * migrate_max_downtime() / 1000000; + + DPRINTF("transferred %" PRIu64 " time_spent %" PRIu64 + " bandwidth %g max_size %" PRId64 "\n", + transferred_bytes, time_spent, bandwidth, max_size); + + s->bytes_xfer = 0; + initial_time = current_time; + } + if (!last_round && (s->bytes_xfer >= s->xfer_limit)) { + /* usleep expects microseconds */ + g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); + } + if (buffered_flush(s) < 0) { + break; + } + + DPRINTF("file is ready\n"); + if (s->bytes_xfer < s->xfer_limit) { + DPRINTF("notifying client\n"); + last_round = migrate_fd_put_ready(s, max_size); + } + } + + g_free(s->buffer); + return NULL; +} + +static const QEMUFileOps buffered_file_ops = { + .get_fd = buffered_get_fd, + .put_buffer = buffered_put_buffer, + .close = buffered_close, + .rate_limit = buffered_rate_limit, + .get_rate_limit = buffered_get_rate_limit, + .set_rate_limit = buffered_set_rate_limit, +}; + +void migrate_fd_connect(MigrationState *s) +{ + s->state = MIG_STATE_ACTIVE; + s->bytes_xfer = 0; + s->buffer = NULL; + s->buffer_size = 0; + s->buffer_capacity = 0; + + s->first_time = true; + + s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; + s->complete = false; + + s->file = qemu_fopen_ops(s, &buffered_file_ops); + + qemu_thread_create(&s->thread, buffered_file_thread, s, + QEMU_THREAD_DETACHED); + notifier_list_notify(&migration_state_notifiers, s); +} diff --git a/net/tap-win32.c b/net/tap-win32.c index 0c63cbd203..265369c3c5 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -31,6 +31,7 @@ #include "qemu-common.h" #include "clients.h" /* net_init_tap */ #include "net/net.h" +#include "net/tap.h" /* tap_has_ufo, ... */ #include "sysemu/sysemu.h" #include "qemu/error-report.h" #include <stdio.h> diff --git a/net/vde.c b/net/vde.c index 754a141543..4dea32d07a 100644 --- a/net/vde.c +++ b/net/vde.c @@ -29,6 +29,7 @@ #include "clients.h" #include "qemu-common.h" #include "qemu/option.h" +#include "qemu/main-loop.h" typedef struct VDEState { NetClientState nc; diff --git a/pc-bios/acpi-dsdt.aml b/pc-bios/acpi-dsdt.aml index 18b4dc1aa5..00224eabb7 100644 --- a/pc-bios/acpi-dsdt.aml +++ b/pc-bios/acpi-dsdt.aml Binary files differdiff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 3eefff4cf8..3910875311 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin Binary files differdiff --git a/pc-bios/q35-acpi-dsdt.aml b/pc-bios/q35-acpi-dsdt.aml index 8a50559514..e50641cc53 100644 --- a/pc-bios/q35-acpi-dsdt.aml +++ b/pc-bios/q35-acpi-dsdt.aml Binary files differdiff --git a/qemu-char.c b/qemu-char.c index 6113d0ab60..c6382a93f5 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -980,6 +980,7 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) CharDriverState *chr; PtyCharDriver *s; struct termios tty; + const char *label; int master_fd, slave_fd, len; #if defined(__OpenBSD__) || defined(__DragonFly__) char pty_name[PATH_MAX]; @@ -1005,7 +1006,12 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) chr->filename = g_malloc(len); snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd)); qemu_opt_set(opts, "path", q_ptsname(master_fd)); - fprintf(stderr, "char device redirected to %s\n", q_ptsname(master_fd)); + + label = qemu_opts_id(opts); + fprintf(stderr, "char device%s%s redirected to %s\n", + label ? " " : "", + label ?: "", + q_ptsname(master_fd)); s = g_malloc0(sizeof(PtyCharDriver)); chr->opaque = s; diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c index 7be292ed68..4489abf1d8 100644 --- a/qemu-thread-posix.c +++ b/qemu-thread-posix.c @@ -122,7 +122,7 @@ void qemu_sem_init(QemuSemaphore *sem, int init) { int rc; -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) rc = pthread_mutex_init(&sem->lock, NULL); if (rc != 0) { error_exit(rc, __func__); @@ -147,7 +147,7 @@ void qemu_sem_destroy(QemuSemaphore *sem) { int rc; -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) rc = pthread_cond_destroy(&sem->cond); if (rc < 0) { error_exit(rc, __func__); @@ -168,7 +168,7 @@ void qemu_sem_post(QemuSemaphore *sem) { int rc; -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_lock(&sem->lock); if (sem->count == INT_MAX) { rc = EINVAL; @@ -206,13 +206,14 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms) int rc; struct timespec ts; -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) compute_abs_deadline(&ts, ms); pthread_mutex_lock(&sem->lock); --sem->count; while (sem->count < 0) { rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts); if (rc == ETIMEDOUT) { + ++sem->count; break; } if (rc != 0) { @@ -248,7 +249,7 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms) void qemu_sem_wait(QemuSemaphore *sem) { -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_lock(&sem->lock); --sem->count; while (sem->count < 0) { diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c index 8037b39045..517878dcc1 100644 --- a/qemu-thread-win32.c +++ b/qemu-thread-win32.c @@ -239,7 +239,7 @@ struct QemuThreadData { CRITICAL_SECTION cs; }; -static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES; +static __thread QemuThreadData *qemu_thread_data; static unsigned __stdcall win32_start_routine(void *arg) { @@ -251,14 +251,15 @@ static unsigned __stdcall win32_start_routine(void *arg) g_free(data); data = NULL; } - TlsSetValue(qemu_thread_tls_index, data); + qemu_thread_data = data; qemu_thread_exit(start_routine(thread_arg)); abort(); } void qemu_thread_exit(void *arg) { - QemuThreadData *data = TlsGetValue(qemu_thread_tls_index); + QemuThreadData *data = qemu_thread_data; + if (data) { assert(data->mode != QEMU_THREAD_DETACHED); data->ret = arg; @@ -298,25 +299,13 @@ void *qemu_thread_join(QemuThread *thread) return ret; } -static inline void qemu_thread_init(void) -{ - if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) { - qemu_thread_tls_index = TlsAlloc(); - if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) { - error_exit(ERROR_NO_SYSTEM_RESOURCES, __func__); - } - } -} - - void qemu_thread_create(QemuThread *thread, void *(*start_routine)(void *), void *arg, int mode) { HANDLE hThread; - struct QemuThreadData *data; - qemu_thread_init(); + data = g_malloc(sizeof *data); data->start_routine = start_routine; data->arg = arg; @@ -338,8 +327,7 @@ void qemu_thread_create(QemuThread *thread, void qemu_thread_get_self(QemuThread *thread) { - qemu_thread_init(); - thread->data = TlsGetValue(qemu_thread_tls_index); + thread->data = qemu_thread_data; thread->tid = GetCurrentThreadId(); } diff --git a/roms/seabios b/roms/seabios -Subproject e8a76b0f225bba5ba9d63ab227e0a37b3beb105 +Subproject a810e4e72a0d42c7bc04eda57382f8e019add90 diff --git a/savevm.c b/savevm.c index b2a844f2b1..bcdb92ee81 100644 --- a/savevm.c +++ b/savevm.c @@ -555,11 +555,6 @@ int qemu_fclose(QEMUFile *f) return ret; } -int qemu_file_put_notify(QEMUFile *f) -{ - return f->ops->put_buffer(f->opaque, NULL, 0, 0); -} - void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) { int l; @@ -1758,6 +1753,25 @@ int qemu_savevm_state_complete(QEMUFile *f) return qemu_file_get_error(f); } +uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size) +{ + SaveStateEntry *se; + uint64_t ret = 0; + + QTAILQ_FOREACH(se, &savevm_handlers, entry) { + if (!se->ops || !se->ops->save_live_pending) { + continue; + } + if (se->ops && se->ops->is_active) { + if (!se->ops->is_active(se->opaque)) { + continue; + } + } + ret += se->ops->save_live_pending(f, se->opaque, max_size); + } + return ret; +} + void qemu_savevm_state_cancel(QEMUFile *f) { SaveStateEntry *se; diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index 23c43e2772..ad5eb3b0ab 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -37,7 +37,7 @@ def c(events): def h(events): - out('#include "trace-dtrace.h"', + out('#include "trace/generated-tracers-dtrace.h"', '') for e in events: diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 6ffb3c2f4e..9a58de1331 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -19,8 +19,8 @@ from tracetool import out def begin(events): out('/* This file is autogenerated by tracetool, do not edit. */', '', - '#ifndef TRACE_H', - '#define TRACE_H', + '#ifndef TRACE__GENERATED_TRACERS_H', + '#define TRACE__GENERATED_TRACERS_H', '', '#include "qemu-common.h"') @@ -32,7 +32,7 @@ def end(events): enabled = 1 out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) out('', - '#endif /* TRACE_H */') + '#endif /* TRACE__GENERATED_TRACERS_H */') def nop(events): for e in events: diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h index f2414f7e4f..16367d2ea4 100644 --- a/target-alpha/cpu-qom.h +++ b/target-alpha/cpu-qom.h @@ -58,6 +58,9 @@ typedef struct AlphaCPU { /*< public >*/ CPUAlphaState env; + + /* This alarm doesn't exist in real hardware; we wish it did. */ + struct QEMUTimer *alarm_timer; } AlphaCPU; static inline AlphaCPU *alpha_env_get_cpu(CPUAlphaState *env) diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 11a19ebc87..212a6250ba 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -21,8 +21,211 @@ #include "cpu.h" #include "qemu-common.h" +#include "qapi/error.h" +static void alpha_cpu_realize(Object *obj, Error **errp) +{ +#ifndef CONFIG_USER_ONLY + AlphaCPU *cpu = ALPHA_CPU(obj); + + qemu_init_vcpu(&cpu->env); +#endif +} + +/* Sort alphabetically by type name. */ +static gint alpha_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *class_a = (ObjectClass *)a; + ObjectClass *class_b = (ObjectClass *)b; + const char *name_a, *name_b; + + name_a = object_class_get_name(class_a); + name_b = object_class_get_name(class_b); + return strcmp(name_a, name_b); +} + +static void alpha_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CPUListState *s = user_data; + + (*s->cpu_fprintf)(s->file, " %s\n", + object_class_get_name(oc)); +} + +void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + CPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_ALPHA_CPU, false); + list = g_slist_sort(list, alpha_cpu_list_compare); + (*cpu_fprintf)(f, "Available CPUs:\n"); + g_slist_foreach(list, alpha_cpu_list_entry, &s); + g_slist_free(list); +} + +/* Models */ + +#define TYPE(model) model "-" TYPE_ALPHA_CPU + +typedef struct AlphaCPUAlias { + const char *alias; + const char *typename; +} AlphaCPUAlias; + +static const AlphaCPUAlias alpha_cpu_aliases[] = { + { "21064", TYPE("ev4") }, + { "21164", TYPE("ev5") }, + { "21164a", TYPE("ev56") }, + { "21164pc", TYPE("pca56") }, + { "21264", TYPE("ev6") }, + { "21264a", TYPE("ev67") }, +}; + +static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc = NULL; + char *typename; + int i; + + if (cpu_model == NULL) { + return NULL; + } + + oc = object_class_by_name(cpu_model); + if (oc != NULL) { + return oc; + } + + for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) { + if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) { + oc = object_class_by_name(alpha_cpu_aliases[i].typename); + assert(oc != NULL); + return oc; + } + } + + typename = g_strdup_printf("%s-" TYPE_ALPHA_CPU, cpu_model); + oc = object_class_by_name(typename); + g_free(typename); + return oc; +} + +AlphaCPU *cpu_alpha_init(const char *cpu_model) +{ + AlphaCPU *cpu; + CPUAlphaState *env; + ObjectClass *cpu_class; + + cpu_class = alpha_cpu_class_by_name(cpu_model); + if (cpu_class == NULL) { + /* Default to ev67; no reason not to emulate insns by default. */ + cpu_class = object_class_by_name(TYPE("ev67")); + } + cpu = ALPHA_CPU(object_new(object_class_get_name(cpu_class))); + env = &cpu->env; + + env->cpu_model_str = cpu_model; + + alpha_cpu_realize(OBJECT(cpu), NULL); + return cpu; +} + +static void ev4_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->implver = IMPLVER_2106x; +} + +static const TypeInfo ev4_cpu_type_info = { + .name = TYPE("ev4"), + .parent = TYPE_ALPHA_CPU, + .instance_init = ev4_cpu_initfn, +}; + +static void ev5_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->implver = IMPLVER_21164; +} + +static const TypeInfo ev5_cpu_type_info = { + .name = TYPE("ev5"), + .parent = TYPE_ALPHA_CPU, + .instance_init = ev5_cpu_initfn, +}; + +static void ev56_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->amask |= AMASK_BWX; +} + +static const TypeInfo ev56_cpu_type_info = { + .name = TYPE("ev56"), + .parent = TYPE("ev5"), + .instance_init = ev56_cpu_initfn, +}; + +static void pca56_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->amask |= AMASK_MVI; +} + +static const TypeInfo pca56_cpu_type_info = { + .name = TYPE("pca56"), + .parent = TYPE("ev56"), + .instance_init = pca56_cpu_initfn, +}; + +static void ev6_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->implver = IMPLVER_21264; + env->amask = AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP; +} + +static const TypeInfo ev6_cpu_type_info = { + .name = TYPE("ev6"), + .parent = TYPE_ALPHA_CPU, + .instance_init = ev6_cpu_initfn, +}; + +static void ev67_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->amask |= AMASK_CIX | AMASK_PREFETCH; +} + +static const TypeInfo ev67_cpu_type_info = { + .name = TYPE("ev67"), + .parent = TYPE("ev6"), + .instance_init = ev67_cpu_initfn, +}; + +static const TypeInfo ev68_cpu_type_info = { + .name = TYPE("ev68"), + .parent = TYPE("ev67"), +}; + static void alpha_cpu_initfn(Object *obj) { AlphaCPU *cpu = ALPHA_CPU(obj); @@ -31,6 +234,8 @@ static void alpha_cpu_initfn(Object *obj) cpu_exec_init(env); tlb_flush(env, 1); + alpha_translate_init(); + #if defined(CONFIG_USER_ONLY) env->ps = PS_USER_MODE; cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD @@ -46,13 +251,20 @@ static const TypeInfo alpha_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(AlphaCPU), .instance_init = alpha_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(AlphaCPUClass), }; static void alpha_cpu_register_types(void) { type_register_static(&alpha_cpu_type_info); + type_register_static(&ev4_cpu_type_info); + type_register_static(&ev5_cpu_type_info); + type_register_static(&ev56_cpu_type_info); + type_register_static(&pca56_cpu_type_info); + type_register_static(&ev6_cpu_type_info); + type_register_static(&ev67_cpu_type_info); + type_register_static(&ev68_cpu_type_info); } type_init(alpha_cpu_register_types) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index b75c856f97..f1db6518ce 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -277,7 +277,6 @@ struct CPUAlphaState { #endif /* This alarm doesn't exist in real hardware; we wish it did. */ - struct QEMUTimer *alarm_timer; uint64_t alarm_expire; /* Those resources are used only in QEMU core */ @@ -290,7 +289,7 @@ struct CPUAlphaState { int implver; }; -#define cpu_init cpu_alpha_init +#define cpu_list alpha_cpu_list #define cpu_exec cpu_alpha_exec #define cpu_gen_code cpu_alpha_gen_code #define cpu_signal_handler cpu_alpha_signal_handler @@ -427,7 +426,20 @@ enum { IR_ZERO = 31, }; -CPUAlphaState * cpu_alpha_init (const char *cpu_model); +void alpha_translate_init(void); + +AlphaCPU *cpu_alpha_init(const char *cpu_model); + +static inline CPUAlphaState *cpu_init(const char *cpu_model) +{ + AlphaCPU *cpu = cpu_alpha_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + +void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf); int cpu_alpha_exec(CPUAlphaState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c index 434a63a97d..339501af90 100644 --- a/target-alpha/sys_helper.c +++ b/target-alpha/sys_helper.c @@ -77,11 +77,13 @@ uint64_t helper_get_time(void) void helper_set_alarm(CPUAlphaState *env, uint64_t expire) { + AlphaCPU *cpu = alpha_env_get_cpu(env); + if (expire) { env->alarm_expire = expire; - qemu_mod_timer(env->alarm_timer, expire); + qemu_mod_timer(cpu->alarm_timer, expire); } else { - qemu_del_timer(env->alarm_timer); + qemu_del_timer(cpu->alarm_timer); } } #endif /* CONFIG_USER_ONLY */ diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 3afc3c63f9..5cb40b7ab6 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -90,7 +90,7 @@ static char cpu_reg_names[10*4+21*5 + 10*5+21*6]; #include "exec/gen-icount.h" -static void alpha_translate_init(void) +void alpha_translate_init(void) { int i; char *p; @@ -3493,62 +3493,6 @@ void gen_intermediate_code_pc (CPUAlphaState *env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -struct cpu_def_t { - const char *name; - int implver, amask; -}; - -static const struct cpu_def_t cpu_defs[] = { - { "ev4", IMPLVER_2106x, 0 }, - { "ev5", IMPLVER_21164, 0 }, - { "ev56", IMPLVER_21164, AMASK_BWX }, - { "pca56", IMPLVER_21164, AMASK_BWX | AMASK_MVI }, - { "ev6", IMPLVER_21264, AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP }, - { "ev67", IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX - | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), }, - { "ev68", IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX - | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), }, - { "21064", IMPLVER_2106x, 0 }, - { "21164", IMPLVER_21164, 0 }, - { "21164a", IMPLVER_21164, AMASK_BWX }, - { "21164pc", IMPLVER_21164, AMASK_BWX | AMASK_MVI }, - { "21264", IMPLVER_21264, AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP }, - { "21264a", IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX - | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), } -}; - -CPUAlphaState * cpu_alpha_init (const char *cpu_model) -{ - AlphaCPU *cpu; - CPUAlphaState *env; - int implver, amask, i, max; - - cpu = ALPHA_CPU(object_new(TYPE_ALPHA_CPU)); - env = &cpu->env; - - alpha_translate_init(); - - /* Default to ev67; no reason not to emulate insns by default. */ - implver = IMPLVER_21264; - amask = (AMASK_BWX | AMASK_FIX | AMASK_CIX | AMASK_MVI - | AMASK_TRAP | AMASK_PREFETCH); - - max = ARRAY_SIZE(cpu_defs); - for (i = 0; i < max; i++) { - if (strcmp (cpu_model, cpu_defs[i].name) == 0) { - implver = cpu_defs[i].implver; - amask = cpu_defs[i].amask; - break; - } - } - env->implver = implver; - env->amask = amask; - env->cpu_model_str = cpu_model; - - qemu_init_vcpu(env); - return env; -} - void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, int pc_pos) { env->pc = tcg_ctx.gen_opc_pc[pc_pos]; diff --git a/target-arm/helper.c b/target-arm/helper.c index e343fac853..0525aec87a 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1291,11 +1291,6 @@ ARMCPU *cpu_arm_init(const char *cpu_model) return cpu; } -typedef struct ARMCPUListState { - fprintf_function cpu_fprintf; - FILE *file; -} ARMCPUListState; - /* Sort alphabetically by type name, except for "any". */ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b) { @@ -1317,7 +1312,7 @@ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b) static void arm_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - ARMCPUListState *s = user_data; + CPUListState *s = user_data; (*s->cpu_fprintf)(s->file, " %s\n", object_class_get_name(oc)); @@ -1325,7 +1320,7 @@ static void arm_cpu_list_entry(gpointer data, gpointer user_data) void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf) { - ARMCPUListState s = { + CPUListState s = { .file = f, .cpu_fprintf = cpu_fprintf, }; diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c index 8209ce9ee2..2cd2f7f09e 100644 --- a/target-i386/arch_dump.c +++ b/target-i386/arch_dump.c @@ -403,7 +403,7 @@ int cpu_get_dump_info(ArchDumpInfo *info) } else { info->d_class = ELFCLASS32; - QLIST_FOREACH(block, &ram_list.blocks, next) { + QTAILQ_FOREACH(block, &ram_list.blocks, next) { if (block->offset + block->length > UINT_MAX) { /* The memory size is greater than 4G */ info->d_class = ELFCLASS64; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 1837f5af04..82685dc3f5 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1637,6 +1637,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { + X86CPU *cpu = x86_env_get_cpu(env); + CPUState *cs = CPU(cpu); + /* test if maximum index reached */ if (index & 0x80000000) { if (index > env->cpuid_xlevel) { @@ -1648,7 +1651,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, index = env->cpuid_xlevel; } } else { - index = env->cpuid_xlevel; + /* Intel documentation states that invalid EAX input will + * return the same information as EAX=cpuid_level + * (Intel SDM Vol. 2A - Instruction Set Reference - CPUID) + */ + index = env->cpuid_level; } } } else { @@ -1753,7 +1760,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0xA: /* Architectural Performance Monitoring Leaf */ if (kvm_enabled()) { - KVMState *s = env->kvm_state; + KVMState *s = cs->kvm_state; *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); @@ -1776,7 +1783,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; } if (kvm_enabled()) { - KVMState *s = env->kvm_state; + KVMState *s = cs->kvm_state; *eax = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EAX); *ebx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EBX); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f63b1fbfda..b31eac1c91 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -307,16 +307,17 @@ static void hardware_memory_error(void) exit(1); } -int kvm_arch_on_sigbus_vcpu(CPUX86State *env, int code, void *addr) +int kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(c); + CPUX86State *env = &cpu->env; ram_addr_t ram_addr; hwaddr paddr; if ((env->mcg_cap & MCG_SER_P) && addr && (code == BUS_MCEERR_AR || code == BUS_MCEERR_AO)) { if (qemu_ram_addr_from_host(addr, &ram_addr) || - !kvm_physical_memory_addr_from_host(env->kvm_state, addr, &paddr)) { + !kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)) { fprintf(stderr, "Hardware memory error for memory used by " "QEMU itself instead of guest system!\n"); /* Hope we are lucky for AO MCE */ @@ -348,8 +349,8 @@ int kvm_arch_on_sigbus(int code, void *addr) /* Hope we are lucky for AO MCE */ if (qemu_ram_addr_from_host(addr, &ram_addr) || - !kvm_physical_memory_addr_from_host(first_cpu->kvm_state, addr, - &paddr)) { + !kvm_physical_memory_addr_from_host(CPU(first_cpu)->kvm_state, + addr, &paddr)) { fprintf(stderr, "Hardware memory error for memory used by " "QEMU itself instead of guest system!: %p\n", addr); return 0; @@ -368,8 +369,10 @@ int kvm_arch_on_sigbus(int code, void *addr) return 0; } -static int kvm_inject_mce_oldstyle(CPUX86State *env) +static int kvm_inject_mce_oldstyle(X86CPU *cpu) { + CPUX86State *env = &cpu->env; + if (!kvm_has_vcpu_events() && env->exception_injected == EXCP12_MCHK) { unsigned int bank, bank_num = env->mcg_cap & 0xff; struct kvm_x86_mce mce; @@ -393,7 +396,7 @@ static int kvm_inject_mce_oldstyle(CPUX86State *env) mce.addr = env->mce_banks[bank * 4 + 2]; mce.misc = env->mce_banks[bank * 4 + 3]; - return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, &mce); + return kvm_vcpu_ioctl(CPU(cpu), KVM_X86_SET_MCE, &mce); } return 0; } @@ -407,12 +410,14 @@ static void cpu_update_state(void *opaque, int running, RunState state) } } -int kvm_arch_init_vcpu(CPUX86State *env) +int kvm_arch_init_vcpu(CPUState *cs) { struct { struct kvm_cpuid2 cpuid; struct kvm_cpuid_entry2 entries[100]; } QEMU_PACKED cpuid_data; + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; uint32_t limit, i, j, cpuid_i; uint32_t unused; struct kvm_cpuid_entry2 *c; @@ -575,12 +580,12 @@ int kvm_arch_init_vcpu(CPUX86State *env) if (((env->cpuid_version >> 8)&0xF) >= 6 && (env->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA) - && kvm_check_extension(env->kvm_state, KVM_CAP_MCE) > 0) { + && kvm_check_extension(cs->kvm_state, KVM_CAP_MCE) > 0) { uint64_t mcg_cap; int banks; int ret; - ret = kvm_get_mce_cap_supported(env->kvm_state, &mcg_cap, &banks); + ret = kvm_get_mce_cap_supported(cs->kvm_state, &mcg_cap, &banks); if (ret < 0) { fprintf(stderr, "kvm_get_mce_cap_supported: %s", strerror(-ret)); return ret; @@ -591,7 +596,7 @@ int kvm_arch_init_vcpu(CPUX86State *env) } mcg_cap &= MCE_CAP_DEF; mcg_cap |= banks; - ret = kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, &mcg_cap); + ret = kvm_vcpu_ioctl(cs, KVM_X86_SETUP_MCE, &mcg_cap); if (ret < 0) { fprintf(stderr, "KVM_X86_SETUP_MCE: %s", strerror(-ret)); return ret; @@ -603,14 +608,14 @@ int kvm_arch_init_vcpu(CPUX86State *env) qemu_add_vm_change_state_handler(cpu_update_state, env); cpuid_data.cpuid.padding = 0; - r = kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data); + r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data); if (r) { return r; } - r = kvm_check_extension(env->kvm_state, KVM_CAP_TSC_CONTROL); + r = kvm_check_extension(cs->kvm_state, KVM_CAP_TSC_CONTROL); if (r && env->tsc_khz) { - r = kvm_vcpu_ioctl(env, KVM_SET_TSC_KHZ, env->tsc_khz); + r = kvm_vcpu_ioctl(cs, KVM_SET_TSC_KHZ, env->tsc_khz); if (r < 0) { fprintf(stderr, "KVM_SET_TSC_KHZ failed\n"); return r; @@ -624,9 +629,10 @@ int kvm_arch_init_vcpu(CPUX86State *env) return 0; } -void kvm_arch_reset_vcpu(CPUX86State *env) +void kvm_arch_reset_vcpu(CPUState *cs) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; env->exception_injected = -1; env->interrupt_injected = -1; @@ -817,13 +823,14 @@ static void kvm_getput_reg(__u64 *kvm_reg, target_ulong *qemu_reg, int set) } } -static int kvm_getput_regs(CPUX86State *env, int set) +static int kvm_getput_regs(X86CPU *cpu, int set) { + CPUX86State *env = &cpu->env; struct kvm_regs regs; int ret = 0; if (!set) { - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_REGS, ®s); if (ret < 0) { return ret; } @@ -852,14 +859,15 @@ static int kvm_getput_regs(CPUX86State *env, int set) kvm_getput_reg(®s.rip, &env->eip, set); if (set) { - ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_REGS, ®s); } return ret; } -static int kvm_put_fpu(CPUX86State *env) +static int kvm_put_fpu(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_fpu fpu; int i; @@ -877,7 +885,7 @@ static int kvm_put_fpu(CPUX86State *env) memcpy(fpu.xmm, env->xmm_regs, sizeof env->xmm_regs); fpu.mxcsr = env->mxcsr; - return kvm_vcpu_ioctl(env, KVM_SET_FPU, &fpu); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_FPU, &fpu); } #define XSAVE_FCW_FSW 0 @@ -890,14 +898,15 @@ static int kvm_put_fpu(CPUX86State *env) #define XSAVE_XSTATE_BV 128 #define XSAVE_YMMH_SPACE 144 -static int kvm_put_xsave(CPUX86State *env) +static int kvm_put_xsave(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_xsave* xsave = env->kvm_xsave_buf; uint16_t cwd, swd, twd; int i, r; if (!kvm_has_xsave()) { - return kvm_put_fpu(env); + return kvm_put_fpu(cpu); } memset(xsave, 0, sizeof(struct kvm_xsave)); @@ -920,12 +929,13 @@ static int kvm_put_xsave(CPUX86State *env) *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV] = env->xstate_bv; memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs, sizeof env->ymmh_regs); - r = kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave); + r = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XSAVE, xsave); return r; } -static int kvm_put_xcrs(CPUX86State *env) +static int kvm_put_xcrs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_xcrs xcrs; if (!kvm_has_xcrs()) { @@ -936,11 +946,12 @@ static int kvm_put_xcrs(CPUX86State *env) xcrs.flags = 0; xcrs.xcrs[0].xcr = 0; xcrs.xcrs[0].value = env->xcr0; - return kvm_vcpu_ioctl(env, KVM_SET_XCRS, &xcrs); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XCRS, &xcrs); } -static int kvm_put_sregs(CPUX86State *env) +static int kvm_put_sregs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_sregs sregs; memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap)); @@ -985,7 +996,7 @@ static int kvm_put_sregs(CPUX86State *env) sregs.efer = env->efer; - return kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs); } static void kvm_msr_entry_set(struct kvm_msr_entry *entry, @@ -995,8 +1006,9 @@ static void kvm_msr_entry_set(struct kvm_msr_entry *entry, entry->data = value; } -static int kvm_put_msrs(CPUX86State *env, int level) +static int kvm_put_msrs(X86CPU *cpu, int level) { + CPUX86State *env = &cpu->env; struct { struct kvm_msrs info; struct kvm_msr_entry entries[100]; @@ -1077,17 +1089,18 @@ static int kvm_put_msrs(CPUX86State *env, int level) msr_data.info.nmsrs = n; - return kvm_vcpu_ioctl(env, KVM_SET_MSRS, &msr_data); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, &msr_data); } -static int kvm_get_fpu(CPUX86State *env) +static int kvm_get_fpu(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_fpu fpu; int i, ret; - ret = kvm_vcpu_ioctl(env, KVM_GET_FPU, &fpu); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_FPU, &fpu); if (ret < 0) { return ret; } @@ -1108,17 +1121,18 @@ static int kvm_get_fpu(CPUX86State *env) return 0; } -static int kvm_get_xsave(CPUX86State *env) +static int kvm_get_xsave(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_xsave* xsave = env->kvm_xsave_buf; int ret, i; uint16_t cwd, swd, twd; if (!kvm_has_xsave()) { - return kvm_get_fpu(env); + return kvm_get_fpu(cpu); } - ret = kvm_vcpu_ioctl(env, KVM_GET_XSAVE, xsave); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_XSAVE, xsave); if (ret < 0) { return ret; } @@ -1146,8 +1160,9 @@ static int kvm_get_xsave(CPUX86State *env) return 0; } -static int kvm_get_xcrs(CPUX86State *env) +static int kvm_get_xcrs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; int i, ret; struct kvm_xcrs xcrs; @@ -1155,7 +1170,7 @@ static int kvm_get_xcrs(CPUX86State *env) return 0; } - ret = kvm_vcpu_ioctl(env, KVM_GET_XCRS, &xcrs); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_XCRS, &xcrs); if (ret < 0) { return ret; } @@ -1170,13 +1185,14 @@ static int kvm_get_xcrs(CPUX86State *env) return 0; } -static int kvm_get_sregs(CPUX86State *env) +static int kvm_get_sregs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_sregs sregs; uint32_t hflags; int bit, i, ret; - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -1254,8 +1270,9 @@ static int kvm_get_sregs(CPUX86State *env) return 0; } -static int kvm_get_msrs(CPUX86State *env) +static int kvm_get_msrs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct { struct kvm_msrs info; struct kvm_msr_entry entries[100]; @@ -1312,7 +1329,7 @@ static int kvm_get_msrs(CPUX86State *env) } msr_data.info.nmsrs = n; - ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &msr_data); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data); if (ret < 0) { return ret; } @@ -1390,11 +1407,11 @@ static int kvm_get_msrs(CPUX86State *env) return 0; } -static int kvm_put_mp_state(CPUX86State *env) +static int kvm_put_mp_state(X86CPU *cpu) { - struct kvm_mp_state mp_state = { .mp_state = env->mp_state }; + struct kvm_mp_state mp_state = { .mp_state = cpu->env.mp_state }; - return kvm_vcpu_ioctl(env, KVM_SET_MP_STATE, &mp_state); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state); } static int kvm_get_mp_state(X86CPU *cpu) @@ -1403,7 +1420,7 @@ static int kvm_get_mp_state(X86CPU *cpu) struct kvm_mp_state mp_state; int ret; - ret = kvm_vcpu_ioctl(env, KVM_GET_MP_STATE, &mp_state); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MP_STATE, &mp_state); if (ret < 0) { return ret; } @@ -1414,14 +1431,15 @@ static int kvm_get_mp_state(X86CPU *cpu) return 0; } -static int kvm_get_apic(CPUX86State *env) +static int kvm_get_apic(X86CPU *cpu) { + CPUX86State *env = &cpu->env; DeviceState *apic = env->apic_state; struct kvm_lapic_state kapic; int ret; if (apic && kvm_irqchip_in_kernel()) { - ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_LAPIC, &kapic); if (ret < 0) { return ret; } @@ -1431,21 +1449,23 @@ static int kvm_get_apic(CPUX86State *env) return 0; } -static int kvm_put_apic(CPUX86State *env) +static int kvm_put_apic(X86CPU *cpu) { + CPUX86State *env = &cpu->env; DeviceState *apic = env->apic_state; struct kvm_lapic_state kapic; if (apic && kvm_irqchip_in_kernel()) { kvm_put_apic_state(apic, &kapic); - return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_LAPIC, &kapic); } return 0; } -static int kvm_put_vcpu_events(CPUX86State *env, int level) +static int kvm_put_vcpu_events(X86CPU *cpu, int level) { + CPUX86State *env = &cpu->env; struct kvm_vcpu_events events; if (!kvm_has_vcpu_events()) { @@ -1475,11 +1495,12 @@ static int kvm_put_vcpu_events(CPUX86State *env, int level) KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR; } - return kvm_vcpu_ioctl(env, KVM_SET_VCPU_EVENTS, &events); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events); } -static int kvm_get_vcpu_events(CPUX86State *env) +static int kvm_get_vcpu_events(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_vcpu_events events; int ret; @@ -1487,7 +1508,7 @@ static int kvm_get_vcpu_events(CPUX86State *env) return 0; } - ret = kvm_vcpu_ioctl(env, KVM_GET_VCPU_EVENTS, &events); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_VCPU_EVENTS, &events); if (ret < 0) { return ret; } @@ -1513,8 +1534,9 @@ static int kvm_get_vcpu_events(CPUX86State *env) return 0; } -static int kvm_guest_debug_workarounds(CPUX86State *env) +static int kvm_guest_debug_workarounds(X86CPU *cpu) { + CPUX86State *env = &cpu->env; int ret = 0; unsigned long reinject_trap = 0; @@ -1542,8 +1564,9 @@ static int kvm_guest_debug_workarounds(CPUX86State *env) return ret; } -static int kvm_put_debugregs(CPUX86State *env) +static int kvm_put_debugregs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_debugregs dbgregs; int i; @@ -1558,11 +1581,12 @@ static int kvm_put_debugregs(CPUX86State *env) dbgregs.dr7 = env->dr[7]; dbgregs.flags = 0; - return kvm_vcpu_ioctl(env, KVM_SET_DEBUGREGS, &dbgregs); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_DEBUGREGS, &dbgregs); } -static int kvm_get_debugregs(CPUX86State *env) +static int kvm_get_debugregs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_debugregs dbgregs; int i, ret; @@ -1570,7 +1594,7 @@ static int kvm_get_debugregs(CPUX86State *env) return 0; } - ret = kvm_vcpu_ioctl(env, KVM_GET_DEBUGREGS, &dbgregs); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_DEBUGREGS, &dbgregs); if (ret < 0) { return ret; } @@ -1583,88 +1607,88 @@ static int kvm_get_debugregs(CPUX86State *env) return 0; } -int kvm_arch_put_registers(CPUX86State *env, int level) +int kvm_arch_put_registers(CPUState *cpu, int level) { - CPUState *cpu = ENV_GET_CPU(env); + X86CPU *x86_cpu = X86_CPU(cpu); int ret; assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); - ret = kvm_getput_regs(env, 1); + ret = kvm_getput_regs(x86_cpu, 1); if (ret < 0) { return ret; } - ret = kvm_put_xsave(env); + ret = kvm_put_xsave(x86_cpu); if (ret < 0) { return ret; } - ret = kvm_put_xcrs(env); + ret = kvm_put_xcrs(x86_cpu); if (ret < 0) { return ret; } - ret = kvm_put_sregs(env); + ret = kvm_put_sregs(x86_cpu); if (ret < 0) { return ret; } /* must be before kvm_put_msrs */ - ret = kvm_inject_mce_oldstyle(env); + ret = kvm_inject_mce_oldstyle(x86_cpu); if (ret < 0) { return ret; } - ret = kvm_put_msrs(env, level); + ret = kvm_put_msrs(x86_cpu, level); if (ret < 0) { return ret; } if (level >= KVM_PUT_RESET_STATE) { - ret = kvm_put_mp_state(env); + ret = kvm_put_mp_state(x86_cpu); if (ret < 0) { return ret; } - ret = kvm_put_apic(env); + ret = kvm_put_apic(x86_cpu); if (ret < 0) { return ret; } } - ret = kvm_put_vcpu_events(env, level); + ret = kvm_put_vcpu_events(x86_cpu, level); if (ret < 0) { return ret; } - ret = kvm_put_debugregs(env); + ret = kvm_put_debugregs(x86_cpu); if (ret < 0) { return ret; } /* must be last */ - ret = kvm_guest_debug_workarounds(env); + ret = kvm_guest_debug_workarounds(x86_cpu); if (ret < 0) { return ret; } return 0; } -int kvm_arch_get_registers(CPUX86State *env) +int kvm_arch_get_registers(CPUState *cs) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(cs); int ret; - assert(cpu_is_stopped(CPU(cpu)) || qemu_cpu_is_self(CPU(cpu))); + assert(cpu_is_stopped(cs) || qemu_cpu_is_self(cs)); - ret = kvm_getput_regs(env, 0); + ret = kvm_getput_regs(cpu, 0); if (ret < 0) { return ret; } - ret = kvm_get_xsave(env); + ret = kvm_get_xsave(cpu); if (ret < 0) { return ret; } - ret = kvm_get_xcrs(env); + ret = kvm_get_xcrs(cpu); if (ret < 0) { return ret; } - ret = kvm_get_sregs(env); + ret = kvm_get_sregs(cpu); if (ret < 0) { return ret; } - ret = kvm_get_msrs(env); + ret = kvm_get_msrs(cpu); if (ret < 0) { return ret; } @@ -1672,30 +1696,32 @@ int kvm_arch_get_registers(CPUX86State *env) if (ret < 0) { return ret; } - ret = kvm_get_apic(env); + ret = kvm_get_apic(cpu); if (ret < 0) { return ret; } - ret = kvm_get_vcpu_events(env); + ret = kvm_get_vcpu_events(cpu); if (ret < 0) { return ret; } - ret = kvm_get_debugregs(env); + ret = kvm_get_debugregs(cpu); if (ret < 0) { return ret; } return 0; } -void kvm_arch_pre_run(CPUX86State *env, struct kvm_run *run) +void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) { + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; int ret; /* Inject NMI */ if (env->interrupt_request & CPU_INTERRUPT_NMI) { env->interrupt_request &= ~CPU_INTERRUPT_NMI; DPRINTF("injected NMI\n"); - ret = kvm_vcpu_ioctl(env, KVM_NMI); + ret = kvm_vcpu_ioctl(cpu, KVM_NMI); if (ret < 0) { fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", strerror(-ret)); @@ -1723,7 +1749,7 @@ void kvm_arch_pre_run(CPUX86State *env, struct kvm_run *run) intr.irq = irq; DPRINTF("injected interrupt %d\n", irq); - ret = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr); + ret = kvm_vcpu_ioctl(cpu, KVM_INTERRUPT, &intr); if (ret < 0) { fprintf(stderr, "KVM: injection failed, interrupt lost (%s)\n", @@ -1747,8 +1773,11 @@ void kvm_arch_pre_run(CPUX86State *env, struct kvm_run *run) } } -void kvm_arch_post_run(CPUX86State *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) { + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + if (run->if_flag) { env->eflags |= IF_MASK; } else { @@ -1758,9 +1787,10 @@ void kvm_arch_post_run(CPUX86State *env, struct kvm_run *run) cpu_set_apic_base(env->apic_state, run->apic_base); } -int kvm_arch_process_async_events(CPUX86State *env) +int kvm_arch_process_async_events(CPUState *cs) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; if (env->interrupt_request & CPU_INTERRUPT_MCE) { /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */ @@ -1830,9 +1860,11 @@ static int kvm_handle_halt(X86CPU *cpu) return 0; } -static int kvm_handle_tpr_access(CPUX86State *env) +static int kvm_handle_tpr_access(X86CPU *cpu) { - struct kvm_run *run = env->kvm_run; + CPUX86State *env = &cpu->env; + CPUState *cs = CPU(cpu); + struct kvm_run *run = cs->kvm_run; apic_handle_tpr_access_report(env->apic_state, run->tpr_access.rip, run->tpr_access.is_write ? TPR_ACCESS_WRITE @@ -1840,8 +1872,9 @@ static int kvm_handle_tpr_access(CPUX86State *env) return 1; } -int kvm_arch_insert_sw_breakpoint(CPUX86State *env, struct kvm_sw_breakpoint *bp) +int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp) { + CPUX86State *env = &X86_CPU(cpu)->env; static const uint8_t int3 = 0xcc; if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0) || @@ -1851,8 +1884,9 @@ int kvm_arch_insert_sw_breakpoint(CPUX86State *env, struct kvm_sw_breakpoint *bp return 0; } -int kvm_arch_remove_sw_breakpoint(CPUX86State *env, struct kvm_sw_breakpoint *bp) +int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp) { + CPUX86State *env = &X86_CPU(cpu)->env; uint8_t int3; if (cpu_memory_rw_debug(env, bp->pc, &int3, 1, 0) || int3 != 0xcc || @@ -1946,9 +1980,10 @@ void kvm_arch_remove_all_hw_breakpoints(void) static CPUWatchpoint hw_watchpoint; -static int kvm_handle_debug(CPUX86State *env, +static int kvm_handle_debug(X86CPU *cpu, struct kvm_debug_exit_arch *arch_info) { + CPUX86State *env = &cpu->env; int ret = 0; int n; @@ -1980,7 +2015,7 @@ static int kvm_handle_debug(CPUX86State *env, } } } - } else if (kvm_find_sw_breakpoint(env, arch_info->pc)) { + } else if (kvm_find_sw_breakpoint(CPU(cpu), arch_info->pc)) { ret = EXCP_DEBUG; } if (ret == 0) { @@ -1995,7 +2030,7 @@ static int kvm_handle_debug(CPUX86State *env, return ret; } -void kvm_arch_update_guest_debug(CPUX86State *env, struct kvm_guest_debug *dbg) +void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) { const uint8_t type_code[] = { [GDB_BREAKPOINT_HW] = 0x0, @@ -2007,7 +2042,7 @@ void kvm_arch_update_guest_debug(CPUX86State *env, struct kvm_guest_debug *dbg) }; int n; - if (kvm_sw_breakpoints_active(env)) { + if (kvm_sw_breakpoints_active(cpu)) { dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; } if (nb_hw_breakpoint > 0) { @@ -2032,9 +2067,9 @@ static bool host_supports_vmx(void) #define VMX_INVALID_GUEST_STATE 0x80000021 -int kvm_arch_handle_exit(CPUX86State *env, struct kvm_run *run) +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(cs); uint64_t code; int ret; @@ -2047,7 +2082,7 @@ int kvm_arch_handle_exit(CPUX86State *env, struct kvm_run *run) ret = 0; break; case KVM_EXIT_TPR_ACCESS: - ret = kvm_handle_tpr_access(env); + ret = kvm_handle_tpr_access(cpu); break; case KVM_EXIT_FAIL_ENTRY: code = run->fail_entry.hardware_entry_failure_reason; @@ -2073,7 +2108,7 @@ int kvm_arch_handle_exit(CPUX86State *env, struct kvm_run *run) break; case KVM_EXIT_DEBUG: DPRINTF("kvm_exit_debug\n"); - ret = kvm_handle_debug(env, &run->debug.arch); + ret = kvm_handle_debug(cpu, &run->debug.arch); break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); @@ -2084,8 +2119,11 @@ int kvm_arch_handle_exit(CPUX86State *env, struct kvm_run *run) return ret; } -bool kvm_arch_stop_on_emulation_error(CPUX86State *env) +bool kvm_arch_stop_on_emulation_error(CPUState *cs) { + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + kvm_cpu_synchronize_state(env); return !(env->cr[0] & CR0_PE_MASK) || ((env->segs[R_CS].selector & 3) != 3); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index a9a277865f..097fc789d4 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -25,11 +25,6 @@ #define SIGNBIT (1u << 31) -typedef struct M68kCPUListState { - fprintf_function cpu_fprintf; - FILE *file; -} M68kCPUListState; - /* Sort alphabetically, except for "any". */ static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) { @@ -51,7 +46,7 @@ static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) static void m68k_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *c = data; - M68kCPUListState *s = user_data; + CPUListState *s = user_data; (*s->cpu_fprintf)(s->file, "%s\n", object_class_get_name(c)); @@ -59,7 +54,7 @@ static void m68k_cpu_list_entry(gpointer data, gpointer user_data) void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) { - M68kCPUListState s = { + CPUListState s = { .file = f, .cpu_fprintf = cpu_fprintf, }; diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 14daf91950..a33e2bf9fd 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -2,7 +2,7 @@ * MIPS ASE DSP Instruction emulation helpers for QEMU. * * Copyright (c) 2012 Jia Liu <proljc@gmail.com> - * Dongxue Zhang <elat.era@gmail.com> + * Dongxue Zhang <elta.era@gmail.com> * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -484,35 +484,6 @@ static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b) return (temp >> 1) & 0x00FF; } -static inline int64_t mipsdsp_rashift_short_acc(int32_t ac, - int32_t shift, - CPUMIPSState *env) -{ - int32_t sign, temp31; - int64_t temp, acc; - - sign = (env->active_tc.HI[ac] >> 31) & 0x01; - acc = ((int64_t)env->active_tc.HI[ac] << 32) | - ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF); - if (shift == 0) { - temp = acc; - } else { - if (sign == 0) { - temp = (((int64_t)0x01 << (32 - shift + 1)) - 1) & (acc >> shift); - } else { - temp = ((((int64_t)0x01 << (shift + 1)) - 1) << (32 - shift)) | - (acc >> shift); - } - } - - temp31 = (temp >> 31) & 0x01; - if (sign != temp31) { - set_DSPControl_overflow_flag(1, 23, env); - } - - return temp; -} - /* 128 bits long. p[0] is LO, p[1] is HI. */ static inline void mipsdsp_rndrashift_short_acc(int64_t *p, int32_t ac, @@ -3407,7 +3378,7 @@ target_ulong helper_extr_w(target_ulong ac, target_ulong shift, int32_t tempI; int64_t tempDL[2]; - shift = shift & 0x0F; + shift = shift & 0x1F; mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env); if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && @@ -3435,7 +3406,7 @@ target_ulong helper_extr_r_w(target_ulong ac, target_ulong shift, { int64_t tempDL[2]; - shift = shift & 0x0F; + shift = shift & 0x1F; mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env); if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && @@ -3462,7 +3433,7 @@ target_ulong helper_extr_rs_w(target_ulong ac, target_ulong shift, int32_t tempI, temp64; int64_t tempDL[2]; - shift = shift & 0x0F; + shift = shift & 0x1F; mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env); if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && @@ -3645,11 +3616,15 @@ target_ulong helper_dextr_rs_l(target_ulong ac, target_ulong shift, target_ulong helper_extr_s_h(target_ulong ac, target_ulong shift, CPUMIPSState *env) { - int64_t temp; + int64_t temp, acc; - shift = shift & 0x0F; + shift = shift & 0x1F; + + acc = ((int64_t)env->active_tc.HI[ac] << 32) | + ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF); + + temp = acc >> shift; - temp = mipsdsp_rashift_short_acc(ac, shift, env); if (temp > (int64_t)0x7FFF) { temp = 0x00007FFF; set_DSPControl_overflow_flag(1, 23, env); @@ -3948,7 +3923,11 @@ void helper_wrdsp(target_ulong rs, target_ulong mask_num, CPUMIPSState *env) if (mask[4] == 1) { overwrite &= 0x00FFFFFF; newbits &= 0x00FFFFFF; +#if defined(TARGET_MIPS64) newbits |= 0xFF000000 & rs; +#else + newbits |= 0x0F000000 & rs; +#endif } if (mask[5] == 1) { @@ -3999,7 +3978,11 @@ target_ulong helper_rddsp(target_ulong masknum, CPUMIPSState *env) } if (mask[4] == 1) { +#if defined(TARGET_MIPS64) temp |= dsp & 0xFF000000; +#else + temp |= dsp & 0x0F000000; +#endif } if (mask[5] == 1) { diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index e85edce6fa..d833d78b4f 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -38,10 +38,9 @@ static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, int error_code, uintptr_t pc) { -#if 1 - if (exception < 0x100) + if (exception < EXCP_SC) { qemu_log("%s: %d %d\n", __func__, exception, error_code); -#endif + } env->exception_index = exception; env->error_code = error_code; @@ -2175,7 +2174,7 @@ static unsigned int ieee_rm[] = { set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status) #define RESTORE_FLUSH_MODE \ - set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status); + set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status) target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) { diff --git a/target-mips/translate.c b/target-mips/translate.c index e81ff38476..6281e70471 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13769,9 +13769,10 @@ static void gen_mipsdsp_bitinsn(CPUMIPSState *env, DisasContext *ctx, check_dsp(ctx); { imm = (ctx->opcode >> 16) & 0x03FF; + imm = (int16_t)(imm << 6) >> 6; tcg_gen_movi_tl(cpu_gpr[ret], \ (target_long)((int32_t)imm << 16 | \ - (uint32_t)(uint16_t)imm)); + (uint16_t)imm)); } break; case OPC_REPLV_PH: diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 88650d4ae4..436ca474ff 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -99,8 +99,10 @@ int kvm_arch_init(KVMState *s) return 0; } -static int kvm_arch_sync_sregs(CPUPPCState *cenv) +static int kvm_arch_sync_sregs(PowerPCCPU *cpu) { + CPUPPCState *cenv = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_sregs sregs; int ret; @@ -117,18 +119,20 @@ static int kvm_arch_sync_sregs(CPUPPCState *cenv) } } - ret = kvm_vcpu_ioctl(cenv, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret) { return ret; } sregs.pvr = cenv->spr[SPR_PVR]; - return kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs); + return kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs); } /* Set up a shared TLB array with KVM */ -static int kvm_booke206_tlb_init(CPUPPCState *env) +static int kvm_booke206_tlb_init(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_book3e_206_tlb_params params = {}; struct kvm_config_tlb cfg = {}; struct kvm_enable_cap encap = {}; @@ -136,7 +140,7 @@ static int kvm_booke206_tlb_init(CPUPPCState *env) int ret, i; if (!kvm_enabled() || - !kvm_check_extension(env->kvm_state, KVM_CAP_SW_TLB)) { + !kvm_check_extension(cs->kvm_state, KVM_CAP_SW_TLB)) { return 0; } @@ -161,7 +165,7 @@ static int kvm_booke206_tlb_init(CPUPPCState *env) encap.cap = KVM_CAP_SW_TLB; encap.args[0] = (uintptr_t)&cfg; - ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &encap); + ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap); if (ret < 0) { fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n", __func__, strerror(-ret)); @@ -174,9 +178,12 @@ static int kvm_booke206_tlb_init(CPUPPCState *env) #if defined(TARGET_PPC64) -static void kvm_get_fallback_smmu_info(CPUPPCState *env, +static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu, struct kvm_ppc_smmu_info *info) { + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); + memset(info, 0, sizeof(*info)); /* We don't have the new KVM_PPC_GET_SMMU_INFO ioctl, so @@ -202,7 +209,7 @@ static void kvm_get_fallback_smmu_info(CPUPPCState *env, * implements KVM_CAP_PPC_GET_SMMU_INFO and thus doesn't hit * this fallback. */ - if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO)) { /* No flags */ info->flags = 0; info->slb_size = 64; @@ -258,18 +265,19 @@ static void kvm_get_fallback_smmu_info(CPUPPCState *env, } } -static void kvm_get_smmu_info(CPUPPCState *env, struct kvm_ppc_smmu_info *info) +static void kvm_get_smmu_info(PowerPCCPU *cpu, struct kvm_ppc_smmu_info *info) { + CPUState *cs = CPU(cpu); int ret; - if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_SMMU_INFO)) { - ret = kvm_vm_ioctl(env->kvm_state, KVM_PPC_GET_SMMU_INFO, info); + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_SMMU_INFO)) { + ret = kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_SMMU_INFO, info); if (ret == 0) { return; } } - kvm_get_fallback_smmu_info(env, info); + kvm_get_fallback_smmu_info(cpu, info); } static long getrampagesize(void) @@ -312,10 +320,11 @@ static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift) return (1ul << shift) <= rampgsize; } -static void kvm_fixup_page_sizes(CPUPPCState *env) +static void kvm_fixup_page_sizes(PowerPCCPU *cpu) { static struct kvm_ppc_smmu_info smmu_info; static bool has_smmu_info; + CPUPPCState *env = &cpu->env; long rampagesize; int iq, ik, jq, jk; @@ -326,7 +335,7 @@ static void kvm_fixup_page_sizes(CPUPPCState *env) /* Collect MMU info from kernel if not already */ if (!has_smmu_info) { - kvm_get_smmu_info(env, &smmu_info); + kvm_get_smmu_info(cpu, &smmu_info); has_smmu_info = true; } @@ -369,22 +378,23 @@ static void kvm_fixup_page_sizes(CPUPPCState *env) } #else /* defined (TARGET_PPC64) */ -static inline void kvm_fixup_page_sizes(CPUPPCState *env) +static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu) { } #endif /* !defined (TARGET_PPC64) */ -int kvm_arch_init_vcpu(CPUPPCState *cenv) +int kvm_arch_init_vcpu(CPUState *cs) { - PowerPCCPU *cpu = ppc_env_get_cpu(cenv); + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *cenv = &cpu->env; int ret; /* Gather server mmu info from KVM and update the CPU state */ - kvm_fixup_page_sizes(cenv); + kvm_fixup_page_sizes(cpu); /* Synchronize sregs with kvm */ - ret = kvm_arch_sync_sregs(cenv); + ret = kvm_arch_sync_sregs(cpu); if (ret) { return ret; } @@ -394,7 +404,7 @@ int kvm_arch_init_vcpu(CPUPPCState *cenv) /* Some targets support access to KVM's guest TLB. */ switch (cenv->mmu_model) { case POWERPC_MMU_BOOKE206: - ret = kvm_booke206_tlb_init(cenv); + ret = kvm_booke206_tlb_init(cpu); break; default: break; @@ -403,12 +413,14 @@ int kvm_arch_init_vcpu(CPUPPCState *cenv) return ret; } -void kvm_arch_reset_vcpu(CPUPPCState *env) +void kvm_arch_reset_vcpu(CPUState *cpu) { } -static void kvm_sw_tlb_put(CPUPPCState *env) +static void kvm_sw_tlb_put(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_dirty_tlb dirty_tlb; unsigned char *bitmap; int ret; @@ -423,7 +435,7 @@ static void kvm_sw_tlb_put(CPUPPCState *env) dirty_tlb.bitmap = (uintptr_t)bitmap; dirty_tlb.num_dirty = env->nb_tlb; - ret = kvm_vcpu_ioctl(env, KVM_DIRTY_TLB, &dirty_tlb); + ret = kvm_vcpu_ioctl(cs, KVM_DIRTY_TLB, &dirty_tlb); if (ret) { fprintf(stderr, "%s: KVM_DIRTY_TLB: %s\n", __func__, strerror(-ret)); @@ -432,15 +444,18 @@ static void kvm_sw_tlb_put(CPUPPCState *env) g_free(bitmap); } -int kvm_arch_put_registers(CPUPPCState *env, int level) +int kvm_arch_put_registers(CPUState *cs, int level) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; struct kvm_regs regs; int ret; int i; - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); - if (ret < 0) + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); + if (ret < 0) { return ret; + } regs.ctr = env->ctr; regs.lr = env->lr; @@ -465,12 +480,12 @@ int kvm_arch_put_registers(CPUPPCState *env, int level) for (i = 0;i < 32; i++) regs.gpr[i] = env->gpr[i]; - ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); if (ret < 0) return ret; if (env->tlb_dirty) { - kvm_sw_tlb_put(env); + kvm_sw_tlb_put(cpu); env->tlb_dirty = false; } @@ -503,7 +518,7 @@ int kvm_arch_put_registers(CPUPPCState *env, int level) | env->IBAT[1][i]; } - ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs); if (ret) { return ret; } @@ -516,7 +531,7 @@ int kvm_arch_put_registers(CPUPPCState *env, int level) .addr = (uintptr_t) &hior, }; - ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret) { return ret; } @@ -525,14 +540,16 @@ int kvm_arch_put_registers(CPUPPCState *env, int level) return ret; } -int kvm_arch_get_registers(CPUPPCState *env) +int kvm_arch_get_registers(CPUState *cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; struct kvm_regs regs; struct kvm_sregs sregs; uint32_t cr; int i, ret; - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); if (ret < 0) return ret; @@ -566,7 +583,7 @@ int kvm_arch_get_registers(CPUPPCState *env) env->gpr[i] = regs.gpr[i]; if (cap_booke_sregs) { - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -670,7 +687,7 @@ int kvm_arch_get_registers(CPUPPCState *env) } if (cap_segstate) { - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -702,7 +719,7 @@ int kvm_arch_get_registers(CPUPPCState *env) return 0; } -int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) +int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level) { unsigned virq = level ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; @@ -714,7 +731,7 @@ int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) return 0; } - kvm_vcpu_ioctl(env, KVM_INTERRUPT, &virq); + kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq); return 0; } @@ -727,8 +744,10 @@ int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) #define PPC_INPUT_INT PPC6xx_INPUT_INT #endif -void kvm_arch_pre_run(CPUPPCState *env, struct kvm_run *run) +void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; int r; unsigned irq; @@ -746,7 +765,7 @@ void kvm_arch_pre_run(CPUPPCState *env, struct kvm_run *run) irq = KVM_INTERRUPT_SET; dprintf("injected interrupt %d\n", irq); - r = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &irq); + r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &irq); if (r < 0) printf("cpu %d fail inject %x\n", env->cpu_index, irq); @@ -760,13 +779,14 @@ void kvm_arch_pre_run(CPUPPCState *env, struct kvm_run *run) * anyways, so we will get a chance to deliver the rest. */ } -void kvm_arch_post_run(CPUPPCState *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) { } -int kvm_arch_process_async_events(CPUPPCState *env) +int kvm_arch_process_async_events(CPUState *cs) { - return env->halted; + PowerPCCPU *cpu = POWERPC_CPU(cs); + return cpu->env.halted; } static int kvmppc_handle_halt(CPUPPCState *env) @@ -796,8 +816,10 @@ static int kvmppc_handle_dcr_write(CPUPPCState *env, uint32_t dcrn, uint32_t dat return 0; } -int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run) +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; int ret; switch (run->exit_reason) { @@ -817,7 +839,7 @@ int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run) #ifdef CONFIG_PSERIES case KVM_EXIT_PAPR_HCALL: dprintf("handle PAPR hypercall\n"); - run->papr_hcall.ret = spapr_hypercall(ppc_env_get_cpu(env), + run->papr_hcall.ret = spapr_hypercall(cpu, run->papr_hcall.nr, run->papr_hcall.args); ret = 0; @@ -969,12 +991,14 @@ uint32_t kvmppc_get_dfp(void) int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs = CPU(cpu); uint32_t *hc = (uint32_t*)buf; struct kvm_ppc_pvinfo pvinfo; - if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO) && - !kvm_vm_ioctl(env->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) { + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) && + !kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) { memcpy(buf, pvinfo.hcall, buf_len); return 0; @@ -997,13 +1021,15 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) return 0; } -void kvmppc_set_papr(CPUPPCState *env) +void kvmppc_set_papr(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_enable_cap cap = {}; int ret; cap.cap = KVM_CAP_PPC_PAPR; - ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap); + ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap); if (ret) { cpu_abort(env, "This KVM version does not support PAPR\n"); @@ -1225,12 +1251,12 @@ int kvmppc_fixup_cpu(CPUPPCState *env) } -bool kvm_arch_stop_on_emulation_error(CPUPPCState *env) +bool kvm_arch_stop_on_emulation_error(CPUState *cpu) { return true; } -int kvm_arch_on_sigbus_vcpu(CPUPPCState *env, int code, void *addr) +int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { return 1; } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 83f98729a2..31eb9e6f22 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -20,8 +20,8 @@ uint64_t kvmppc_get_clockfreq(void); uint32_t kvmppc_get_vmx(void); uint32_t kvmppc_get_dfp(void); int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); -int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level); -void kvmppc_set_papr(CPUPPCState *env); +int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); +void kvmppc_set_papr(PowerPCCPU *cpu); int kvmppc_smt_threads(void); #ifndef CONFIG_USER_ONLY off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); @@ -65,12 +65,12 @@ static inline int kvmppc_read_segment_page_sizes(uint32_t *prop, int maxcells) return -1; } -static inline int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) +static inline int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level) { return -1; } -static inline void kvmppc_set_papr(CPUPPCState *env) +static inline void kvmppc_set_papr(PowerPCCPU *cpu) { } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index dda0b9af66..cd565c91de 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -296,21 +296,21 @@ void s390x_cpu_timer(void *opaque); int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall); #ifdef CONFIG_KVM -void kvm_s390_interrupt(CPUS390XState *env, int type, uint32_t code); -void kvm_s390_virtio_irq(CPUS390XState *env, int config_change, uint64_t token); -void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, +void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code); +void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token); +void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm); #else -static inline void kvm_s390_interrupt(CPUS390XState *env, int type, uint32_t code) +static inline void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code) { } -static inline void kvm_s390_virtio_irq(CPUS390XState *env, int config_change, +static inline void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) { } -static inline void kvm_s390_interrupt_internal(CPUS390XState *env, int type, +static inline void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm) { diff --git a/target-s390x/interrupt.c b/target-s390x/interrupt.c index 6c0024b426..e51519dbd7 100644 --- a/target-s390x/interrupt.c +++ b/target-s390x/interrupt.c @@ -19,7 +19,8 @@ void s390_sclp_extint(uint32_t parm) if (kvm_enabled()) { #ifdef CONFIG_KVM - kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE, parm, 0, 1); + kvm_s390_interrupt_internal(dummy_cpu, KVM_S390_INT_SERVICE, parm, + 0, 1); #endif } else { env->psw.addr += 4; diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 762231d845..6ec5e6d8a6 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -72,43 +72,45 @@ int kvm_arch_init(KVMState *s) return 0; } -int kvm_arch_init_vcpu(CPUS390XState *env) +int kvm_arch_init_vcpu(CPUState *cpu) { int ret = 0; - if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) { + if (kvm_vcpu_ioctl(cpu, KVM_S390_INITIAL_RESET, NULL) < 0) { perror("cannot init reset vcpu"); } return ret; } -void kvm_arch_reset_vcpu(CPUS390XState *env) +void kvm_arch_reset_vcpu(CPUState *cpu) { /* FIXME: add code to reset vcpu. */ } -int kvm_arch_put_registers(CPUS390XState *env, int level) +int kvm_arch_put_registers(CPUState *cs, int level) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; struct kvm_sregs sregs; struct kvm_regs regs; int ret; int i; /* always save the PSW and the GPRS*/ - env->kvm_run->psw_addr = env->psw.addr; - env->kvm_run->psw_mask = env->psw.mask; + cs->kvm_run->psw_addr = env->psw.addr; + cs->kvm_run->psw_mask = env->psw.mask; - if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { + if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { for (i = 0; i < 16; i++) { - env->kvm_run->s.regs.gprs[i] = env->regs[i]; - env->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS; + cs->kvm_run->s.regs.gprs[i] = env->regs[i]; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS; } } else { for (i = 0; i < 16; i++) { regs.gprs[i] = env->regs[i]; } - ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); if (ret < 0) { return ret; } @@ -120,53 +122,55 @@ int kvm_arch_put_registers(CPUS390XState *env, int level) } if (cap_sync_regs && - env->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && - env->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { + cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && + cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { for (i = 0; i < 16; i++) { - env->kvm_run->s.regs.acrs[i] = env->aregs[i]; - env->kvm_run->s.regs.crs[i] = env->cregs[i]; + cs->kvm_run->s.regs.acrs[i] = env->aregs[i]; + cs->kvm_run->s.regs.crs[i] = env->cregs[i]; } - env->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS; - env->kvm_run->kvm_dirty_regs |= KVM_SYNC_CRS; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_CRS; } else { for (i = 0; i < 16; i++) { sregs.acrs[i] = env->aregs[i]; sregs.crs[i] = env->cregs[i]; } - ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs); if (ret < 0) { return ret; } } /* Finally the prefix */ - if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { - env->kvm_run->s.regs.prefix = env->psa; - env->kvm_run->kvm_dirty_regs |= KVM_SYNC_PREFIX; + if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { + cs->kvm_run->s.regs.prefix = env->psa; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_PREFIX; } else { /* prefix is only supported via sync regs */ } return 0; } -int kvm_arch_get_registers(CPUS390XState *env) +int kvm_arch_get_registers(CPUState *cs) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; struct kvm_sregs sregs; struct kvm_regs regs; int ret; int i; /* get the PSW */ - env->psw.addr = env->kvm_run->psw_addr; - env->psw.mask = env->kvm_run->psw_mask; + env->psw.addr = cs->kvm_run->psw_addr; + env->psw.mask = cs->kvm_run->psw_mask; /* the GPRS */ - if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { + if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { for (i = 0; i < 16; i++) { - env->regs[i] = env->kvm_run->s.regs.gprs[i]; + env->regs[i] = cs->kvm_run->s.regs.gprs[i]; } } else { - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); if (ret < 0) { return ret; } @@ -177,14 +181,14 @@ int kvm_arch_get_registers(CPUS390XState *env) /* The ACRS and CRS */ if (cap_sync_regs && - env->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && - env->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { + cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && + cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { for (i = 0; i < 16; i++) { - env->aregs[i] = env->kvm_run->s.regs.acrs[i]; - env->cregs[i] = env->kvm_run->s.regs.crs[i]; + env->aregs[i] = cs->kvm_run->s.regs.acrs[i]; + env->cregs[i] = cs->kvm_run->s.regs.crs[i]; } } else { - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -195,8 +199,8 @@ int kvm_arch_get_registers(CPUS390XState *env) } /* Finally the prefix */ - if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { - env->psa = env->kvm_run->s.regs.prefix; + if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { + env->psa = cs->kvm_run->s.regs.prefix; } else { /* no prefix without sync regs */ } @@ -239,8 +243,10 @@ void *kvm_arch_vmalloc(ram_addr_t size) } } -int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp) +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || @@ -250,8 +256,10 @@ int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint * return 0; } -int kvm_arch_remove_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp) +int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; uint8_t t[4]; static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; @@ -266,26 +274,28 @@ int kvm_arch_remove_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint * return 0; } -void kvm_arch_pre_run(CPUS390XState *env, struct kvm_run *run) +void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) { } -void kvm_arch_post_run(CPUS390XState *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) { } -int kvm_arch_process_async_events(CPUS390XState *env) +int kvm_arch_process_async_events(CPUState *cs) { - return env->halted; + S390CPU *cpu = S390_CPU(cs); + return cpu->env.halted; } -void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, +void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm) { + CPUState *cs = CPU(cpu); struct kvm_s390_interrupt kvmint; int r; - if (!env->kvm_state) { + if (!cs->kvm_state) { return; } @@ -294,9 +304,9 @@ void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, kvmint.parm64 = parm64; if (vm) { - r = kvm_vm_ioctl(env->kvm_state, KVM_S390_INTERRUPT, &kvmint); + r = kvm_vm_ioctl(cs->kvm_state, KVM_S390_INTERRUPT, &kvmint); } else { - r = kvm_vcpu_ioctl(env, KVM_S390_INTERRUPT, &kvmint); + r = kvm_vcpu_ioctl(cs, KVM_S390_INTERRUPT, &kvmint); } if (r < 0) { @@ -305,34 +315,38 @@ void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, } } -void kvm_s390_virtio_irq(CPUS390XState *env, int config_change, uint64_t token) +void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) { - kvm_s390_interrupt_internal(env, KVM_S390_INT_VIRTIO, config_change, + kvm_s390_interrupt_internal(cpu, KVM_S390_INT_VIRTIO, config_change, token, 1); } -void kvm_s390_interrupt(CPUS390XState *env, int type, uint32_t code) +void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code) { - kvm_s390_interrupt_internal(env, type, code, 0, 0); + kvm_s390_interrupt_internal(cpu, type, code, 0, 0); } -static void enter_pgmcheck(CPUS390XState *env, uint16_t code) +static void enter_pgmcheck(S390CPU *cpu, uint16_t code) { - kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); + kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code); } -static inline void setcc(CPUS390XState *env, uint64_t cc) +static inline void setcc(S390CPU *cpu, uint64_t cc) { - env->kvm_run->psw_mask &= ~(3ull << 44); - env->kvm_run->psw_mask |= (cc & 3) << 44; + CPUS390XState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + cs->kvm_run->psw_mask &= ~(3ull << 44); + cs->kvm_run->psw_mask |= (cc & 3) << 44; env->psw.mask &= ~(3ul << 44); env->psw.mask |= (cc & 3) << 44; } -static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run, +static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, uint16_t ipbh0) { + CPUS390XState *env = &cpu->env; uint32_t sccb; uint64_t code; int r = 0; @@ -343,14 +357,14 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run, r = sclp_service_call(sccb, code); if (r < 0) { - enter_pgmcheck(env, -r); + enter_pgmcheck(cpu, -r); } - setcc(env, r); + setcc(cpu, r); return 0; } -static int handle_priv(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) +static int handle_priv(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { int r = 0; uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16; @@ -358,7 +372,7 @@ static int handle_priv(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) dprintf("KVM: PRIV: %d\n", ipa1); switch (ipa1) { case PRIV_SCLP_CALL: - r = kvm_sclp_service_call(env, run, ipbh0); + r = kvm_sclp_service_call(cpu, run, ipbh0); break; default: dprintf("KVM: unknown PRIV: 0x%x\n", ipa1); @@ -401,7 +415,7 @@ static int s390_cpu_restart(S390CPU *cpu) { CPUS390XState *env = &cpu->env; - kvm_s390_interrupt(env, KVM_S390_RESTART, 0); + kvm_s390_interrupt(cpu, KVM_S390_RESTART, 0); s390_add_running_cpu(env); qemu_cpu_kick(CPU(cpu)); dprintf("DONE: SIGP cpu restart: %p\n", env); @@ -415,12 +429,13 @@ static int s390_store_status(CPUS390XState *env, uint32_t parameter) return -1; } -static int s390_cpu_initial_reset(CPUS390XState *env) +static int s390_cpu_initial_reset(S390CPU *cpu) { + CPUS390XState *env = &cpu->env; int i; s390_del_running_cpu(env); - if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) { + if (kvm_vcpu_ioctl(CPU(cpu), KVM_S390_INITIAL_RESET, NULL) < 0) { perror("cannot init reset vcpu"); } @@ -434,8 +449,9 @@ static int s390_cpu_initial_reset(CPUS390XState *env) return 0; } -static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) +static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { + CPUS390XState *env = &cpu->env; uint8_t order_code; uint32_t parameter; uint16_t cpu_addr; @@ -479,7 +495,7 @@ static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) /* make the caller panic */ return -1; case SIGP_INITIAL_CPU_RESET: - r = s390_cpu_initial_reset(target_env); + r = s390_cpu_initial_reset(target_cpu); break; default: fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", order_code); @@ -487,12 +503,13 @@ static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) } out: - setcc(env, r ? 3 : 0); + setcc(cpu, r ? 3 : 0); return 0; } -static int handle_instruction(CPUS390XState *env, struct kvm_run *run) +static int handle_instruction(S390CPU *cpu, struct kvm_run *run) { + CPUS390XState *env = &cpu->env; unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00); uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff; int ipb_code = (run->s390_sieic.ipb & 0x0fff0000) >> 16; @@ -501,43 +518,45 @@ static int handle_instruction(CPUS390XState *env, struct kvm_run *run) dprintf("handle_instruction 0x%x 0x%x\n", run->s390_sieic.ipa, run->s390_sieic.ipb); switch (ipa0) { case IPA0_PRIV: - r = handle_priv(env, run, ipa1); + r = handle_priv(cpu, run, ipa1); break; case IPA0_DIAG: r = handle_diag(env, run, ipb_code); break; case IPA0_SIGP: - r = handle_sigp(env, run, ipa1); + r = handle_sigp(cpu, run, ipa1); break; } if (r < 0) { - enter_pgmcheck(env, 0x0001); + enter_pgmcheck(cpu, 0x0001); } return 0; } -static bool is_special_wait_psw(CPUS390XState *env) +static bool is_special_wait_psw(CPUState *cs) { /* signal quiesce */ - return env->kvm_run->psw_addr == 0xfffUL; + return cs->kvm_run->psw_addr == 0xfffUL; } -static int handle_intercept(CPUS390XState *env) +static int handle_intercept(S390CPU *cpu) { - struct kvm_run *run = env->kvm_run; + CPUS390XState *env = &cpu->env; + CPUState *cs = CPU(cpu); + struct kvm_run *run = cs->kvm_run; int icpt_code = run->s390_sieic.icptcode; int r = 0; dprintf("intercept: 0x%x (at 0x%lx)\n", icpt_code, - (long)env->kvm_run->psw_addr); + (long)cs->kvm_run->psw_addr); switch (icpt_code) { case ICPT_INSTRUCTION: - r = handle_instruction(env, run); + r = handle_instruction(cpu, run); break; case ICPT_WAITPSW: if (s390_del_running_cpu(env) == 0 && - is_special_wait_psw(env)) { + is_special_wait_psw(cs)) { qemu_system_shutdown_request(); } r = EXCP_HALTED; @@ -565,13 +584,14 @@ static int handle_intercept(CPUS390XState *env) return r; } -int kvm_arch_handle_exit(CPUS390XState *env, struct kvm_run *run) +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { + S390CPU *cpu = S390_CPU(cs); int ret = 0; switch (run->exit_reason) { case KVM_EXIT_S390_SIEIC: - ret = handle_intercept(env); + ret = handle_intercept(cpu); break; case KVM_EXIT_S390_RESET: qemu_system_reset_request(); @@ -587,12 +607,12 @@ int kvm_arch_handle_exit(CPUS390XState *env, struct kvm_run *run) return ret; } -bool kvm_arch_stop_on_emulation_error(CPUS390XState *env) +bool kvm_arch_stop_on_emulation_error(CPUState *cpu) { return true; } -int kvm_arch_on_sigbus_vcpu(CPUS390XState *env, int code, void *addr) +int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { return 1; } diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index e521ed55cc..70f9739685 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -57,7 +57,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) if (kvm_enabled()) { #ifdef CONFIG_KVM - kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); + kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code); #endif } else { env->int_pgm_code = code; diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index ff4f628404..5359538ea5 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -13,7 +13,9 @@ #include "exec/gdbstub.h" #include "helper.h" #include "qemu/host-utils.h" +#ifndef CONFIG_USER_ONLY #include "ui/console.h" +#endif #undef DEBUG_UC32 diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 0a037291ef..7029ac4814 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -3005,7 +3005,11 @@ static void gen_intermediate_code_internal( gen_icount_end(tb, insn_count); *tcg_ctx.gen_opc_ptr = INDEX_op_end; - if (!search_pc) { + if (search_pc) { + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; + memset(tcg_ctx.gen_opc_instr_start + lj + 1, 0, + (j - lj) * sizeof(tcg_ctx.gen_opc_instr_start[0])); + } else { tb->size = dc.pc - pc_start; tb->icount = insn_count; } diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index 5b27cf6f12..656e73621a 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -824,7 +824,7 @@ static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah, tcg_out_brcond(s, TCG_COND_EQ, ah, bh, bhconst, label_index); break; case TCG_COND_NE: - tcg_out_brcond(s, TCG_COND_NE, al, bl, bhconst, label_index); + tcg_out_brcond(s, TCG_COND_NE, al, bl, blconst, label_index); tcg_out_brcond(s, TCG_COND_NE, ah, bh, bhconst, label_index); break; default: diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index ae8274652a..e0838748a9 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -97,6 +97,18 @@ static const int tcg_target_call_oarg_regs[] = { # define TCG_REG_L1 TCG_REG_EDX #endif +/* For 32-bit, we are going to attempt to determine at runtime whether cmov + is available. However, the host compiler must supply <cpuid.h>, as we're + not going to go so far as our own inline assembly. */ +#if TCG_TARGET_REG_BITS == 64 +# define have_cmov 1 +#elif defined(CONFIG_CPUID_H) +#include <cpuid.h> +static bool have_cmov; +#else +# define have_cmov 0 +#endif + static uint8_t *tb_ret_addr; static void patch_reloc(uint8_t *code_ptr, int type, @@ -943,7 +955,14 @@ static void tcg_out_movcond32(TCGContext *s, TCGCond cond, TCGArg dest, TCGArg v1) { tcg_out_cmp(s, c1, c2, const_c2, 0); - tcg_out_modrm(s, OPC_CMOVCC | tcg_cond_to_jcc[cond], dest, v1); + if (have_cmov) { + tcg_out_modrm(s, OPC_CMOVCC | tcg_cond_to_jcc[cond], dest, v1); + } else { + int over = gen_new_label(); + tcg_out_jxx(s, tcg_cond_to_jcc[tcg_invert_cond(cond)], over, 1); + tcg_out_mov(s, TCG_TYPE_I32, dest, v1); + tcg_out_label(s, over, s->code_ptr); + } } #if TCG_TARGET_REG_BITS == 64 @@ -2243,6 +2262,16 @@ static void tcg_target_qemu_prologue(TCGContext *s) static void tcg_target_init(TCGContext *s) { + /* For 32-bit, 99% certainty that we're running on hardware that supports + cmov, but we still need to check. In case cmov is not available, we'll + use a small forward branch. */ +#ifndef have_cmov + { + unsigned a, b, c, d; + have_cmov = (__get_cpuid(1, &a, &b, &c, &d) && (d & bit_CMOV)); + } +#endif + #if !defined(CONFIG_USER_ONLY) /* fail safe */ if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 5352ac0254..e63db9cfe9 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -91,12 +91,7 @@ typedef enum { #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 1 -#if defined(__x86_64__) || defined(__i686__) -/* Use cmov only if the compiler is already doing so. */ #define TCG_TARGET_HAS_movcond_i32 1 -#else -#define TCG_TARGET_HAS_movcond_i32 0 -#endif #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 1 diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 0b3cb0be3a..91c9d80dd5 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -2329,6 +2329,7 @@ static inline void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, #define tcg_gen_qemu_ldst_op tcg_gen_op3i_i32 #define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i32 #define TCGV_UNUSED(x) TCGV_UNUSED_I32(x) +#define TCGV_IS_UNUSED(x) TCGV_IS_UNUSED_I32(x) #define TCGV_EQUAL(a, b) TCGV_EQUAL_I32(a, b) #else #define TCGv TCGv_i64 @@ -2340,6 +2341,7 @@ static inline void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, #define tcg_gen_qemu_ldst_op tcg_gen_op3i_i64 #define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i64 #define TCGV_UNUSED(x) TCGV_UNUSED_I64(x) +#define TCGV_IS_UNUSED(x) TCGV_IS_UNUSED_I64(x) #define TCGV_EQUAL(a, b) TCGV_EQUAL_I64(a, b) #endif diff --git a/tcg/tcg.h b/tcg/tcg.h index b2e2a25653..a4279725a6 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -270,6 +270,9 @@ typedef int TCGv_i64; #define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1) #define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1) +#define TCGV_IS_UNUSED_I32(x) (GET_TCGV_I32(x) == -1) +#define TCGV_IS_UNUSED_I64(x) (GET_TCGV_I64(x) == -1) + /* call flags */ /* Helper does not read globals (either directly or through an exception). It implies TCG_CALL_NO_WRITE_GLOBALS. */ diff --git a/tests/tcg/mips/mips32-dsp/extr_r_w.c b/tests/tcg/mips/mips32-dsp/extr_r_w.c index 0beeefd366..02e022427a 100644 --- a/tests/tcg/mips/mips32-dsp/extr_r_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_r_w.c @@ -44,5 +44,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_r.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extr_rs_w.c b/tests/tcg/mips/mips32-dsp/extr_rs_w.c index 24c748db20..c3a22ee704 100644 --- a/tests/tcg/mips/mips32-dsp/extr_rs_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_rs_w.c @@ -44,5 +44,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_rs.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extr_s_h.c b/tests/tcg/mips/mips32-dsp/extr_s_h.c index b2129134c8..9bc2a63cc2 100644 --- a/tests/tcg/mips/mips32-dsp/extr_s_h.c +++ b/tests/tcg/mips/mips32-dsp/extr_s_h.c @@ -59,5 +59,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dsp */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x123; + acl = 0x87654321; + result = 0x1238; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_s.h %0, $ac1, 28\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extr_w.c b/tests/tcg/mips/mips32-dsp/extr_w.c index 02ab9ecaae..bd6b0b95c2 100644 --- a/tests/tcg/mips/mips32-dsp/extr_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_w.c @@ -44,5 +44,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extrv_r_w.c b/tests/tcg/mips/mips32-dsp/extrv_r_w.c index 005807b142..2403b3afe4 100644 --- a/tests/tcg/mips/mips32-dsp/extrv_r_w.c +++ b/tests/tcg/mips/mips32-dsp/extrv_r_w.c @@ -50,5 +50,30 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + rs = 31; + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("wrdsp %1, 0x01\n\t" + "mthi %3, $ac1\n\t" + "mtlo %4, $ac1\n\t" + "extrv_r.w %0, $ac1, %2\n\t" + "rddsp %1\n\t" + : "=r"(rt), "+r"(dsp) + : "r"(rs), "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extrv_rs_w.c b/tests/tcg/mips/mips32-dsp/extrv_rs_w.c index c2d8513bb6..ccceeb9f4c 100644 --- a/tests/tcg/mips/mips32-dsp/extrv_rs_w.c +++ b/tests/tcg/mips/mips32-dsp/extrv_rs_w.c @@ -48,5 +48,30 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + rs = 0x1F; + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("wrdsp %1, 0x01\n\t" + "mthi %3, $ac1\n\t" + "mtlo %4, $ac1\n\t" + "extrv_rs.w %0, $ac1, %2\n\t" + "rddsp %1\n\t" + : "=r"(rt), "+r"(dsp) + : "r"(rs), "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extrv_s_h.c b/tests/tcg/mips/mips32-dsp/extrv_s_h.c index 8c13b5eda5..feac3e2e33 100644 --- a/tests/tcg/mips/mips32-dsp/extrv_s_h.c +++ b/tests/tcg/mips/mips32-dsp/extrv_s_h.c @@ -67,5 +67,22 @@ int main() assert(dsp == 0); assert(result == rt); + rs = 0x1C; + ach = 0x123; + acl = 0x87654321; + result = 0x1238; + __asm + ("wrdsp %1, 0x01\n\t" + "mthi %3, $ac1\n\t" + "mtlo %4, $ac1\n\t" + "extrv_s.h %0, $ac1, %2\n\t" + "rddsp %1\n\t" + : "=r"(rt), "+r"(dsp) + : "r"(rs), "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extrv_w.c b/tests/tcg/mips/mips32-dsp/extrv_w.c index 9cb493df39..9e8b238a04 100644 --- a/tests/tcg/mips/mips32-dsp/extrv_w.c +++ b/tests/tcg/mips/mips32-dsp/extrv_w.c @@ -50,5 +50,31 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + rs = 31; + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("wrdsp %1, 0x01\n\t" + "mthi %3, $ac1\n\t" + "mtlo %4, $ac1\n\t" + "extrv.w %0, $ac1, %2\n\t" + "rddsp %1\n\t" + : "=r"(rt), "+r"(dsp) + : "r"(rs), "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/rddsp.c b/tests/tcg/mips/mips32-dsp/rddsp.c index e8948ec1d9..2f30285033 100644 --- a/tests/tcg/mips/mips32-dsp/rddsp.c +++ b/tests/tcg/mips/mips32-dsp/rddsp.c @@ -6,14 +6,13 @@ int main() int dsp_i, dsp_o; int ccond_i, outflag_i, efi_i, c_i, scount_i, pos_i; int ccond_o, outflag_o, efi_o, c_o, scount_o, pos_o; - int ccond_r, outflag_r, efi_r, c_r, scount_r, pos_r; - ccond_i = 0x000000BC;/* 4 */ - outflag_i = 0x0000001B;/* 3 */ - efi_i = 0x00000001;/* 5 */ - c_i = 0x00000001;/* 2 */ - scount_i = 0x0000000F;/* 1 */ - pos_i = 0x0000000C;/* 0 */ + ccond_i = 0x0000000C; /* 4 */ + outflag_i = 0x0000001B; /* 3 */ + efi_i = 0x00000001; /* 5 */ + c_i = 0x00000001; /* 2 */ + scount_i = 0x0000000F; /* 1 */ + pos_i = 0x0000000C; /* 0 */ dsp_i = (ccond_i << 24) | \ (outflag_i << 16) | \ @@ -22,13 +21,6 @@ int main() (scount_i << 7) | \ pos_i; - ccond_r = ccond_i; - outflag_r = outflag_i; - efi_r = efi_i; - c_r = c_i; - scount_r = scount_i; - pos_r = pos_i; - __asm ("wrdsp %1, 0x3F\n\t" "rddsp %0, 0x3F\n\t" @@ -43,12 +35,12 @@ int main() scount_o = (dsp_o >> 7) & 0x3F; pos_o = dsp_o & 0x1F; - assert(ccond_o == ccond_r); - assert(outflag_o == outflag_r); - assert(efi_o == efi_r); - assert(c_o == c_r); - assert(scount_o == scount_r); - assert(pos_o == pos_r); + assert(ccond_o == ccond_i); + assert(outflag_o == outflag_i); + assert(efi_o == efi_i); + assert(c_o == c_i); + assert(scount_o == scount_i); + assert(pos_o == pos_i); return 0; } diff --git a/tests/tcg/mips/mips32-dsp/wrdsp.c b/tests/tcg/mips/mips32-dsp/wrdsp.c index e8948ec1d9..dc54943a99 100644 --- a/tests/tcg/mips/mips32-dsp/wrdsp.c +++ b/tests/tcg/mips/mips32-dsp/wrdsp.c @@ -6,14 +6,13 @@ int main() int dsp_i, dsp_o; int ccond_i, outflag_i, efi_i, c_i, scount_i, pos_i; int ccond_o, outflag_o, efi_o, c_o, scount_o, pos_o; - int ccond_r, outflag_r, efi_r, c_r, scount_r, pos_r; - ccond_i = 0x000000BC;/* 4 */ - outflag_i = 0x0000001B;/* 3 */ - efi_i = 0x00000001;/* 5 */ - c_i = 0x00000001;/* 2 */ - scount_i = 0x0000000F;/* 1 */ - pos_i = 0x0000000C;/* 0 */ + ccond_i = 0x000000BC; /* 4 */ + outflag_i = 0x0000001B; /* 3 */ + efi_i = 0x00000001; /* 5 */ + c_i = 0x00000001; /* 2 */ + scount_i = 0x0000000F; /* 1 */ + pos_i = 0x0000000C; /* 0 */ dsp_i = (ccond_i << 24) | \ (outflag_i << 16) | \ @@ -22,13 +21,6 @@ int main() (scount_i << 7) | \ pos_i; - ccond_r = ccond_i; - outflag_r = outflag_i; - efi_r = efi_i; - c_r = c_i; - scount_r = scount_i; - pos_r = pos_i; - __asm ("wrdsp %1, 0x3F\n\t" "rddsp %0, 0x3F\n\t" @@ -43,12 +35,12 @@ int main() scount_o = (dsp_o >> 7) & 0x3F; pos_o = dsp_o & 0x1F; - assert(ccond_o == ccond_r); - assert(outflag_o == outflag_r); - assert(efi_o == efi_r); - assert(c_o == c_r); - assert(scount_o == scount_r); - assert(pos_o == pos_r); + assert(ccond_o == (ccond_i & 0x0F)); + assert(outflag_o == outflag_i); + assert(efi_o == efi_i); + assert(c_o == c_i); + assert(scount_o == scount_i); + assert(pos_o == pos_i); return 0; } diff --git a/trace.h b/trace.h new file mode 100644 index 0000000000..c15f498128 --- /dev/null +++ b/trace.h @@ -0,0 +1,6 @@ +#ifndef TRACE_H +#define TRACE_H + +#include "trace/generated-tracers.h" + +#endif /* TRACE_H */ diff --git a/trace/Makefile.objs b/trace/Makefile.objs new file mode 100644 index 0000000000..b791723696 --- /dev/null +++ b/trace/Makefile.objs @@ -0,0 +1,70 @@ +# -*- mode: makefile -*- + +###################################################################### +# Auto-generated tracing routines + +ifeq ($(TRACE_BACKEND),dtrace) +TRACE_H_EXTRA_DEPS=$(obj)/generated-tracers-dtrace.h +endif +$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp $(TRACE_H_EXTRA_DEPS) +$(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=h \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp +$(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=c \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h + +ifneq ($(TRACE_BACKEND),dtrace) +trace-obj-y += generated-tracers.o +endif + + +###################################################################### +# Auto-generated DTrace code + +# Normal practice is to name DTrace probe file with a '.d' extension +# but that gets picked up by QEMU's Makefile as an external dependency +# rule file. So we use '.dtrace' instead +$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp +$(obj)/generated-tracers-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=d \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-tracers-dtrace.h: trace/generated-tracers-dtrace.dtrace + $(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@") + +$(obj)/generated-tracers-dtrace.o: trace/generated-tracers-dtrace.dtrace + $(call quiet-command,dtrace -o $@ -G -s $<, " GEN $@") + +trace-obj-$(CONFIG_TRACE_DTRACE) += generated-tracers-dtrace.o + + +ifeq ($(LIBTOOL),) +$(obj)/generated-tracers-dtrace.lo: $(obj)/generated-tracers-dtrace.dtrace + @echo "missing libtool. please install and rerun configure."; exit 1 +else +$(obj)/generated-tracers-dtrace.lo: $(obj)/generated-tracers-dtrace.dtrace + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN $@") +endif + + +###################################################################### +# Backend code + +trace-obj-$(CONFIG_TRACE_DEFAULT) += default.o +trace-obj-$(CONFIG_TRACE_SIMPLE) += simple.o +trace-obj-$(CONFIG_TRACE_STDERR) += stderr.o +trace-obj-y += control.o diff --git a/translate-all.c b/translate-all.c index b621748ec0..d367fc4d11 100644 --- a/translate-all.c +++ b/translate-all.c @@ -759,19 +759,17 @@ static void tb_page_check(void) #endif -/* invalidate one TB */ -static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb, - int next_offset) +static inline void tb_hash_remove(TranslationBlock **ptb, TranslationBlock *tb) { TranslationBlock *tb1; for (;;) { tb1 = *ptb; if (tb1 == tb) { - *ptb = *(TranslationBlock **)((char *)tb1 + next_offset); + *ptb = tb1->phys_hash_next; break; } - ptb = (TranslationBlock **)((char *)tb1 + next_offset); + ptb = &tb1->phys_hash_next; } } @@ -828,6 +826,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) tb_set_jmp_target(tb, n, (uintptr_t)(tb->tc_ptr + tb->tb_next_offset[n])); } +/* invalidate one TB */ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) { CPUArchState *env; @@ -839,8 +838,7 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) /* remove the TB from the hash list */ phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); h = tb_phys_hash_func(phys_pc); - tb_remove(&tb_phys_hash[h], tb, - offsetof(TranslationBlock, phys_hash_next)); + tb_hash_remove(&tb_phys_hash[h], tb); /* remove the TB from the page list */ if (tb->page_addr[0] != page_addr) { diff --git a/ui/Makefile.objs b/ui/Makefile.objs index dc8f0e46ad..6768bb7f7e 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -14,6 +14,5 @@ common-obj-$(CONFIG_CURSES) += curses.o common-obj-$(CONFIG_VNC) += $(vnc-obj-y) $(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS) -$(obj)/vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS) $(obj)/cocoa.o: $(SRC_PATH)/$(obj)/cocoa.m diff --git a/xen-all.c b/xen-all.c index 50edaecbf1..19bcfd1510 100644 --- a/xen-all.c +++ b/xen-all.c @@ -16,6 +16,7 @@ #include "hw/xen_backend.h" #include "qmp-commands.h" +#include "char/char.h" #include "qemu/range.h" #include "sysemu/xen-mapcache.h" #include "trace.h" |