diff options
243 files changed, 2927 insertions, 2461 deletions
@@ -148,10 +148,6 @@ endif all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules -vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) - -vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) - config-host.h: config-host.h-timestamp config-host.h-timestamp: config-host.mak qemu-options.def: $(SRC_PATH)/qemu-options.hx @@ -195,8 +191,6 @@ ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS)) recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) -bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) - $(BUILD_DIR)/version.o: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h | $(BUILD_DIR)/version.lo $(call quiet-command,$(WINDRES) -I$(BUILD_DIR) -o $@ $<," RC version.o") $(BUILD_DIR)/version.lo: $(SRC_PATH)/version.rc $(BUILD_DIR)/config-host.h @@ -384,17 +378,25 @@ install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \ install-datadir install-localstatedir $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ifneq ($(TOOLS),) - $(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)" + $(INSTALL_PROG) $(TOOLS) "$(DESTDIR)$(bindir)" +ifneq ($(STRIP),) + $(STRIP) $(TOOLS:%="$(DESTDIR)$(bindir)/%") +endif endif ifneq ($(CONFIG_MODULES),) $(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)" - for s in $(patsubst %.mo,%$(DSOSUF),$(modules-m)); do \ - $(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \ + for s in $(modules-m:.mo=$(DSOSUF)); do \ + t="$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \ + $(INSTALL_LIB) $$s "$$t"; \ + test -z "$(STRIP)" || $(STRIP) "$$t"; \ done endif ifneq ($(HELPERS-y),) $(INSTALL_DIR) "$(DESTDIR)$(libexecdir)" - $(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)" + $(INSTALL_PROG) $(HELPERS-y) "$(DESTDIR)$(libexecdir)" +ifneq ($(STRIP),) + $(STRIP) $(HELPERS-y:%="$(DESTDIR)$(libexecdir)/%") +endif endif ifneq ($(BLOBS),) set -e; for x in $(BLOBS); do \ diff --git a/Makefile.objs b/Makefile.objs index a6e0e2aacc..b897e1dc34 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -31,6 +31,8 @@ libcacard-y += libcacard/vcard_emul_nss.o libcacard-y += libcacard/vcard_emul_type.o libcacard-y += libcacard/card_7816.o libcacard-y += libcacard/vcardt.o +libcacard/vcard_emul_nss.o-cflags := $(NSS_CFLAGS) +libcacard/vcard_emul_nss.o-libs := $(NSS_LIBS) ###################################################################### # Target independent part of system emulation. The long term path is to @@ -64,9 +66,11 @@ common-obj-y += hw/ common-obj-y += ui/ common-obj-y += bt-host.o bt-vhci.o +bt-host.o-cflags := $(BLUEZ_CFLAGS) common-obj-y += dma-helpers.o common-obj-y += vl.o +vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS) common-obj-y += tpm.o common-obj-$(CONFIG_SLIRP) += slirp/ diff --git a/Makefile.target b/Makefile.target index 6d8fde8b9e..9986047545 100644 --- a/Makefile.target +++ b/Makefile.target @@ -16,19 +16,22 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/include ifdef CONFIG_USER_ONLY # user emulator name QEMU_PROG=qemu-$(TARGET_NAME) +QEMU_PROG_BUILD = $(QEMU_PROG) else # system emulator name +QEMU_PROG=qemu-system-$(TARGET_NAME)$(EXESUF) ifneq (,$(findstring -mwindows,$(libs_softmmu))) # Terminate program name with a 'w' because the linker builds a windows executable. QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF) -endif # windows executable -QEMU_PROG=qemu-system-$(TARGET_NAME)$(EXESUF) +$(QEMU_PROG): $(QEMU_PROGW) + $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)") +QEMU_PROG_BUILD = $(QEMU_PROGW) +else +QEMU_PROG_BUILD = $(QEMU_PROG) endif - -PROGS=$(QEMU_PROG) -ifdef QEMU_PROGW -PROGS+=$(QEMU_PROGW) endif + +PROGS=$(QEMU_PROG) $(QEMU_PROGW) STPFILES= config-target.h: config-target.h-timestamp @@ -140,10 +143,7 @@ endif # CONFIG_SOFTMMU %/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS) dummy := $(call unnest-vars,,obj-y) - -# we are making another call to unnest-vars with different vars, protect obj-y, -# it can be overriden in subdir Makefile.objs -obj-y-save := $(obj-y) +all-obj-y := $(obj-y) block-obj-y := common-obj-y := @@ -153,27 +153,16 @@ dummy := $(call unnest-vars,.., \ block-obj-m \ common-obj-y \ common-obj-m) - -# Now restore obj-y -obj-y := $(obj-y-save) - -all-obj-y = $(obj-y) $(common-obj-y) +all-obj-y += $(common-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) ifndef CONFIG_HAIKU LIBS+=-lm endif -ifdef QEMU_PROGW -# The linker builds a windows executable. Make also a console executable. -$(QEMU_PROGW): $(all-obj-y) ../libqemuutil.a ../libqemustub.a +# build either PROG or PROGW +$(QEMU_PROG_BUILD): $(all-obj-y) ../libqemuutil.a ../libqemustub.a $(call LINK,$^) -$(QEMU_PROG): $(QEMU_PROGW) - $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)") -else -$(QEMU_PROG): $(all-obj-y) ../libqemuutil.a ../libqemustub.a - $(call LINK,$^) -endif gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") @@ -194,9 +183,9 @@ endif install: all ifneq ($(PROGS),) - $(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)" + $(INSTALL_PROG) $(PROGS) "$(DESTDIR)$(bindir)" ifneq ($(STRIP),) - $(STRIP) $(patsubst %,"$(DESTDIR)$(bindir)/%",$(PROGS)) + $(STRIP) $(PROGS:%="$(DESTDIR)$(bindir)/%") endif endif ifdef CONFIG_TRACE_SYSTEMTAP diff --git a/arch_init.c b/arch_init.c index 995f56d504..685ba0e268 100644 --- a/arch_init.c +++ b/arch_init.c @@ -560,20 +560,93 @@ static void migration_bitmap_sync(void) } /* - * ram_save_block: Writes a page of memory to the stream f + * ram_save_page: Send the given page to the stream + * + * Returns: Number of bytes written. + */ +static int ram_save_page(QEMUFile *f, RAMBlock* block, ram_addr_t offset, + bool last_stage) +{ + int bytes_sent; + int cont; + ram_addr_t current_addr; + MemoryRegion *mr = block->mr; + uint8_t *p; + int ret; + bool send_async = true; + + 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; + ret = ram_control_save_page(f, block->offset, + offset, TARGET_PAGE_SIZE, &bytes_sent); + + XBZRLE_cache_lock(); + + current_addr = block->offset + offset; + if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { + if (ret != RAM_SAVE_CONTROL_DELAYED) { + if (bytes_sent > 0) { + acct_info.norm_pages++; + } else if (bytes_sent == 0) { + acct_info.dup_pages++; + } + } + } else if (is_zero_range(p, TARGET_PAGE_SIZE)) { + acct_info.dup_pages++; + bytes_sent = save_block_hdr(f, block, offset, cont, + RAM_SAVE_FLAG_COMPRESS); + qemu_put_byte(f, 0); + bytes_sent++; + /* Must let xbzrle know, otherwise a previous (now 0'd) cached + * page would be stale + */ + xbzrle_cache_zero_page(current_addr); + } else if (!ram_bulk_stage && migrate_use_xbzrle()) { + bytes_sent = save_xbzrle_page(f, &p, current_addr, block, + offset, cont, last_stage); + if (!last_stage) { + /* Can't send this cached data async, since the cache page + * might get updated before it gets to the wire + */ + send_async = false; + } + } + + /* XBZRLE overflow or normal page */ + if (bytes_sent == -1) { + bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE); + if (send_async) { + qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE); + } else { + qemu_put_buffer(f, p, TARGET_PAGE_SIZE); + } + bytes_sent += TARGET_PAGE_SIZE; + acct_info.norm_pages++; + } + + XBZRLE_cache_unlock(); + + return bytes_sent; +} + +/* + * ram_find_and_save_block: Finds a page to send and sends it to f * * Returns: The number of bytes written. * 0 means no dirty pages */ -static int ram_save_block(QEMUFile *f, bool last_stage) +static int ram_find_and_save_block(QEMUFile *f, bool last_stage) { RAMBlock *block = last_seen_block; ram_addr_t offset = last_offset; bool complete_round = false; int bytes_sent = 0; MemoryRegion *mr; - ram_addr_t current_addr; if (!block) block = QTAILQ_FIRST(&ram_list.blocks); @@ -594,64 +667,8 @@ static int ram_save_block(QEMUFile *f, bool last_stage) ram_bulk_stage = false; } } else { - int ret; - uint8_t *p; - bool send_async = true; - 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; - ret = ram_control_save_page(f, block->offset, - offset, TARGET_PAGE_SIZE, &bytes_sent); - - XBZRLE_cache_lock(); - - current_addr = block->offset + offset; - if (ret != RAM_SAVE_CONTROL_NOT_SUPP) { - if (ret != RAM_SAVE_CONTROL_DELAYED) { - if (bytes_sent > 0) { - acct_info.norm_pages++; - } else if (bytes_sent == 0) { - acct_info.dup_pages++; - } - } - } else if (is_zero_range(p, TARGET_PAGE_SIZE)) { - acct_info.dup_pages++; - bytes_sent = save_block_hdr(f, block, offset, cont, - RAM_SAVE_FLAG_COMPRESS); - qemu_put_byte(f, 0); - bytes_sent++; - /* Must let xbzrle know, otherwise a previous (now 0'd) cached - * page would be stale - */ - xbzrle_cache_zero_page(current_addr); - } else if (!ram_bulk_stage && migrate_use_xbzrle()) { - bytes_sent = save_xbzrle_page(f, &p, current_addr, block, - offset, cont, last_stage); - if (!last_stage) { - /* Can't send this cached data async, since the cache page - * might get updated before it gets to the wire - */ - send_async = false; - } - } - - /* XBZRLE overflow or normal page */ - if (bytes_sent == -1) { - bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE); - if (send_async) { - qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE); - } else { - qemu_put_buffer(f, p, TARGET_PAGE_SIZE); - } - bytes_sent += TARGET_PAGE_SIZE; - acct_info.norm_pages++; - } + bytes_sent = ram_save_page(f, block, offset, last_stage); - XBZRLE_cache_unlock(); /* if page is unmodified, continue to the next */ if (bytes_sent > 0) { last_sent_block = block; @@ -850,7 +867,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) while ((ret = qemu_file_rate_limit(f)) == 0) { int bytes_sent; - bytes_sent = ram_save_block(f, false); + bytes_sent = ram_find_and_save_block(f, false); /* no more blocks to sent */ if (bytes_sent == 0) { break; @@ -912,7 +929,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) while (true) { int bytes_sent; - bytes_sent = ram_save_block(f, true); + bytes_sent = ram_find_and_save_block(f, true); /* no more blocks to sent */ if (bytes_sent == 0) { break; @@ -946,7 +963,6 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host) { - int ret, rc = 0; unsigned int xh_len; int xh_flags; @@ -971,18 +987,13 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host) qemu_get_buffer(f, xbzrle_decoded_buf, xh_len); /* decode RLE */ - ret = xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host, - TARGET_PAGE_SIZE); - if (ret == -1) { + if (xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host, + TARGET_PAGE_SIZE) == -1) { fprintf(stderr, "Failed to load XBZRLE page - decode error!\n"); - rc = -1; - } else if (ret > TARGET_PAGE_SIZE) { - fprintf(stderr, "Failed to load XBZRLE page - size %d exceeds %d!\n", - ret, TARGET_PAGE_SIZE); - abort(); + return -1; } - return rc; + return 0; } static inline void *host_from_stream_offset(QEMUFile *f, diff --git a/audio/Makefile.objs b/audio/Makefile.objs index d71a877249..26a0ac9507 100644 --- a/audio/Makefile.objs +++ b/audio/Makefile.objs @@ -14,4 +14,4 @@ common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o common-obj-y += wavcapture.o $(obj)/audio.o $(obj)/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS) -$(obj)/sdlaudio.o: QEMU_CFLAGS += $(SDL_CFLAGS) +sdlaudio.o-cflags := $(SDL_CFLAGS) diff --git a/audio/audio.c b/audio/audio.c index fc775110af..9d018e9ded 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1812,8 +1812,7 @@ static const VMStateDescription vmstate_audio = { .name = "audio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_END_OF_LIST() } }; diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 42557d54ea..591ddcf6f3 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -3,6 +3,6 @@ common-obj-$(CONFIG_POSIX) += rng-random.o common-obj-y += msmouse.o common-obj-$(CONFIG_BRLAPI) += baum.o -$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) +baum.o-cflags := $(SDL_CFLAGS) common-obj-$(CONFIG_TPM) += tpm.o @@ -775,6 +775,16 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs) } /* + * Returns the flags that a temporary snapshot should get, based on the + * originally requested flags (the originally requested image will have flags + * like a backing file) + */ +static int bdrv_temp_snapshot_flags(int flags) +{ + return (flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY; +} + +/* * Returns the flags that bs->file should get, based on the given flags for * the parent BDS */ @@ -787,11 +797,6 @@ static int bdrv_inherited_flags(int flags) * so we can enable both unconditionally on lower layers. */ flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP; - /* The backing file of a temporary snapshot is read-only */ - if (flags & BDRV_O_SNAPSHOT) { - flags &= ~BDRV_O_RDWR; - } - /* Clear flags that only apply to the top layer */ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ); @@ -817,11 +822,6 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) { int open_flags = flags | BDRV_O_CACHE_WB; - /* The backing file of a temporary snapshot is read-only */ - if (flags & BDRV_O_SNAPSHOT) { - open_flags &= ~BDRV_O_RDWR; - } - /* * Clear flags that are internal to the block layer before opening the * image. @@ -1206,7 +1206,7 @@ done: return ret; } -void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) +void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) { /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ char *tmp_filename = g_malloc0(PATH_MAX + 1); @@ -1262,8 +1262,7 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp) bs_snapshot = bdrv_new("", &error_abort); ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options, - (bs->open_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY, - bdrv_qcow2, &local_err); + flags, bdrv_qcow2, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; @@ -1298,6 +1297,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, BlockDriverState *file = NULL, *bs; const char *drvname; Error *local_err = NULL; + int snapshot_flags = 0; assert(pbs); @@ -1358,6 +1358,10 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, if (flags & BDRV_O_RDWR) { flags |= BDRV_O_ALLOW_RDWR; } + if (flags & BDRV_O_SNAPSHOT) { + snapshot_flags = bdrv_temp_snapshot_flags(flags); + flags = bdrv_backing_flags(flags); + } assert(file == NULL); ret = bdrv_open_image(&file, filename, options, "file", @@ -1417,8 +1421,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename, /* For snapshot=on, create a temporary qcow2 overlay. bs points to the * temporary snapshot afterwards. */ - if (flags & BDRV_O_SNAPSHOT) { - bdrv_append_temp_snapshot(bs, &local_err); + if (snapshot_flags) { + bdrv_append_temp_snapshot(bs, snapshot_flags, &local_err); if (local_err) { error_propagate(errp, local_err); goto close_and_fail; diff --git a/block/gluster.c b/block/gluster.c index 8836085646..d0726ec92c 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -207,6 +207,11 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename, "volume=%s image=%s transport=%s", gconf->server, gconf->port, gconf->volname, gconf->image, gconf->transport); + + /* glfs_init sometimes doesn't set errno although docs suggest that */ + if (errno == 0) + errno = EINVAL; + goto out; } return glfs; @@ -482,7 +487,7 @@ static int qemu_gluster_create(const char *filename, glfs = qemu_gluster_init(gconf, filename, errp); if (!glfs) { - ret = -EINVAL; + ret = -errno; goto out; } diff --git a/block/iscsi.c b/block/iscsi.c index a30202b4fe..52355b8bce 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2,7 +2,7 @@ * QEMU Block driver for iSCSI images * * Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com> - * Copyright (c) 2012-2013 Peter Lieven <pl@kamp.de> + * Copyright (c) 2012-2014 Peter Lieven <pl@kamp.de> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/block/nfs.c b/block/nfs.c index 9fa831f160..539bd951df 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -256,6 +256,10 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename, error_setg(errp, "Invalid URL specified"); goto fail; } + if (!uri->server) { + error_setg(errp, "Invalid URL specified"); + goto fail; + } strp = strrchr(uri->path, '/'); if (strp == NULL) { error_setg(errp, "Invalid URL specified"); diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index e79895d11d..9507aef847 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -656,7 +656,9 @@ retry: /* Make sure that all offsets in the "allocated" range are representable * in an int64_t */ - if (s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) { + if (s->free_cluster_index > 0 && + s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) + { return -EFBIG; } diff --git a/block/raw-posix.c b/block/raw-posix.c index 3ce026db58..6586a0c9e1 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -146,6 +146,9 @@ typedef struct BDRVRawState { bool has_discard:1; bool has_write_zeroes:1; bool discard_zeroes:1; +#ifdef CONFIG_FIEMAP + bool skip_fiemap; +#endif } BDRVRawState; typedef struct BDRVRawReopenState { @@ -1272,53 +1275,29 @@ static int raw_create(const char *filename, QEMUOptionParameter *options, return result; } -/* - * Returns true iff the specified sector is present in the disk image. Drivers - * not implementing the functionality are assumed to not support backing files, - * hence all their sectors are reported as allocated. - * - * If 'sector_num' is beyond the end of the disk image the return value is 0 - * and 'pnum' is set to 0. - * - * 'pnum' is set to the number of sectors (including and immediately following - * the specified sector) that are known to be in the same - * allocated/unallocated state. - * - * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes - * beyond the end of the disk image it will be clamped. - */ -static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, - int64_t sector_num, - int nb_sectors, int *pnum) +static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data, + off_t *hole, int nb_sectors, int *pnum) { - off_t start, data, hole; - int64_t ret; - - ret = fd_open(bs); - if (ret < 0) { - return ret; - } - - start = sector_num * BDRV_SECTOR_SIZE; - ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; - #ifdef CONFIG_FIEMAP - BDRVRawState *s = bs->opaque; + int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; struct { struct fiemap fm; struct fiemap_extent fe; } f; + if (s->skip_fiemap) { + return -ENOTSUP; + } + f.fm.fm_start = start; f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE; f.fm.fm_flags = 0; f.fm.fm_extent_count = 1; f.fm.fm_reserved = 0; if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) { - /* Assume everything is allocated. */ - *pnum = nb_sectors; - return ret; + s->skip_fiemap = true; + return -errno; } if (f.fm.fm_mapped_extents == 0) { @@ -1326,44 +1305,92 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, * f.fm.fm_start + f.fm.fm_length must be clamped to the file size! */ off_t length = lseek(s->fd, 0, SEEK_END); - hole = f.fm.fm_start; - data = MIN(f.fm.fm_start + f.fm.fm_length, length); + *hole = f.fm.fm_start; + *data = MIN(f.fm.fm_start + f.fm.fm_length, length); } else { - data = f.fe.fe_logical; - hole = f.fe.fe_logical + f.fe.fe_length; + *data = f.fe.fe_logical; + *hole = f.fe.fe_logical + f.fe.fe_length; if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) { ret |= BDRV_BLOCK_ZERO; } } -#elif defined SEEK_HOLE && defined SEEK_DATA + return ret; +#else + return -ENOTSUP; +#endif +} +static int64_t try_seek_hole(BlockDriverState *bs, off_t start, off_t *data, + off_t *hole, int *pnum) +{ +#if defined SEEK_HOLE && defined SEEK_DATA BDRVRawState *s = bs->opaque; - hole = lseek(s->fd, start, SEEK_HOLE); - if (hole == -1) { + *hole = lseek(s->fd, start, SEEK_HOLE); + if (*hole == -1) { /* -ENXIO indicates that sector_num was past the end of the file. * There is a virtual hole there. */ assert(errno != -ENXIO); - /* Most likely EINVAL. Assume everything is allocated. */ - *pnum = nb_sectors; - return ret; + return -errno; } - if (hole > start) { - data = start; + if (*hole > start) { + *data = start; } else { /* On a hole. We need another syscall to find its end. */ - data = lseek(s->fd, start, SEEK_DATA); - if (data == -1) { - data = lseek(s->fd, 0, SEEK_END); + *data = lseek(s->fd, start, SEEK_DATA); + if (*data == -1) { + *data = lseek(s->fd, 0, SEEK_END); } } + + return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; #else - data = 0; - hole = start + nb_sectors * BDRV_SECTOR_SIZE; + return -ENOTSUP; #endif +} + +/* + * Returns true iff the specified sector is present in the disk image. Drivers + * not implementing the functionality are assumed to not support backing files, + * hence all their sectors are reported as allocated. + * + * If 'sector_num' is beyond the end of the disk image the return value is 0 + * and 'pnum' is set to 0. + * + * 'pnum' is set to the number of sectors (including and immediately following + * the specified sector) that are known to be in the same + * allocated/unallocated state. + * + * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes + * beyond the end of the disk image it will be clamped. + */ +static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors, int *pnum) +{ + off_t start, data = 0, hole = 0; + int64_t ret; + + ret = fd_open(bs); + if (ret < 0) { + return ret; + } + + start = sector_num * BDRV_SECTOR_SIZE; + + ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum); + if (ret < 0) { + ret = try_seek_hole(bs, start, &data, &hole, pnum); + if (ret < 0) { + /* Assume everything is allocated. */ + data = 0; + hole = start + nb_sectors * BDRV_SECTOR_SIZE; + ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; + } + } if (data <= start) { /* On a data extent, compute sectors to the end of the extent. */ diff --git a/block/vmdk.c b/block/vmdk.c index 06a1f9f93b..480ea37d7c 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1496,6 +1496,19 @@ static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num, return ret; } +static int vmdk_write_compressed(BlockDriverState *bs, + int64_t sector_num, + const uint8_t *buf, + int nb_sectors) +{ + BDRVVmdkState *s = bs->opaque; + if (s->num_extents == 1 && s->extents[0].compressed) { + return vmdk_write(bs, sector_num, buf, nb_sectors, false, false); + } else { + return -ENOTSUP; + } +} + static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, int nb_sectors, @@ -2063,6 +2076,26 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs) return spec_info; } +static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) +{ + int i; + BDRVVmdkState *s = bs->opaque; + assert(s->num_extents); + bdi->needs_compressed_writes = s->extents[0].compressed; + if (!s->extents[0].flat) { + bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS; + } + /* See if we have multiple extents but they have different cases */ + for (i = 1; i < s->num_extents; i++) { + if (bdi->needs_compressed_writes != s->extents[i].compressed || + (bdi->cluster_size && bdi->cluster_size != + s->extents[i].cluster_sectors << BDRV_SECTOR_BITS)) { + return -ENOTSUP; + } + } + return 0; +} + static QEMUOptionParameter vmdk_create_options[] = { { .name = BLOCK_OPT_SIZE, @@ -2109,6 +2142,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_reopen_prepare = vmdk_reopen_prepare, .bdrv_read = vmdk_co_read, .bdrv_write = vmdk_co_write, + .bdrv_write_compressed = vmdk_write_compressed, .bdrv_co_write_zeroes = vmdk_co_write_zeroes, .bdrv_close = vmdk_close, .bdrv_create = vmdk_create, @@ -2118,6 +2152,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_has_zero_init = vmdk_has_zero_init, .bdrv_get_specific_info = vmdk_get_specific_info, .bdrv_refresh_limits = vmdk_refresh_limits, + .bdrv_get_info = vmdk_get_info, .create_options = vmdk_create_options, }; diff --git a/bsd-user/main.c b/bsd-user/main.c index f81ba55af8..4ba61da896 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -43,7 +43,7 @@ unsigned long reserved_va; #endif static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; -const char *qemu_uname_release = CONFIG_UNAME_RELEASE; +const char *qemu_uname_release; extern char **environ; enum BSDType bsd_type; @@ -1003,8 +1003,6 @@ int main(int argc, char **argv) cpu->opaque = ts; #if defined(TARGET_I386) - cpu_x86_set_cpl(env, 3); - env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; env->hflags |= HF_PE_MASK; if (env->features[FEAT_1_EDX] & CPUID_SSE) { @@ -3470,10 +3470,10 @@ if test "$smartcard_nss" != "no"; then #include <pk11pub.h> int main(void) { PK11_FreeSlot(0); return 0; } EOF - smartcard_includes="-I\$(SRC_PATH)/libcacard" - libcacard_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs" - libcacard_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags" - test_cflags="$libcacard_cflags" + # FIXME: do not include $glib_* in here + nss_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs" + nss_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags" + test_cflags="$nss_cflags" # The header files in nss < 3.13.3 have a bug which causes them to # emit a warning. If we're going to compile QEMU with -Werror, then # test that the headers don't have this bug. Otherwise we would pass @@ -3483,11 +3483,8 @@ EOF fi if test -n "$libtool" && $pkg_config --atleast-version=3.12.8 nss && \ - compile_prog "$test_cflags" "$libcacard_libs"; then + compile_prog "$test_cflags" "$nss_libs"; then smartcard_nss="yes" - QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags" - QEMU_INCLUDES="$QEMU_INCLUDES $smartcard_includes" - libs_softmmu="$libcacard_libs $libs_softmmu" else if test "$smartcard_nss" = "yes"; then feature_not_found "nss" @@ -4501,8 +4498,8 @@ fi if test "$smartcard_nss" = "yes" ; then echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak - echo "libcacard_libs=$libcacard_libs" >> $config_host_mak - echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak + echo "NSS_LIBS=$nss_libs" >> $config_host_mak + echo "NSS_CFLAGS=$nss_cflags" >> $config_host_mak fi if test "$libusb" = "yes" ; then diff --git a/cpu-exec.c b/cpu-exec.c index 2f54054d8c..38e5f02a30 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -336,19 +336,25 @@ int cpu_exec(CPUArchState *env) } #endif #if defined(TARGET_I386) + if (interrupt_request & CPU_INTERRUPT_INIT) { + cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0); + do_cpu_init(x86_cpu); + cpu->exception_index = EXCP_HALTED; + cpu_loop_exit(cpu); + } +#else + if (interrupt_request & CPU_INTERRUPT_RESET) { + cpu_reset(cpu); + } +#endif +#if defined(TARGET_I386) #if !defined(CONFIG_USER_ONLY) if (interrupt_request & CPU_INTERRUPT_POLL) { cpu->interrupt_request &= ~CPU_INTERRUPT_POLL; apic_poll_irq(x86_cpu->apic_state); } #endif - if (interrupt_request & CPU_INTERRUPT_INIT) { - cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, - 0); - do_cpu_init(x86_cpu); - cpu->exception_index = EXCP_HALTED; - cpu_loop_exit(cpu); - } else if (interrupt_request & CPU_INTERRUPT_SIPI) { + if (interrupt_request & CPU_INTERRUPT_SIPI) { do_cpu_sipi(x86_cpu); } else if (env->hflags2 & HF2_GIF_MASK) { if ((interrupt_request & CPU_INTERRUPT_SMI) && @@ -405,9 +411,6 @@ int cpu_exec(CPUArchState *env) } } #elif defined(TARGET_PPC) - if ((interrupt_request & CPU_INTERRUPT_RESET)) { - cpu_reset(cpu); - } if (interrupt_request & CPU_INTERRUPT_HARD) { ppc_hw_interrupt(env); if (env->pending_interrupts == 0) { @@ -430,8 +430,7 @@ static const VMStateDescription vmstate_timers = { .name = "timer", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT64(cpu_ticks_offset, TimersState), VMSTATE_INT64(dummy, TimersState), VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2), diff --git a/disas/Makefile.objs b/disas/Makefile.objs index 41c237424a..8dae4daec0 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -4,7 +4,7 @@ common-obj-$(CONFIG_ARM_DIS) += arm.o common-obj-$(CONFIG_ARM_A64_DIS) += arm-a64.o common-obj-$(CONFIG_ARM_A64_DIS) += libvixl/ libvixldir = $(SRC_PATH)/disas/libvixl -$(obj)/arm-a64.o: QEMU_CFLAGS += -I$(libvixldir) +arm-a64.o-cflags := -I$(libvixldir) common-obj-$(CONFIG_CRIS_DIS) += cris.o common-obj-$(CONFIG_HPPA_DIS) += hppa.o common-obj-$(CONFIG_I386_DIS) += i386.o diff --git a/disas/libvixl/a64/assembler-a64.h b/disas/libvixl/a64/assembler-a64.h index 93b3011868..1e2947b283 100644 --- a/disas/libvixl/a64/assembler-a64.h +++ b/disas/libvixl/a64/assembler-a64.h @@ -38,6 +38,7 @@ namespace vixl { typedef uint64_t RegList; static const int kRegListSizeInBits = sizeof(RegList) * 8; + // Registers. // Some CPURegister methods can return Register and FPRegister types, so we @@ -58,62 +59,62 @@ class CPURegister { }; CPURegister() : code_(0), size_(0), type_(kNoRegister) { - ASSERT(!IsValid()); - ASSERT(IsNone()); + VIXL_ASSERT(!IsValid()); + VIXL_ASSERT(IsNone()); } CPURegister(unsigned code, unsigned size, RegisterType type) : code_(code), size_(size), type_(type) { - ASSERT(IsValidOrNone()); + VIXL_ASSERT(IsValidOrNone()); } unsigned code() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return code_; } RegisterType type() const { - ASSERT(IsValidOrNone()); + VIXL_ASSERT(IsValidOrNone()); return type_; } RegList Bit() const { - ASSERT(code_ < (sizeof(RegList) * 8)); + VIXL_ASSERT(code_ < (sizeof(RegList) * 8)); return IsValid() ? (static_cast<RegList>(1) << code_) : 0; } unsigned size() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return size_; } int SizeInBytes() const { - ASSERT(IsValid()); - ASSERT(size() % 8 == 0); + VIXL_ASSERT(IsValid()); + VIXL_ASSERT(size() % 8 == 0); return size_ / 8; } int SizeInBits() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return size_; } bool Is32Bits() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return size_ == 32; } bool Is64Bits() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return size_ == 64; } bool IsValid() const { if (IsValidRegister() || IsValidFPRegister()) { - ASSERT(!IsNone()); + VIXL_ASSERT(!IsNone()); return true; } else { - ASSERT(IsNone()); + VIXL_ASSERT(IsNone()); return false; } } @@ -132,25 +133,29 @@ class CPURegister { bool IsNone() const { // kNoRegister types should always have size 0 and code 0. - ASSERT((type_ != kNoRegister) || (code_ == 0)); - ASSERT((type_ != kNoRegister) || (size_ == 0)); + VIXL_ASSERT((type_ != kNoRegister) || (code_ == 0)); + VIXL_ASSERT((type_ != kNoRegister) || (size_ == 0)); return type_ == kNoRegister; } + bool Aliases(const CPURegister& other) const { + VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone()); + return (code_ == other.code_) && (type_ == other.type_); + } + bool Is(const CPURegister& other) const { - ASSERT(IsValidOrNone() && other.IsValidOrNone()); - return (code_ == other.code_) && (size_ == other.size_) && - (type_ == other.type_); + VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone()); + return Aliases(other) && (size_ == other.size_); } inline bool IsZero() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return IsRegister() && (code_ == kZeroRegCode); } inline bool IsSP() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return IsRegister() && (code_ == kSPRegInternalCode); } @@ -188,13 +193,13 @@ class Register : public CPURegister { explicit Register() : CPURegister() {} inline explicit Register(const CPURegister& other) : CPURegister(other.code(), other.size(), other.type()) { - ASSERT(IsValidRegister()); + VIXL_ASSERT(IsValidRegister()); } explicit Register(unsigned code, unsigned size) : CPURegister(code, size, kRegister) {} bool IsValid() const { - ASSERT(IsRegister() || IsNone()); + VIXL_ASSERT(IsRegister() || IsNone()); return IsValidRegister(); } @@ -216,13 +221,13 @@ class FPRegister : public CPURegister { inline FPRegister() : CPURegister() {} inline explicit FPRegister(const CPURegister& other) : CPURegister(other.code(), other.size(), other.type()) { - ASSERT(IsValidFPRegister()); + VIXL_ASSERT(IsValidFPRegister()); } inline FPRegister(unsigned code, unsigned size) : CPURegister(code, size, kFPRegister) {} bool IsValid() const { - ASSERT(IsFPRegister() || IsNone()); + VIXL_ASSERT(IsFPRegister() || IsNone()); return IsValidFPRegister(); } @@ -306,30 +311,30 @@ class CPURegList { CPURegister reg4 = NoCPUReg) : list_(reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit()), size_(reg1.size()), type_(reg1.type()) { - ASSERT(AreSameSizeAndType(reg1, reg2, reg3, reg4)); - ASSERT(IsValid()); + VIXL_ASSERT(AreSameSizeAndType(reg1, reg2, reg3, reg4)); + VIXL_ASSERT(IsValid()); } inline CPURegList(CPURegister::RegisterType type, unsigned size, RegList list) : list_(list), size_(size), type_(type) { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); } inline CPURegList(CPURegister::RegisterType type, unsigned size, unsigned first_reg, unsigned last_reg) : size_(size), type_(type) { - ASSERT(((type == CPURegister::kRegister) && - (last_reg < kNumberOfRegisters)) || - ((type == CPURegister::kFPRegister) && - (last_reg < kNumberOfFPRegisters))); - ASSERT(last_reg >= first_reg); - list_ = (1UL << (last_reg + 1)) - 1; - list_ &= ~((1UL << first_reg) - 1); - ASSERT(IsValid()); + VIXL_ASSERT(((type == CPURegister::kRegister) && + (last_reg < kNumberOfRegisters)) || + ((type == CPURegister::kFPRegister) && + (last_reg < kNumberOfFPRegisters))); + VIXL_ASSERT(last_reg >= first_reg); + list_ = (UINT64_C(1) << (last_reg + 1)) - 1; + list_ &= ~((UINT64_C(1) << first_reg) - 1); + VIXL_ASSERT(IsValid()); } inline CPURegister::RegisterType type() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return type_; } @@ -337,9 +342,9 @@ class CPURegList { // this list are left unchanged. The type and size of the registers in the // 'other' list must match those in this list. void Combine(const CPURegList& other) { - ASSERT(IsValid()); - ASSERT(other.type() == type_); - ASSERT(other.RegisterSizeInBits() == size_); + VIXL_ASSERT(IsValid()); + VIXL_ASSERT(other.type() == type_); + VIXL_ASSERT(other.RegisterSizeInBits() == size_); list_ |= other.list(); } @@ -347,44 +352,49 @@ class CPURegList { // do not exist in this list are ignored. The type and size of the registers // in the 'other' list must match those in this list. void Remove(const CPURegList& other) { - ASSERT(IsValid()); - ASSERT(other.type() == type_); - ASSERT(other.RegisterSizeInBits() == size_); + VIXL_ASSERT(IsValid()); + VIXL_ASSERT(other.type() == type_); + VIXL_ASSERT(other.RegisterSizeInBits() == size_); list_ &= ~other.list(); } // Variants of Combine and Remove which take a single register. inline void Combine(const CPURegister& other) { - ASSERT(other.type() == type_); - ASSERT(other.size() == size_); + VIXL_ASSERT(other.type() == type_); + VIXL_ASSERT(other.size() == size_); Combine(other.code()); } inline void Remove(const CPURegister& other) { - ASSERT(other.type() == type_); - ASSERT(other.size() == size_); + VIXL_ASSERT(other.type() == type_); + VIXL_ASSERT(other.size() == size_); Remove(other.code()); } // Variants of Combine and Remove which take a single register by its code; // the type and size of the register is inferred from this list. inline void Combine(int code) { - ASSERT(IsValid()); - ASSERT(CPURegister(code, size_, type_).IsValid()); - list_ |= (1UL << code); + VIXL_ASSERT(IsValid()); + VIXL_ASSERT(CPURegister(code, size_, type_).IsValid()); + list_ |= (UINT64_C(1) << code); } inline void Remove(int code) { - ASSERT(IsValid()); - ASSERT(CPURegister(code, size_, type_).IsValid()); - list_ &= ~(1UL << code); + VIXL_ASSERT(IsValid()); + VIXL_ASSERT(CPURegister(code, size_, type_).IsValid()); + list_ &= ~(UINT64_C(1) << code); } inline RegList list() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return list_; } + inline void set_list(RegList new_list) { + VIXL_ASSERT(IsValid()); + list_ = new_list; + } + // Remove all callee-saved registers from the list. This can be useful when // preparing registers for an AAPCS64 function call, for example. void RemoveCalleeSaved(); @@ -401,31 +411,41 @@ class CPURegList { static CPURegList GetCallerSavedFP(unsigned size = kDRegSize); inline bool IsEmpty() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return list_ == 0; } inline bool IncludesAliasOf(const CPURegister& other) const { - ASSERT(IsValid()); - return (type_ == other.type()) && (other.Bit() & list_); + VIXL_ASSERT(IsValid()); + return (type_ == other.type()) && ((other.Bit() & list_) != 0); + } + + inline bool IncludesAliasOf(int code) const { + VIXL_ASSERT(IsValid()); + return ((code & list_) != 0); } inline int Count() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return CountSetBits(list_, kRegListSizeInBits); } inline unsigned RegisterSizeInBits() const { - ASSERT(IsValid()); + VIXL_ASSERT(IsValid()); return size_; } inline unsigned RegisterSizeInBytes() const { int size_in_bits = RegisterSizeInBits(); - ASSERT((size_in_bits % 8) == 0); + VIXL_ASSERT((size_in_bits % 8) == 0); return size_in_bits / 8; } + inline unsigned TotalSizeInBytes() const { + VIXL_ASSERT(IsValid()); + return RegisterSizeInBytes() * Count(); + } + private: RegList list_; unsigned size_; @@ -471,33 +491,34 @@ class Operand { bool IsImmediate() const; bool IsShiftedRegister() const; bool IsExtendedRegister() const; + bool IsZero() const; // This returns an LSL shift (<= 4) operand as an equivalent extend operand, // which helps in the encoding of instructions that use the stack pointer. Operand ToExtendedRegister() const; int64_t immediate() const { - ASSERT(IsImmediate()); + VIXL_ASSERT(IsImmediate()); return immediate_; } Register reg() const { - ASSERT(IsShiftedRegister() || IsExtendedRegister()); + VIXL_ASSERT(IsShiftedRegister() || IsExtendedRegister()); return reg_; } Shift shift() const { - ASSERT(IsShiftedRegister()); + VIXL_ASSERT(IsShiftedRegister()); return shift_; } Extend extend() const { - ASSERT(IsExtendedRegister()); + VIXL_ASSERT(IsExtendedRegister()); return extend_; } unsigned shift_amount() const { - ASSERT(IsShiftedRegister() || IsExtendedRegister()); + VIXL_ASSERT(IsShiftedRegister() || IsExtendedRegister()); return shift_amount_; } @@ -556,7 +577,7 @@ class Label { Label() : is_bound_(false), link_(NULL), target_(NULL) {} ~Label() { // If the label has been linked to, it needs to be bound to a target. - ASSERT(!IsLinked() || IsBound()); + VIXL_ASSERT(!IsLinked() || IsBound()); } inline Instruction* link() const { return link_; } @@ -643,7 +664,7 @@ class Assembler { void bind(Label* label); int UpdateAndGetByteOffsetTo(Label* label); inline int UpdateAndGetInstructionOffsetTo(Label* label) { - ASSERT(Label::kEndOfChain == 0); + VIXL_ASSERT(Label::kEndOfChain == 0); return UpdateAndGetByteOffsetTo(label) >> kInstructionSizeLog2; } @@ -716,8 +737,12 @@ class Assembler { // Add. void add(const Register& rd, const Register& rn, - const Operand& operand, - FlagsUpdate S = LeaveFlags); + const Operand& operand); + + // Add and update status flags. + void adds(const Register& rd, + const Register& rn, + const Operand& operand); // Compare negative. void cmn(const Register& rn, const Operand& operand); @@ -725,40 +750,62 @@ class Assembler { // Subtract. void sub(const Register& rd, const Register& rn, - const Operand& operand, - FlagsUpdate S = LeaveFlags); + const Operand& operand); + + // Subtract and update status flags. + void subs(const Register& rd, + const Register& rn, + const Operand& operand); // Compare. void cmp(const Register& rn, const Operand& operand); // Negate. void neg(const Register& rd, - const Operand& operand, - FlagsUpdate S = LeaveFlags); + const Operand& operand); + + // Negate and update status flags. + void negs(const Register& rd, + const Operand& operand); // Add with carry bit. void adc(const Register& rd, const Register& rn, - const Operand& operand, - FlagsUpdate S = LeaveFlags); + const Operand& operand); + + // Add with carry bit and update status flags. + void adcs(const Register& rd, + const Register& rn, + const Operand& operand); // Subtract with carry bit. void sbc(const Register& rd, const Register& rn, - const Operand& operand, - FlagsUpdate S = LeaveFlags); + const Operand& operand); + + // Subtract with carry bit and update status flags. + void sbcs(const Register& rd, + const Register& rn, + const Operand& operand); // Negate with carry bit. void ngc(const Register& rd, - const Operand& operand, - FlagsUpdate S = LeaveFlags); + const Operand& operand); + + // Negate with carry bit and update status flags. + void ngcs(const Register& rd, + const Operand& operand); // Logical instructions. // Bitwise and (A & B). void and_(const Register& rd, const Register& rn, - const Operand& operand, - FlagsUpdate S = LeaveFlags); + const Operand& operand); + + // Bitwise and (A & B) and update status flags. + void ands(const Register& rd, + const Register& rn, + const Operand& operand); // Bit test and set flags. void tst(const Register& rn, const Operand& operand); @@ -766,8 +813,12 @@ class Assembler { // Bit clear (A & ~B). void bic(const Register& rd, const Register& rn, - const Operand& operand, - FlagsUpdate S = LeaveFlags); + const Operand& operand); + + // Bit clear (A & ~B) and update status flags. + void bics(const Register& rd, + const Register& rn, + const Operand& operand); // Bitwise or (A | B). void orr(const Register& rd, const Register& rn, const Operand& operand); @@ -818,8 +869,8 @@ class Assembler { const Register& rn, unsigned lsb, unsigned width) { - ASSERT(width >= 1); - ASSERT(lsb + width <= rn.size()); + VIXL_ASSERT(width >= 1); + VIXL_ASSERT(lsb + width <= rn.size()); bfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); } @@ -828,15 +879,15 @@ class Assembler { const Register& rn, unsigned lsb, unsigned width) { - ASSERT(width >= 1); - ASSERT(lsb + width <= rn.size()); + VIXL_ASSERT(width >= 1); + VIXL_ASSERT(lsb + width <= rn.size()); bfm(rd, rn, lsb, lsb + width - 1); } // Sbfm aliases. // Arithmetic shift right. inline void asr(const Register& rd, const Register& rn, unsigned shift) { - ASSERT(shift < rd.size()); + VIXL_ASSERT(shift < rd.size()); sbfm(rd, rn, shift, rd.size() - 1); } @@ -845,8 +896,8 @@ class Assembler { const Register& rn, unsigned lsb, unsigned width) { - ASSERT(width >= 1); - ASSERT(lsb + width <= rn.size()); + VIXL_ASSERT(width >= 1); + VIXL_ASSERT(lsb + width <= rn.size()); sbfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); } @@ -855,8 +906,8 @@ class Assembler { const Register& rn, unsigned lsb, unsigned width) { - ASSERT(width >= 1); - ASSERT(lsb + width <= rn.size()); + VIXL_ASSERT(width >= 1); + VIXL_ASSERT(lsb + width <= rn.size()); sbfm(rd, rn, lsb, lsb + width - 1); } @@ -879,13 +930,13 @@ class Assembler { // Logical shift left. inline void lsl(const Register& rd, const Register& rn, unsigned shift) { unsigned reg_size = rd.size(); - ASSERT(shift < reg_size); + VIXL_ASSERT(shift < reg_size); ubfm(rd, rn, (reg_size - shift) % reg_size, reg_size - shift - 1); } // Logical shift right. inline void lsr(const Register& rd, const Register& rn, unsigned shift) { - ASSERT(shift < rd.size()); + VIXL_ASSERT(shift < rd.size()); ubfm(rd, rn, shift, rd.size() - 1); } @@ -894,8 +945,8 @@ class Assembler { const Register& rn, unsigned lsb, unsigned width) { - ASSERT(width >= 1); - ASSERT(lsb + width <= rn.size()); + VIXL_ASSERT(width >= 1); + VIXL_ASSERT(lsb + width <= rn.size()); ubfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1); } @@ -904,8 +955,8 @@ class Assembler { const Register& rn, unsigned lsb, unsigned width) { - ASSERT(width >= 1); - ASSERT(lsb + width <= rn.size()); + VIXL_ASSERT(width >= 1); + VIXL_ASSERT(lsb + width <= rn.size()); ubfm(rd, rn, lsb, lsb + width - 1); } @@ -1109,9 +1160,12 @@ class Assembler { // Load literal to register. void ldr(const Register& rt, uint64_t imm); - // Load literal to FP register. + // Load double precision floating point literal to FP register. void ldr(const FPRegister& ft, double imm); + // Load single precision floating point literal to FP register. + void ldr(const FPRegister& ft, float imm); + // Move instructions. The default shift of -1 indicates that the move // instruction will calculate an appropriate 16-bit immediate and left shift // that is equal to the 64-bit immediate argument. If an explicit left shift @@ -1160,6 +1214,15 @@ class Assembler { // System hint. void hint(SystemHint code); + // Data memory barrier. + void dmb(BarrierDomain domain, BarrierType type); + + // Data synchronization barrier. + void dsb(BarrierDomain domain, BarrierType type); + + // Instruction synchronization barrier. + void isb(); + // Alias for system instructions. // No-op. void nop() { @@ -1167,17 +1230,20 @@ class Assembler { } // FP instructions. - // Move immediate to FP register. - void fmov(FPRegister fd, double imm); + // Move double precision immediate to FP register. + void fmov(const FPRegister& fd, double imm); + + // Move single precision immediate to FP register. + void fmov(const FPRegister& fd, float imm); // Move FP register to register. - void fmov(Register rd, FPRegister fn); + void fmov(const Register& rd, const FPRegister& fn); // Move register to FP register. - void fmov(FPRegister fd, Register rn); + void fmov(const FPRegister& fd, const Register& rn); // Move FP register to FP register. - void fmov(FPRegister fd, FPRegister fn); + void fmov(const FPRegister& fd, const FPRegister& fn); // FP add. void fadd(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm); @@ -1188,12 +1254,30 @@ class Assembler { // FP multiply. void fmul(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm); - // FP multiply and subtract. + // FP fused multiply and add. + void fmadd(const FPRegister& fd, + const FPRegister& fn, + const FPRegister& fm, + const FPRegister& fa); + + // FP fused multiply and subtract. void fmsub(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm, const FPRegister& fa); + // FP fused multiply, add and negate. + void fnmadd(const FPRegister& fd, + const FPRegister& fn, + const FPRegister& fm, + const FPRegister& fa); + + // FP fused multiply, subtract and negate. + void fnmsub(const FPRegister& fd, + const FPRegister& fn, + const FPRegister& fm, + const FPRegister& fa); + // FP divide. void fdiv(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm); @@ -1203,6 +1287,12 @@ class Assembler { // FP minimum. void fmin(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm); + // FP maximum number. + void fmaxnm(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm); + + // FP minimum number. + void fminnm(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm); + // FP absolute. void fabs(const FPRegister& fd, const FPRegister& fn); @@ -1212,6 +1302,12 @@ class Assembler { // FP square root. void fsqrt(const FPRegister& fd, const FPRegister& fn); + // FP round to integer (nearest with ties to away). + void frinta(const FPRegister& fd, const FPRegister& fn); + + // FP round to integer (toward minus infinity). + void frintm(const FPRegister& fd, const FPRegister& fn); + // FP round to integer (nearest with ties to even). void frintn(const FPRegister& fd, const FPRegister& fn); @@ -1244,24 +1340,30 @@ class Assembler { // FP convert between single and double precision. void fcvt(const FPRegister& fd, const FPRegister& fn); - // Convert FP to unsigned integer (round towards -infinity). - void fcvtmu(const Register& rd, const FPRegister& fn); + // Convert FP to signed integer (nearest with ties to away). + void fcvtas(const Register& rd, const FPRegister& fn); + + // Convert FP to unsigned integer (nearest with ties to away). + void fcvtau(const Register& rd, const FPRegister& fn); // Convert FP to signed integer (round towards -infinity). void fcvtms(const Register& rd, const FPRegister& fn); - // Convert FP to unsigned integer (nearest with ties to even). - void fcvtnu(const Register& rd, const FPRegister& fn); + // Convert FP to unsigned integer (round towards -infinity). + void fcvtmu(const Register& rd, const FPRegister& fn); // Convert FP to signed integer (nearest with ties to even). void fcvtns(const Register& rd, const FPRegister& fn); - // Convert FP to unsigned integer (round towards zero). - void fcvtzu(const Register& rd, const FPRegister& fn); + // Convert FP to unsigned integer (nearest with ties to even). + void fcvtnu(const Register& rd, const FPRegister& fn); // Convert FP to signed integer (round towards zero). void fcvtzs(const Register& rd, const FPRegister& fn); + // Convert FP to unsigned integer (round towards zero). + void fcvtzu(const Register& rd, const FPRegister& fn); + // Convert signed integer or fixed point to FP. void scvtf(const FPRegister& fd, const Register& rn, unsigned fbits = 0); @@ -1282,14 +1384,14 @@ class Assembler { // character. The instruction pointer (pc_) is then aligned correctly for // subsequent instructions. void EmitStringData(const char * string) { - ASSERT(string != NULL); + VIXL_ASSERT(string != NULL); size_t len = strlen(string) + 1; EmitData(string, len); // Pad with NULL characters until pc_ is aligned. const char pad[] = {'\0', '\0', '\0', '\0'}; - ASSERT(sizeof(pad) == kInstructionSize); + VIXL_STATIC_ASSERT(sizeof(pad) == kInstructionSize); Instruction* next_pc = AlignUp(pc_, kInstructionSize); EmitData(&pad, next_pc - pc_); } @@ -1298,44 +1400,44 @@ class Assembler { // Register encoding. static Instr Rd(CPURegister rd) { - ASSERT(rd.code() != kSPRegInternalCode); + VIXL_ASSERT(rd.code() != kSPRegInternalCode); return rd.code() << Rd_offset; } static Instr Rn(CPURegister rn) { - ASSERT(rn.code() != kSPRegInternalCode); + VIXL_ASSERT(rn.code() != kSPRegInternalCode); return rn.code() << Rn_offset; } static Instr Rm(CPURegister rm) { - ASSERT(rm.code() != kSPRegInternalCode); + VIXL_ASSERT(rm.code() != kSPRegInternalCode); return rm.code() << Rm_offset; } static Instr Ra(CPURegister ra) { - ASSERT(ra.code() != kSPRegInternalCode); + VIXL_ASSERT(ra.code() != kSPRegInternalCode); return ra.code() << Ra_offset; } static Instr Rt(CPURegister rt) { - ASSERT(rt.code() != kSPRegInternalCode); + VIXL_ASSERT(rt.code() != kSPRegInternalCode); return rt.code() << Rt_offset; } static Instr Rt2(CPURegister rt2) { - ASSERT(rt2.code() != kSPRegInternalCode); + VIXL_ASSERT(rt2.code() != kSPRegInternalCode); return rt2.code() << Rt2_offset; } // These encoding functions allow the stack pointer to be encoded, and // disallow the zero register. static Instr RdSP(Register rd) { - ASSERT(!rd.IsZero()); + VIXL_ASSERT(!rd.IsZero()); return (rd.code() & kRegCodeMask) << Rd_offset; } static Instr RnSP(Register rn) { - ASSERT(!rn.IsZero()); + VIXL_ASSERT(!rn.IsZero()); return (rn.code() & kRegCodeMask) << Rn_offset; } @@ -1346,7 +1448,7 @@ class Assembler { } else if (S == LeaveFlags) { return 0 << FlagsUpdate_offset; } - UNREACHABLE(); + VIXL_UNREACHABLE(); return 0; } @@ -1356,7 +1458,7 @@ class Assembler { // PC-relative address encoding. static Instr ImmPCRelAddress(int imm21) { - ASSERT(is_int21(imm21)); + VIXL_ASSERT(is_int21(imm21)); Instr imm = static_cast<Instr>(truncate_to_int21(imm21)); Instr immhi = (imm >> ImmPCRelLo_width) << ImmPCRelHi_offset; Instr immlo = imm << ImmPCRelLo_offset; @@ -1365,27 +1467,27 @@ class Assembler { // Branch encoding. static Instr ImmUncondBranch(int imm26) { - ASSERT(is_int26(imm26)); + VIXL_ASSERT(is_int26(imm26)); return truncate_to_int26(imm26) << ImmUncondBranch_offset; } static Instr ImmCondBranch(int imm19) { - ASSERT(is_int19(imm19)); + VIXL_ASSERT(is_int19(imm19)); return truncate_to_int19(imm19) << ImmCondBranch_offset; } static Instr ImmCmpBranch(int imm19) { - ASSERT(is_int19(imm19)); + VIXL_ASSERT(is_int19(imm19)); return truncate_to_int19(imm19) << ImmCmpBranch_offset; } static Instr ImmTestBranch(int imm14) { - ASSERT(is_int14(imm14)); + VIXL_ASSERT(is_int14(imm14)); return truncate_to_int14(imm14) << ImmTestBranch_offset; } static Instr ImmTestBranchBit(unsigned bit_pos) { - ASSERT(is_uint6(bit_pos)); + VIXL_ASSERT(is_uint6(bit_pos)); // Subtract five from the shift offset, as we need bit 5 from bit_pos. unsigned b5 = bit_pos << (ImmTestBranchBit5_offset - 5); unsigned b40 = bit_pos << ImmTestBranchBit40_offset; @@ -1400,7 +1502,7 @@ class Assembler { } static Instr ImmAddSub(int64_t imm) { - ASSERT(IsImmAddSub(imm)); + VIXL_ASSERT(IsImmAddSub(imm)); if (is_uint12(imm)) { // No shift required. return imm << ImmAddSub_offset; } else { @@ -1409,55 +1511,55 @@ class Assembler { } static inline Instr ImmS(unsigned imms, unsigned reg_size) { - ASSERT(((reg_size == kXRegSize) && is_uint6(imms)) || + VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(imms)) || ((reg_size == kWRegSize) && is_uint5(imms))); USE(reg_size); return imms << ImmS_offset; } static inline Instr ImmR(unsigned immr, unsigned reg_size) { - ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) || + VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) || ((reg_size == kWRegSize) && is_uint5(immr))); USE(reg_size); - ASSERT(is_uint6(immr)); + VIXL_ASSERT(is_uint6(immr)); return immr << ImmR_offset; } static inline Instr ImmSetBits(unsigned imms, unsigned reg_size) { - ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); - ASSERT(is_uint6(imms)); - ASSERT((reg_size == kXRegSize) || is_uint6(imms + 3)); + VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); + VIXL_ASSERT(is_uint6(imms)); + VIXL_ASSERT((reg_size == kXRegSize) || is_uint6(imms + 3)); USE(reg_size); return imms << ImmSetBits_offset; } static inline Instr ImmRotate(unsigned immr, unsigned reg_size) { - ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); - ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) || + VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); + VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) || ((reg_size == kWRegSize) && is_uint5(immr))); USE(reg_size); return immr << ImmRotate_offset; } static inline Instr ImmLLiteral(int imm19) { - ASSERT(is_int19(imm19)); + VIXL_ASSERT(is_int19(imm19)); return truncate_to_int19(imm19) << ImmLLiteral_offset; } static inline Instr BitN(unsigned bitn, unsigned reg_size) { - ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); - ASSERT((reg_size == kXRegSize) || (bitn == 0)); + VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); + VIXL_ASSERT((reg_size == kXRegSize) || (bitn == 0)); USE(reg_size); return bitn << BitN_offset; } static Instr ShiftDP(Shift shift) { - ASSERT(shift == LSL || shift == LSR || shift == ASR || shift == ROR); + VIXL_ASSERT(shift == LSL || shift == LSR || shift == ASR || shift == ROR); return shift << ShiftDP_offset; } static Instr ImmDPShift(unsigned amount) { - ASSERT(is_uint6(amount)); + VIXL_ASSERT(is_uint6(amount)); return amount << ImmDPShift_offset; } @@ -1466,12 +1568,12 @@ class Assembler { } static Instr ImmExtendShift(unsigned left_shift) { - ASSERT(left_shift <= 4); + VIXL_ASSERT(left_shift <= 4); return left_shift << ImmExtendShift_offset; } static Instr ImmCondCmp(unsigned imm) { - ASSERT(is_uint5(imm)); + VIXL_ASSERT(is_uint5(imm)); return imm << ImmCondCmp_offset; } @@ -1481,55 +1583,65 @@ class Assembler { // MemOperand offset encoding. static Instr ImmLSUnsigned(int imm12) { - ASSERT(is_uint12(imm12)); + VIXL_ASSERT(is_uint12(imm12)); return imm12 << ImmLSUnsigned_offset; } static Instr ImmLS(int imm9) { - ASSERT(is_int9(imm9)); + VIXL_ASSERT(is_int9(imm9)); return truncate_to_int9(imm9) << ImmLS_offset; } static Instr ImmLSPair(int imm7, LSDataSize size) { - ASSERT(((imm7 >> size) << size) == imm7); + VIXL_ASSERT(((imm7 >> size) << size) == imm7); int scaled_imm7 = imm7 >> size; - ASSERT(is_int7(scaled_imm7)); + VIXL_ASSERT(is_int7(scaled_imm7)); return truncate_to_int7(scaled_imm7) << ImmLSPair_offset; } static Instr ImmShiftLS(unsigned shift_amount) { - ASSERT(is_uint1(shift_amount)); + VIXL_ASSERT(is_uint1(shift_amount)); return shift_amount << ImmShiftLS_offset; } static Instr ImmException(int imm16) { - ASSERT(is_uint16(imm16)); + VIXL_ASSERT(is_uint16(imm16)); return imm16 << ImmException_offset; } static Instr ImmSystemRegister(int imm15) { - ASSERT(is_uint15(imm15)); + VIXL_ASSERT(is_uint15(imm15)); return imm15 << ImmSystemRegister_offset; } static Instr ImmHint(int imm7) { - ASSERT(is_uint7(imm7)); + VIXL_ASSERT(is_uint7(imm7)); return imm7 << ImmHint_offset; } + static Instr ImmBarrierDomain(int imm2) { + VIXL_ASSERT(is_uint2(imm2)); + return imm2 << ImmBarrierDomain_offset; + } + + static Instr ImmBarrierType(int imm2) { + VIXL_ASSERT(is_uint2(imm2)); + return imm2 << ImmBarrierType_offset; + } + static LSDataSize CalcLSDataSize(LoadStoreOp op) { - ASSERT((SizeLS_offset + SizeLS_width) == (kInstructionSize * 8)); + VIXL_ASSERT((SizeLS_offset + SizeLS_width) == (kInstructionSize * 8)); return static_cast<LSDataSize>(op >> SizeLS_offset); } // Move immediates encoding. static Instr ImmMoveWide(uint64_t imm) { - ASSERT(is_uint16(imm)); + VIXL_ASSERT(is_uint16(imm)); return imm << ImmMoveWide_offset; } static Instr ShiftMoveWide(int64_t shift) { - ASSERT(is_uint2(shift)); + VIXL_ASSERT(is_uint2(shift)); return shift << ShiftMoveWide_offset; } @@ -1543,20 +1655,20 @@ class Assembler { } static Instr FPScale(unsigned scale) { - ASSERT(is_uint6(scale)); + VIXL_ASSERT(is_uint6(scale)); return scale << FPScale_offset; } // Size of the code generated in bytes uint64_t SizeOfCodeGenerated() const { - ASSERT((pc_ >= buffer_) && (pc_ < (buffer_ + buffer_size_))); + VIXL_ASSERT((pc_ >= buffer_) && (pc_ < (buffer_ + buffer_size_))); return pc_ - buffer_; } // Size of the code generated since label to the current position. uint64_t SizeOfCodeGeneratedSince(Label* label) const { - ASSERT(label->IsBound()); - ASSERT((pc_ >= label->target()) && (pc_ < (buffer_ + buffer_size_))); + VIXL_ASSERT(label->IsBound()); + VIXL_ASSERT((pc_ >= label->target()) && (pc_ < (buffer_ + buffer_size_))); return pc_ - label->target(); } @@ -1568,7 +1680,7 @@ class Assembler { inline void ReleaseLiteralPool() { if (--literal_pool_monitor_ == 0) { // Has the literal pool been blocked for too long? - ASSERT(literals_.empty() || + VIXL_ASSERT(literals_.empty() || (pc_ < (literals_.back()->pc_ + kMaxLoadLiteralRange))); } } @@ -1622,6 +1734,9 @@ class Assembler { FlagsUpdate S, AddSubWithCarryOp op); + static bool IsImmFP32(float imm); + static bool IsImmFP64(double imm); + // Functions for emulating operands not directly supported by the instruction // set. void EmitShift(const Register& rd, @@ -1706,17 +1821,13 @@ class Assembler { const FPRegister& fa, FPDataProcessing3SourceOp op); - // Encoding helpers. - static bool IsImmFP32(float imm); - static bool IsImmFP64(double imm); - void RecordLiteral(int64_t imm, unsigned size); // Emit the instruction at pc_. void Emit(Instr instruction) { - ASSERT(sizeof(*pc_) == 1); - ASSERT(sizeof(instruction) == kInstructionSize); - ASSERT((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_)); + VIXL_STATIC_ASSERT(sizeof(*pc_) == 1); + VIXL_STATIC_ASSERT(sizeof(instruction) == kInstructionSize); + VIXL_ASSERT((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_)); #ifdef DEBUG finalized_ = false; @@ -1729,8 +1840,8 @@ class Assembler { // Emit data inline in the instruction stream. void EmitData(void const * data, unsigned size) { - ASSERT(sizeof(*pc_) == 1); - ASSERT((pc_ + size) <= (buffer_ + buffer_size_)); + VIXL_STATIC_ASSERT(sizeof(*pc_) == 1); + VIXL_ASSERT((pc_ + size) <= (buffer_ + buffer_size_)); #ifdef DEBUG finalized_ = false; @@ -1744,7 +1855,7 @@ class Assembler { } inline void CheckBufferSpace() { - ASSERT(pc_ < (buffer_ + buffer_size_)); + VIXL_ASSERT(pc_ < (buffer_ + buffer_size_)); if (pc_ > next_literal_pool_check_) { CheckLiteralPool(); } diff --git a/disas/libvixl/a64/constants-a64.h b/disas/libvixl/a64/constants-a64.h index 2e0336dd0f..99677c1be3 100644 --- a/disas/libvixl/a64/constants-a64.h +++ b/disas/libvixl/a64/constants-a64.h @@ -116,6 +116,8 @@ V_(ImmCmpBranch, 23, 5, SignedBits) \ V_(ImmLLiteral, 23, 5, SignedBits) \ V_(ImmException, 20, 5, Bits) \ V_(ImmHint, 11, 5, Bits) \ +V_(ImmBarrierDomain, 11, 10, Bits) \ +V_(ImmBarrierType, 9, 8, Bits) \ \ /* System (MRS, MSR) */ \ V_(ImmSystemRegister, 19, 5, Bits) \ @@ -181,7 +183,7 @@ enum Condition { inline Condition InvertCondition(Condition cond) { // Conditions al and nv behave identically, as "always true". They can't be // inverted, because there is no "always false" condition. - ASSERT((cond != al) && (cond != nv)); + VIXL_ASSERT((cond != al) && (cond != nv)); return static_cast<Condition>(cond ^ 1); } @@ -246,6 +248,20 @@ enum SystemHint { SEVL = 5 }; +enum BarrierDomain { + OuterShareable = 0, + NonShareable = 1, + InnerShareable = 2, + FullSystem = 3 +}; + +enum BarrierType { + BarrierOther = 0, + BarrierReads = 1, + BarrierWrites = 2, + BarrierAll = 3 +}; + // System/special register names. // This information is not encoded as one field but as the concatenation of // multiple fields (Op0<0>, Op1, Crn, Crm, Op2). @@ -274,7 +290,7 @@ enum SystemRegister { // // The enumerations can be used like this: // -// ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed); +// VIXL_ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed); // switch(instr->Mask(PCRelAddressingMask)) { // case ADR: Format("adr 'Xd, 'AddrPCRelByte"); break; // case ADRP: Format("adrp 'Xd, 'AddrPCRelPage"); break; @@ -560,6 +576,15 @@ enum ExceptionOp { DCPS3 = ExceptionFixed | 0x00A00003 }; +enum MemBarrierOp { + MemBarrierFixed = 0xD503309F, + MemBarrierFMask = 0xFFFFF09F, + MemBarrierMask = 0xFFFFF0FF, + DSB = MemBarrierFixed | 0x00000000, + DMB = MemBarrierFixed | 0x00000020, + ISB = MemBarrierFixed | 0x00000040 +}; + // Any load or store. enum LoadStoreAnyOp { LoadStoreAnyFMask = 0x0a000000, @@ -927,17 +952,22 @@ enum FPDataProcessing1SourceOp { FRINTN = FRINTN_s, FRINTP_s = FPDataProcessing1SourceFixed | 0x00048000, FRINTP_d = FPDataProcessing1SourceFixed | FP64 | 0x00048000, + FRINTP = FRINTP_s, FRINTM_s = FPDataProcessing1SourceFixed | 0x00050000, FRINTM_d = FPDataProcessing1SourceFixed | FP64 | 0x00050000, + FRINTM = FRINTM_s, FRINTZ_s = FPDataProcessing1SourceFixed | 0x00058000, FRINTZ_d = FPDataProcessing1SourceFixed | FP64 | 0x00058000, FRINTZ = FRINTZ_s, FRINTA_s = FPDataProcessing1SourceFixed | 0x00060000, FRINTA_d = FPDataProcessing1SourceFixed | FP64 | 0x00060000, + FRINTA = FRINTA_s, FRINTX_s = FPDataProcessing1SourceFixed | 0x00070000, FRINTX_d = FPDataProcessing1SourceFixed | FP64 | 0x00070000, + FRINTX = FRINTX_s, FRINTI_s = FPDataProcessing1SourceFixed | 0x00078000, - FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000 + FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000, + FRINTI = FRINTI_s }; // Floating point data processing 2 source. diff --git a/disas/libvixl/a64/decoder-a64.cc b/disas/libvixl/a64/decoder-a64.cc index 9e9033c49c..8450eb3b49 100644 --- a/disas/libvixl/a64/decoder-a64.cc +++ b/disas/libvixl/a64/decoder-a64.cc @@ -132,7 +132,7 @@ void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor, } // We reached the end of the list. The last element must be // registered_visitor. - ASSERT(*it == registered_visitor); + VIXL_ASSERT(*it == registered_visitor); visitors_.insert(it, new_visitor); } @@ -150,7 +150,7 @@ void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor, } // We reached the end of the list. The last element must be // registered_visitor. - ASSERT(*it == registered_visitor); + VIXL_ASSERT(*it == registered_visitor); visitors_.push_back(new_visitor); } @@ -161,16 +161,16 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) { void Decoder::DecodePCRelAddressing(Instruction* instr) { - ASSERT(instr->Bits(27, 24) == 0x0); + VIXL_ASSERT(instr->Bits(27, 24) == 0x0); // We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level // decode. - ASSERT(instr->Bit(28) == 0x1); + VIXL_ASSERT(instr->Bit(28) == 0x1); VisitPCRelAddressing(instr); } void Decoder::DecodeBranchSystemException(Instruction* instr) { - ASSERT((instr->Bits(27, 24) == 0x4) || + VIXL_ASSERT((instr->Bits(27, 24) == 0x4) || (instr->Bits(27, 24) == 0x5) || (instr->Bits(27, 24) == 0x6) || (instr->Bits(27, 24) == 0x7) ); @@ -271,7 +271,7 @@ void Decoder::DecodeBranchSystemException(Instruction* instr) { void Decoder::DecodeLoadStore(Instruction* instr) { - ASSERT((instr->Bits(27, 24) == 0x8) || + VIXL_ASSERT((instr->Bits(27, 24) == 0x8) || (instr->Bits(27, 24) == 0x9) || (instr->Bits(27, 24) == 0xC) || (instr->Bits(27, 24) == 0xD) ); @@ -390,7 +390,7 @@ void Decoder::DecodeLoadStore(Instruction* instr) { void Decoder::DecodeLogical(Instruction* instr) { - ASSERT(instr->Bits(27, 24) == 0x2); + VIXL_ASSERT(instr->Bits(27, 24) == 0x2); if (instr->Mask(0x80400000) == 0x00400000) { VisitUnallocated(instr); @@ -409,7 +409,7 @@ void Decoder::DecodeLogical(Instruction* instr) { void Decoder::DecodeBitfieldExtract(Instruction* instr) { - ASSERT(instr->Bits(27, 24) == 0x3); + VIXL_ASSERT(instr->Bits(27, 24) == 0x3); if ((instr->Mask(0x80400000) == 0x80000000) || (instr->Mask(0x80400000) == 0x00400000) || @@ -434,7 +434,7 @@ void Decoder::DecodeBitfieldExtract(Instruction* instr) { void Decoder::DecodeAddSubImmediate(Instruction* instr) { - ASSERT(instr->Bits(27, 24) == 0x1); + VIXL_ASSERT(instr->Bits(27, 24) == 0x1); if (instr->Bit(23) == 1) { VisitUnallocated(instr); } else { @@ -444,8 +444,8 @@ void Decoder::DecodeAddSubImmediate(Instruction* instr) { void Decoder::DecodeDataProcessing(Instruction* instr) { - ASSERT((instr->Bits(27, 24) == 0xA) || - (instr->Bits(27, 24) == 0xB) ); + VIXL_ASSERT((instr->Bits(27, 24) == 0xA) || + (instr->Bits(27, 24) == 0xB)); if (instr->Bit(24) == 0) { if (instr->Bit(28) == 0) { @@ -559,8 +559,8 @@ void Decoder::DecodeDataProcessing(Instruction* instr) { void Decoder::DecodeFP(Instruction* instr) { - ASSERT((instr->Bits(27, 24) == 0xE) || - (instr->Bits(27, 24) == 0xF) ); + VIXL_ASSERT((instr->Bits(27, 24) == 0xE) || + (instr->Bits(27, 24) == 0xF)); if (instr->Bit(28) == 0) { DecodeAdvSIMDDataProcessing(instr); @@ -665,14 +665,14 @@ void Decoder::DecodeFP(Instruction* instr) { VisitFPConditionalSelect(instr); break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } } } } } else { // Bit 30 == 1 has been handled earlier. - ASSERT(instr->Bit(30) == 0); + VIXL_ASSERT(instr->Bit(30) == 0); if (instr->Mask(0xA0800000) != 0) { VisitUnallocated(instr); } else { @@ -687,21 +687,21 @@ void Decoder::DecodeFP(Instruction* instr) { void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) { // TODO: Implement Advanced SIMD load/store instruction decode. - ASSERT(instr->Bits(29, 25) == 0x6); + VIXL_ASSERT(instr->Bits(29, 25) == 0x6); VisitUnimplemented(instr); } void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) { // TODO: Implement Advanced SIMD data processing instruction decode. - ASSERT(instr->Bits(27, 25) == 0x7); + VIXL_ASSERT(instr->Bits(27, 25) == 0x7); VisitUnimplemented(instr); } #define DEFINE_VISITOR_CALLERS(A) \ void Decoder::Visit##A(Instruction *instr) { \ - ASSERT(instr->Mask(A##FMask) == A##Fixed); \ + VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \ std::list<DecoderVisitor*>::iterator it; \ for (it = visitors_.begin(); it != visitors_.end(); it++) { \ (*it)->Visit##A(instr); \ diff --git a/disas/libvixl/a64/disasm-a64.cc b/disas/libvixl/a64/disasm-a64.cc index 5f172da7d3..aa133a99bf 100644 --- a/disas/libvixl/a64/disasm-a64.cc +++ b/disas/libvixl/a64/disasm-a64.cc @@ -95,7 +95,7 @@ void Disassembler::VisitAddSubImmediate(Instruction* instr) { } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -142,7 +142,7 @@ void Disassembler::VisitAddSubShifted(Instruction* instr) { } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -180,7 +180,7 @@ void Disassembler::VisitAddSubExtended(Instruction* instr) { } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -215,7 +215,7 @@ void Disassembler::VisitAddSubWithCarry(Instruction* instr) { } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -258,30 +258,30 @@ void Disassembler::VisitLogicalImmediate(Instruction* instr) { } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) { - ASSERT((reg_size == kXRegSize) || - ((reg_size == kWRegSize) && (value <= 0xffffffff))); + VIXL_ASSERT((reg_size == kXRegSize) || + ((reg_size == kWRegSize) && (value <= 0xffffffff))); // Test for movz: 16 bits set at positions 0, 16, 32 or 48. - if (((value & 0xffffffffffff0000ULL) == 0ULL) || - ((value & 0xffffffff0000ffffULL) == 0ULL) || - ((value & 0xffff0000ffffffffULL) == 0ULL) || - ((value & 0x0000ffffffffffffULL) == 0ULL)) { + if (((value & UINT64_C(0xffffffffffff0000)) == 0) || + ((value & UINT64_C(0xffffffff0000ffff)) == 0) || + ((value & UINT64_C(0xffff0000ffffffff)) == 0) || + ((value & UINT64_C(0x0000ffffffffffff)) == 0)) { return true; } // Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48). if ((reg_size == kXRegSize) && - (((value & 0xffffffffffff0000ULL) == 0xffffffffffff0000ULL) || - ((value & 0xffffffff0000ffffULL) == 0xffffffff0000ffffULL) || - ((value & 0xffff0000ffffffffULL) == 0xffff0000ffffffffULL) || - ((value & 0x0000ffffffffffffULL) == 0x0000ffffffffffffULL))) { + (((~value & UINT64_C(0xffffffffffff0000)) == 0) || + ((~value & UINT64_C(0xffffffff0000ffff)) == 0) || + ((~value & UINT64_C(0xffff0000ffffffff)) == 0) || + ((~value & UINT64_C(0x0000ffffffffffff)) == 0))) { return true; } if ((reg_size == kWRegSize) && @@ -337,7 +337,7 @@ void Disassembler::VisitLogicalShifted(Instruction* instr) { } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); @@ -353,7 +353,7 @@ void Disassembler::VisitConditionalCompareRegister(Instruction* instr) { case CCMN_x: mnemonic = "ccmn"; break; case CCMP_w: case CCMP_x: mnemonic = "ccmp"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -368,7 +368,7 @@ void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) { case CCMN_x_imm: mnemonic = "ccmn"; break; case CCMP_w_imm: case CCMP_x_imm: mnemonic = "ccmp"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -421,7 +421,7 @@ void Disassembler::VisitConditionalSelect(Instruction* instr) { } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -520,7 +520,7 @@ void Disassembler::VisitExtract(Instruction* instr) { } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -538,7 +538,7 @@ void Disassembler::VisitPCRelAddressing(Instruction* instr) { void Disassembler::VisitConditionalBranch(Instruction* instr) { switch (instr->Mask(ConditionalBranchMask)) { case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } } @@ -570,7 +570,7 @@ void Disassembler::VisitUnconditionalBranch(Instruction* instr) { switch (instr->Mask(UnconditionalBranchMask)) { case B: mnemonic = "b"; break; case BL: mnemonic = "bl"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -591,7 +591,7 @@ void Disassembler::VisitDataProcessing1Source(Instruction* instr) { FORMAT(CLS, "cls"); #undef FORMAT case REV32_x: mnemonic = "rev32"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -690,7 +690,7 @@ void Disassembler::VisitDataProcessing3Source(Instruction* instr) { form = form_xxx; break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -705,7 +705,7 @@ void Disassembler::VisitCompareBranch(Instruction* instr) { case CBZ_x: mnemonic = "cbz"; break; case CBNZ_w: case CBNZ_x: mnemonic = "cbnz"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -722,7 +722,7 @@ void Disassembler::VisitTestBranch(Instruction* instr) { switch (instr->Mask(TestBranchMask)) { case TBZ: mnemonic = "tbz"; break; case TBNZ: mnemonic = "tbnz"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -742,7 +742,7 @@ void Disassembler::VisitMoveWideImmediate(Instruction* instr) { case MOVZ_x: mnemonic = "movz"; break; case MOVK_w: case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -981,7 +981,7 @@ void Disassembler::VisitFPConditionalSelect(Instruction* instr) { switch (instr->Mask(FPConditionalSelectMask)) { case FCSEL_s: case FCSEL_d: mnemonic = "fcsel"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -1033,7 +1033,7 @@ void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) { FORMAT(FMINNM, "fminnm"); FORMAT(FNMUL, "fnmul"); #undef FORMAT - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -1052,7 +1052,7 @@ void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) { FORMAT(FNMADD, "fnmadd"); FORMAT(FNMSUB, "fnmsub"); #undef FORMAT - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -1065,7 +1065,7 @@ void Disassembler::VisitFPImmediate(Instruction* instr) { switch (instr->Mask(FPImmediateMask)) { case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break; case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -1082,6 +1082,14 @@ void Disassembler::VisitFPIntegerConvert(Instruction* instr) { case FMOV_xd: mnemonic = "fmov"; form = form_rf; break; case FMOV_sw: case FMOV_dx: mnemonic = "fmov"; form = form_fr; break; + case FCVTAS_ws: + case FCVTAS_xs: + case FCVTAS_wd: + case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break; + case FCVTAU_ws: + case FCVTAU_xs: + case FCVTAU_wd: + case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break; case FCVTMS_ws: case FCVTMS_xs: case FCVTMS_wd: @@ -1141,7 +1149,7 @@ void Disassembler::VisitFPFixedPointConvert(Instruction* instr) { case UCVTF_sx_fixed: case UCVTF_dw_fixed: case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } Format(instr, mnemonic, form); } @@ -1176,7 +1184,7 @@ void Disassembler::VisitSystem(Instruction* instr) { } } } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) { - ASSERT(instr->Mask(SystemHintMask) == HINT); + VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT); switch (instr->ImmHint()) { case NOP: { mnemonic = "nop"; @@ -1184,6 +1192,24 @@ void Disassembler::VisitSystem(Instruction* instr) { break; } } + } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) { + switch (instr->Mask(MemBarrierMask)) { + case DMB: { + mnemonic = "dmb"; + form = "'M"; + break; + } + case DSB: { + mnemonic = "dsb"; + form = "'M"; + break; + } + case ISB: { + mnemonic = "isb"; + form = NULL; + break; + } + } } Format(instr, mnemonic, form); @@ -1226,7 +1252,7 @@ void Disassembler::ProcessOutput(Instruction* /*instr*/) { void Disassembler::Format(Instruction* instr, const char* mnemonic, const char* format) { - ASSERT(mnemonic != NULL); + VIXL_ASSERT(mnemonic != NULL); ResetOutput(); Substitute(instr, mnemonic); if (format != NULL) { @@ -1268,8 +1294,9 @@ int Disassembler::SubstituteField(Instruction* instr, const char* format) { case 'A': return SubstitutePCRelAddressField(instr, format); case 'B': return SubstituteBranchTargetField(instr, format); case 'O': return SubstituteLSRegOffsetField(instr, format); + case 'M': return SubstituteBarrierField(instr, format); default: { - UNREACHABLE(); + VIXL_UNREACHABLE(); return 1; } } @@ -1294,7 +1321,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr, } break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } // Increase field length for registers tagged as stack. @@ -1331,7 +1358,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr, int Disassembler::SubstituteImmediateField(Instruction* instr, const char* format) { - ASSERT(format[0] == 'I'); + VIXL_ASSERT(format[0] == 'I'); switch (format[1]) { case 'M': { // IMoveImm or IMoveLSL. @@ -1339,10 +1366,10 @@ int Disassembler::SubstituteImmediateField(Instruction* instr, uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide()); AppendToOutput("#0x%" PRIx64, imm); } else { - ASSERT(format[5] == 'L'); + VIXL_ASSERT(format[5] == 'L'); AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide()); if (instr->ShiftMoveWide() > 0) { - AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide()); + AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); } } return 8; @@ -1384,14 +1411,14 @@ int Disassembler::SubstituteImmediateField(Instruction* instr, return 6; } case 'A': { // IAddSub. - ASSERT(instr->ShiftAddSub() <= 1); + VIXL_ASSERT(instr->ShiftAddSub() <= 1); int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub()); AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm); return 7; } case 'F': { // IFPSingle, IFPDouble or IFPFBits. if (format[3] == 'F') { // IFPFbits. - AppendToOutput("#%" PRId64, 64 - instr->FPScale()); + AppendToOutput("#%d", 64 - instr->FPScale()); return 8; } else { AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(), @@ -1412,27 +1439,27 @@ int Disassembler::SubstituteImmediateField(Instruction* instr, return 5; } case 'P': { // IP - Conditional compare. - AppendToOutput("#%" PRId64, instr->ImmCondCmp()); + AppendToOutput("#%d", instr->ImmCondCmp()); return 2; } case 'B': { // Bitfields. return SubstituteBitfieldImmediateField(instr, format); } case 'E': { // IExtract. - AppendToOutput("#%" PRId64, instr->ImmS()); + AppendToOutput("#%d", instr->ImmS()); return 8; } case 'S': { // IS - Test and branch bit. - AppendToOutput("#%" PRId64, (instr->ImmTestBranchBit5() << 5) | - instr->ImmTestBranchBit40()); + AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | + instr->ImmTestBranchBit40()); return 2; } case 'D': { // IDebug - HLT and BRK instructions. - AppendToOutput("#0x%" PRIx64, instr->ImmException()); + AppendToOutput("#0x%x", instr->ImmException()); return 6; } default: { - UNIMPLEMENTED(); + VIXL_UNIMPLEMENTED(); return 0; } } @@ -1441,7 +1468,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr, int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr, const char* format) { - ASSERT((format[0] == 'I') && (format[1] == 'B')); + VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B')); unsigned r = instr->ImmR(); unsigned s = instr->ImmS(); @@ -1455,19 +1482,19 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr, AppendToOutput("#%d", s + 1); return 5; } else { - ASSERT(format[3] == '-'); + VIXL_ASSERT(format[3] == '-'); AppendToOutput("#%d", s - r + 1); return 7; } } case 'Z': { // IBZ-r. - ASSERT((format[3] == '-') && (format[4] == 'r')); + VIXL_ASSERT((format[3] == '-') && (format[4] == 'r')); unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize; AppendToOutput("#%d", reg_size - r); return 5; } default: { - UNREACHABLE(); + VIXL_UNREACHABLE(); return 0; } } @@ -1476,7 +1503,7 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr, int Disassembler::SubstituteLiteralField(Instruction* instr, const char* format) { - ASSERT(strncmp(format, "LValue", 6) == 0); + VIXL_ASSERT(strncmp(format, "LValue", 6) == 0); USE(format); switch (instr->Mask(LoadLiteralMask)) { @@ -1484,7 +1511,7 @@ int Disassembler::SubstituteLiteralField(Instruction* instr, case LDR_x_lit: case LDR_s_lit: case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break; - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } return 6; @@ -1492,12 +1519,12 @@ int Disassembler::SubstituteLiteralField(Instruction* instr, int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) { - ASSERT(format[0] == 'H'); - ASSERT(instr->ShiftDP() <= 0x3); + VIXL_ASSERT(format[0] == 'H'); + VIXL_ASSERT(instr->ShiftDP() <= 0x3); switch (format[1]) { case 'D': { // HDP. - ASSERT(instr->ShiftDP() != ROR); + VIXL_ASSERT(instr->ShiftDP() != ROR); } // Fall through. case 'L': { // HLo. if (instr->ImmDPShift() != 0) { @@ -1508,7 +1535,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) { return 3; } default: - UNIMPLEMENTED(); + VIXL_UNIMPLEMENTED(); return 0; } } @@ -1516,7 +1543,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) { int Disassembler::SubstituteConditionField(Instruction* instr, const char* format) { - ASSERT(format[0] == 'C'); + VIXL_ASSERT(format[0] == 'C'); const char* condition_code[] = { "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", @@ -1538,27 +1565,27 @@ int Disassembler::SubstituteConditionField(Instruction* instr, int Disassembler::SubstitutePCRelAddressField(Instruction* instr, const char* format) { USE(format); - ASSERT(strncmp(format, "AddrPCRel", 9) == 0); + VIXL_ASSERT(strncmp(format, "AddrPCRel", 9) == 0); int offset = instr->ImmPCRel(); // Only ADR (AddrPCRelByte) is supported. - ASSERT(strcmp(format, "AddrPCRelByte") == 0); + VIXL_ASSERT(strcmp(format, "AddrPCRelByte") == 0); char sign = '+'; if (offset < 0) { offset = -offset; sign = '-'; } - // TODO: Extend this to support printing the target address. - AppendToOutput("#%c0x%x", sign, offset); + VIXL_STATIC_ASSERT(sizeof(*instr) == 1); + AppendToOutput("#%c0x%x (addr %p)", sign, offset, instr + offset); return 13; } int Disassembler::SubstituteBranchTargetField(Instruction* instr, const char* format) { - ASSERT(strncmp(format, "BImm", 4) == 0); + VIXL_ASSERT(strncmp(format, "BImm", 4) == 0); int64_t offset = 0; switch (format[5]) { @@ -1570,7 +1597,7 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr, case 'm': offset = instr->ImmCmpBranch(); break; // BImmTest - test and branch immediate. case 'e': offset = instr->ImmTestBranch(); break; - default: UNIMPLEMENTED(); + default: VIXL_UNIMPLEMENTED(); } offset <<= kInstructionSizeLog2; char sign = '+'; @@ -1578,15 +1605,16 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr, offset = -offset; sign = '-'; } - AppendToOutput("#%c0x%" PRIx64, sign, offset); + VIXL_STATIC_ASSERT(sizeof(*instr) == 1); + AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, instr + offset); return 8; } int Disassembler::SubstituteExtendField(Instruction* instr, const char* format) { - ASSERT(strncmp(format, "Ext", 3) == 0); - ASSERT(instr->ExtendMode() <= 7); + VIXL_ASSERT(strncmp(format, "Ext", 3) == 0); + VIXL_ASSERT(instr->ExtendMode() <= 7); USE(format); const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx", @@ -1598,12 +1626,12 @@ int Disassembler::SubstituteExtendField(Instruction* instr, (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) || (instr->ExtendMode() == UXTX))) { if (instr->ImmExtendShift() > 0) { - AppendToOutput(", lsl #%" PRId64, instr->ImmExtendShift()); + AppendToOutput(", lsl #%d", instr->ImmExtendShift()); } } else { AppendToOutput(", %s", extend_mode[instr->ExtendMode()]); if (instr->ImmExtendShift() > 0) { - AppendToOutput(" #%" PRId64, instr->ImmExtendShift()); + AppendToOutput(" #%d", instr->ImmExtendShift()); } } return 3; @@ -1612,7 +1640,7 @@ int Disassembler::SubstituteExtendField(Instruction* instr, int Disassembler::SubstituteLSRegOffsetField(Instruction* instr, const char* format) { - ASSERT(strncmp(format, "Offsetreg", 9) == 0); + VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0); const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl", "undefined", "undefined", "sxtw", "sxtx" }; USE(format); @@ -1632,7 +1660,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr, if (!((ext == UXTX) && (shift == 0))) { AppendToOutput(", %s", extend_mode[ext]); if (shift != 0) { - AppendToOutput(" #%" PRId64, instr->SizeLS()); + AppendToOutput(" #%d", instr->SizeLS()); } } return 9; @@ -1641,7 +1669,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr, int Disassembler::SubstitutePrefetchField(Instruction* instr, const char* format) { - ASSERT(format[0] == 'P'); + VIXL_ASSERT(format[0] == 'P'); USE(format); int prefetch_mode = instr->PrefetchMode(); @@ -1654,6 +1682,23 @@ int Disassembler::SubstitutePrefetchField(Instruction* instr, return 6; } +int Disassembler::SubstituteBarrierField(Instruction* instr, + const char* format) { + VIXL_ASSERT(format[0] == 'M'); + USE(format); + + static const char* options[4][4] = { + { "sy (0b0000)", "oshld", "oshst", "osh" }, + { "sy (0b0100)", "nshld", "nshst", "nsh" }, + { "sy (0b1000)", "ishld", "ishst", "ish" }, + { "sy (0b1100)", "ld", "st", "sy" } + }; + int domain = instr->ImmBarrierDomain(); + int type = instr->ImmBarrierType(); + + AppendToOutput("%s", options[domain][type]); + return 1; +} void Disassembler::ResetOutput() { buffer_pos_ = 0; diff --git a/disas/libvixl/a64/disasm-a64.h b/disas/libvixl/a64/disasm-a64.h index 857a5acac4..3a56e15515 100644 --- a/disas/libvixl/a64/disasm-a64.h +++ b/disas/libvixl/a64/disasm-a64.h @@ -64,6 +64,7 @@ class Disassembler: public DecoderVisitor { int SubstituteBranchTargetField(Instruction* instr, const char* format); int SubstituteLSRegOffsetField(Instruction* instr, const char* format); int SubstitutePrefetchField(Instruction* instr, const char* format); + int SubstituteBarrierField(Instruction* instr, const char* format); inline bool RdIsZROrSP(Instruction* instr) const { return (instr->Rd() == kZeroRegCode); diff --git a/disas/libvixl/a64/instructions-a64.cc b/disas/libvixl/a64/instructions-a64.cc index e87fa3acce..c4eb7c4518 100644 --- a/disas/libvixl/a64/instructions-a64.cc +++ b/disas/libvixl/a64/instructions-a64.cc @@ -33,20 +33,20 @@ namespace vixl { static uint64_t RotateRight(uint64_t value, unsigned int rotate, unsigned int width) { - ASSERT(width <= 64); + VIXL_ASSERT(width <= 64); rotate &= 63; - return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) | - (value >> rotate); + return ((value & ((UINT64_C(1) << rotate) - 1)) << + (width - rotate)) | (value >> rotate); } static uint64_t RepeatBitsAcrossReg(unsigned reg_size, uint64_t value, unsigned width) { - ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) || - (width == 32)); - ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); - uint64_t result = value & ((1UL << width) - 1UL); + VIXL_ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) || + (width == 32)); + VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize)); + uint64_t result = value & ((UINT64_C(1) << width) - 1); for (unsigned i = width; i < reg_size; i *= 2) { result |= (result << i); } @@ -84,7 +84,7 @@ uint64_t Instruction::ImmLogical() { if (imm_s == 0x3F) { return 0; } - uint64_t bits = (1UL << (imm_s + 1)) - 1; + uint64_t bits = (UINT64_C(1) << (imm_s + 1)) - 1; return RotateRight(bits, imm_r, 64); } else { if ((imm_s >> 1) == 0x1F) { @@ -96,14 +96,14 @@ uint64_t Instruction::ImmLogical() { if ((imm_s & mask) == mask) { return 0; } - uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1; + uint64_t bits = (UINT64_C(1) << ((imm_s & mask) + 1)) - 1; return RepeatBitsAcrossReg(reg_size, RotateRight(bits, imm_r & mask, width), width); } } } - UNREACHABLE(); + VIXL_UNREACHABLE(); return 0; } @@ -155,7 +155,7 @@ Instruction* Instruction::ImmPCOffsetTarget() { offset = ImmPCRel(); } else { // All PC-relative branches. - ASSERT(BranchType() != UnknownBranchType); + VIXL_ASSERT(BranchType() != UnknownBranchType); // Relative branch offsets are instruction-size-aligned. offset = ImmBranch() << kInstructionSizeLog2; } @@ -169,7 +169,7 @@ inline int Instruction::ImmBranch() const { case UncondBranchType: return ImmUncondBranch(); case CompareBranchType: return ImmCmpBranch(); case TestBranchType: return ImmTestBranch(); - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } return 0; } @@ -186,7 +186,7 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) { void Instruction::SetPCRelImmTarget(Instruction* target) { // ADRP is not supported, so 'this' must point to an ADR instruction. - ASSERT(Mask(PCRelAddressingMask) == ADR); + VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR); Instr imm = Assembler::ImmPCRelAddress(target - this); @@ -195,7 +195,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) { void Instruction::SetBranchImmTarget(Instruction* target) { - ASSERT(((target - this) & 3) == 0); + VIXL_ASSERT(((target - this) & 3) == 0); Instr branch_imm = 0; uint32_t imm_mask = 0; int offset = (target - this) >> kInstructionSizeLog2; @@ -220,14 +220,14 @@ void Instruction::SetBranchImmTarget(Instruction* target) { imm_mask = ImmTestBranch_mask; break; } - default: UNREACHABLE(); + default: VIXL_UNREACHABLE(); } SetInstructionBits(Mask(~imm_mask) | branch_imm); } void Instruction::SetImmLLiteral(Instruction* source) { - ASSERT(((source - this) & 3) == 0); + VIXL_ASSERT(((source - this) & 3) == 0); int offset = (source - this) >> kLiteralEntrySizeLog2; Instr imm = Assembler::ImmLLiteral(offset); Instr mask = ImmLLiteral_mask; diff --git a/disas/libvixl/a64/instructions-a64.h b/disas/libvixl/a64/instructions-a64.h index ba9068ca8b..a4240d7d33 100644 --- a/disas/libvixl/a64/instructions-a64.h +++ b/disas/libvixl/a64/instructions-a64.h @@ -44,30 +44,36 @@ const unsigned kMaxLoadLiteralRange = 1 * MBytes; const unsigned kWRegSize = 32; const unsigned kWRegSizeLog2 = 5; const unsigned kWRegSizeInBytes = kWRegSize / 8; +const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3; const unsigned kXRegSize = 64; const unsigned kXRegSizeLog2 = 6; const unsigned kXRegSizeInBytes = kXRegSize / 8; +const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3; const unsigned kSRegSize = 32; const unsigned kSRegSizeLog2 = 5; const unsigned kSRegSizeInBytes = kSRegSize / 8; +const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3; const unsigned kDRegSize = 64; const unsigned kDRegSizeLog2 = 6; const unsigned kDRegSizeInBytes = kDRegSize / 8; -const int64_t kWRegMask = 0x00000000ffffffffLL; -const int64_t kXRegMask = 0xffffffffffffffffLL; -const int64_t kSRegMask = 0x00000000ffffffffLL; -const int64_t kDRegMask = 0xffffffffffffffffLL; -const int64_t kXSignMask = 0x1LL << 63; -const int64_t kWSignMask = 0x1LL << 31; -const int64_t kByteMask = 0xffL; -const int64_t kHalfWordMask = 0xffffL; -const int64_t kWordMask = 0xffffffffLL; -const uint64_t kXMaxUInt = 0xffffffffffffffffULL; -const uint64_t kWMaxUInt = 0xffffffffULL; -const int64_t kXMaxInt = 0x7fffffffffffffffLL; -const int64_t kXMinInt = 0x8000000000000000LL; -const int32_t kWMaxInt = 0x7fffffff; -const int32_t kWMinInt = 0x80000000; +const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3; +const uint64_t kWRegMask = UINT64_C(0xffffffff); +const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff); +const uint64_t kSRegMask = UINT64_C(0xffffffff); +const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff); +const uint64_t kSSignMask = UINT64_C(0x80000000); +const uint64_t kDSignMask = UINT64_C(0x8000000000000000); +const uint64_t kWSignMask = UINT64_C(0x80000000); +const uint64_t kXSignMask = UINT64_C(0x8000000000000000); +const uint64_t kByteMask = UINT64_C(0xff); +const uint64_t kHalfWordMask = UINT64_C(0xffff); +const uint64_t kWordMask = UINT64_C(0xffffffff); +const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff); +const uint64_t kWMaxUInt = UINT64_C(0xffffffff); +const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff); +const int64_t kXMinInt = INT64_C(0x8000000000000000); +const int32_t kWMaxInt = INT32_C(0x7fffffff); +const int32_t kWMinInt = INT32_C(0x80000000); const unsigned kLinkRegCode = 30; const unsigned kZeroRegCode = 31; const unsigned kSPRegInternalCode = 63; @@ -81,18 +87,28 @@ const unsigned kFloatExponentBits = 8; const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000); const float kFP32NegativeInfinity = rawbits_to_float(0xff800000); -const double kFP64PositiveInfinity = rawbits_to_double(0x7ff0000000000000ULL); -const double kFP64NegativeInfinity = rawbits_to_double(0xfff0000000000000ULL); +const double kFP64PositiveInfinity = + rawbits_to_double(UINT64_C(0x7ff0000000000000)); +const double kFP64NegativeInfinity = + rawbits_to_double(UINT64_C(0xfff0000000000000)); // This value is a signalling NaN as both a double and as a float (taking the // least-significant word). -static const double kFP64SignallingNaN = rawbits_to_double(0x7ff000007f800001ULL); +static const double kFP64SignallingNaN = + rawbits_to_double(UINT64_C(0x7ff000007f800001)); static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001); // A similar value, but as a quiet NaN. -static const double kFP64QuietNaN = rawbits_to_double(0x7ff800007fc00001ULL); +static const double kFP64QuietNaN = + rawbits_to_double(UINT64_C(0x7ff800007fc00001)); static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001); +// The default NaN values (for FPCR.DN=1). +static const double kFP64DefaultNaN = + rawbits_to_double(UINT64_C(0x7ff8000000000000)); +static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000); + + enum LSDataSize { LSByte = 0, LSHalfword = 1, @@ -325,7 +341,7 @@ class Instruction { } inline Instruction* InstructionAtOffset(int64_t offset) { - ASSERT(IsWordAligned(this + offset)); + VIXL_ASSERT(IsWordAligned(this + offset)); return this + offset; } diff --git a/disas/libvixl/globals.h b/disas/libvixl/globals.h index a6a3fccd8a..e28dc6663a 100644 --- a/disas/libvixl/globals.h +++ b/disas/libvixl/globals.h @@ -27,8 +27,20 @@ #ifndef VIXL_GLOBALS_H #define VIXL_GLOBALS_H -// Get the standard printf format macros for C99 stdint types. +// Get standard C99 macros for integer types. +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +#ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS +#endif + +#include <stdint.h> #include <inttypes.h> #include <assert.h> @@ -45,21 +57,29 @@ typedef uint8_t byte; const int KBytes = 1024; const int MBytes = 1024 * KBytes; - #define ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort() +#define VIXL_ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort() #ifdef DEBUG - #define ASSERT(condition) assert(condition) - #define CHECK(condition) ASSERT(condition) - #define UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); ABORT() - #define UNREACHABLE() printf("UNREACHABLE\t"); ABORT() + #define VIXL_ASSERT(condition) assert(condition) + #define VIXL_CHECK(condition) VIXL_ASSERT(condition) + #define VIXL_UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); VIXL_ABORT() + #define VIXL_UNREACHABLE() printf("UNREACHABLE\t"); VIXL_ABORT() #else - #define ASSERT(condition) ((void) 0) - #define CHECK(condition) assert(condition) - #define UNIMPLEMENTED() ((void) 0) - #define UNREACHABLE() ((void) 0) + #define VIXL_ASSERT(condition) ((void) 0) + #define VIXL_CHECK(condition) assert(condition) + #define VIXL_UNIMPLEMENTED() ((void) 0) + #define VIXL_UNREACHABLE() ((void) 0) #endif +// This is not as powerful as template based assertions, but it is simple. +// It assumes that the descriptions are unique. If this starts being a problem, +// we can switch to a different implemention. +#define VIXL_CONCAT(a, b) a##b +#define VIXL_STATIC_ASSERT_LINE(line, condition) \ + typedef char VIXL_CONCAT(STATIC_ASSERT_LINE_, line)[(condition) ? 1 : -1] \ + __attribute__((unused)) +#define VIXL_STATIC_ASSERT(condition) VIXL_STATIC_ASSERT_LINE(__LINE__, condition) //NOLINT template <typename T> inline void USE(T) {} -#define ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); ABORT() +#define VIXL_ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); VIXL_ABORT() #endif // VIXL_GLOBALS_H diff --git a/disas/libvixl/platform.h b/disas/libvixl/platform.h index a2600f370d..b5c2085b90 100644 --- a/disas/libvixl/platform.h +++ b/disas/libvixl/platform.h @@ -34,9 +34,7 @@ namespace vixl { // Currently we assume running the simulator implies running on x86 hardware. inline void HostBreakpoint() { asm("int3"); } #else -inline void HostBreakpoint() { - // TODO: Implement HostBreakpoint on a64. -} +inline void HostBreakpoint() { asm("brk"); } #endif } // namespace vixl diff --git a/disas/libvixl/utils.cc b/disas/libvixl/utils.cc index a45fb95f47..c9c05d1e18 100644 --- a/disas/libvixl/utils.cc +++ b/disas/libvixl/utils.cc @@ -58,9 +58,9 @@ double rawbits_to_double(uint64_t bits) { int CountLeadingZeros(uint64_t value, int width) { - ASSERT((width == 32) || (width == 64)); + VIXL_ASSERT((width == 32) || (width == 64)); int count = 0; - uint64_t bit_test = 1UL << (width - 1); + uint64_t bit_test = UINT64_C(1) << (width - 1); while ((count < width) && ((bit_test & value) == 0)) { count++; bit_test >>= 1; @@ -70,7 +70,7 @@ int CountLeadingZeros(uint64_t value, int width) { int CountLeadingSignBits(int64_t value, int width) { - ASSERT((width == 32) || (width == 64)); + VIXL_ASSERT((width == 32) || (width == 64)); if (value >= 0) { return CountLeadingZeros(value, width) - 1; } else { @@ -80,7 +80,7 @@ int CountLeadingSignBits(int64_t value, int width) { int CountTrailingZeros(uint64_t value, int width) { - ASSERT((width == 32) || (width == 64)); + VIXL_ASSERT((width == 32) || (width == 64)); int count = 0; while ((count < width) && (((value >> count) & 1) == 0)) { count++; @@ -92,10 +92,10 @@ int CountTrailingZeros(uint64_t value, int width) { int CountSetBits(uint64_t value, int width) { // TODO: Other widths could be added here, as the implementation already // supports them. - ASSERT((width == 32) || (width == 64)); + VIXL_ASSERT((width == 32) || (width == 64)); // Mask out unused bits to ensure that they are not counted. - value &= (0xffffffffffffffffULL >> (64-width)); + value &= (UINT64_C(0xffffffffffffffff) >> (64-width)); // Add up the set bits. // The algorithm works by adding pairs of bit fields together iteratively, @@ -108,18 +108,19 @@ int CountSetBits(uint64_t value, int width) { // value = h+g+f+e d+c+b+a // \ | // value = h+g+f+e+d+c+b+a - value = ((value >> 1) & 0x5555555555555555ULL) + - (value & 0x5555555555555555ULL); - value = ((value >> 2) & 0x3333333333333333ULL) + - (value & 0x3333333333333333ULL); - value = ((value >> 4) & 0x0f0f0f0f0f0f0f0fULL) + - (value & 0x0f0f0f0f0f0f0f0fULL); - value = ((value >> 8) & 0x00ff00ff00ff00ffULL) + - (value & 0x00ff00ff00ff00ffULL); - value = ((value >> 16) & 0x0000ffff0000ffffULL) + - (value & 0x0000ffff0000ffffULL); - value = ((value >> 32) & 0x00000000ffffffffULL) + - (value & 0x00000000ffffffffULL); + const uint64_t kMasks[] = { + UINT64_C(0x5555555555555555), + UINT64_C(0x3333333333333333), + UINT64_C(0x0f0f0f0f0f0f0f0f), + UINT64_C(0x00ff00ff00ff00ff), + UINT64_C(0x0000ffff0000ffff), + UINT64_C(0x00000000ffffffff), + }; + + for (unsigned i = 0; i < (sizeof(kMasks) / sizeof(kMasks[0])); i++) { + int shift = 1 << i; + value = ((value >> shift) & kMasks[i]) + (value & kMasks[i]); + } return value; } diff --git a/disas/libvixl/utils.h b/disas/libvixl/utils.h index 029341eb14..83c928c8e3 100644 --- a/disas/libvixl/utils.h +++ b/disas/libvixl/utils.h @@ -27,7 +27,7 @@ #ifndef VIXL_UTILS_H #define VIXL_UTILS_H - +#include <math.h> #include <string.h> #include "globals.h" @@ -35,19 +35,19 @@ namespace vixl { // Check number width. inline bool is_intn(unsigned n, int64_t x) { - ASSERT((0 < n) && (n < 64)); - int64_t limit = 1ULL << (n - 1); + VIXL_ASSERT((0 < n) && (n < 64)); + int64_t limit = INT64_C(1) << (n - 1); return (-limit <= x) && (x < limit); } inline bool is_uintn(unsigned n, int64_t x) { - ASSERT((0 < n) && (n < 64)); + VIXL_ASSERT((0 < n) && (n < 64)); return !(x >> n); } inline unsigned truncate_to_intn(unsigned n, int64_t x) { - ASSERT((0 < n) && (n < 64)); - return (x & ((1ULL << n) - 1)); + VIXL_ASSERT((0 < n) && (n < 64)); + return (x & ((INT64_C(1) << n) - 1)); } #define INT_1_TO_63_LIST(V) \ @@ -90,13 +90,67 @@ inline int64_t signed_bitextract_64(int msb, int lsb, int64_t x) { return (x << (63 - msb)) >> (lsb + 63 - msb); } -// floating point representation +// Floating point representation. uint32_t float_to_rawbits(float value); uint64_t double_to_rawbits(double value); float rawbits_to_float(uint32_t bits); double rawbits_to_double(uint64_t bits); -// Bits counting. + +// NaN tests. +inline bool IsSignallingNaN(double num) { + const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000); + uint64_t raw = double_to_rawbits(num); + if (isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) { + return true; + } + return false; +} + + +inline bool IsSignallingNaN(float num) { + const uint32_t kFP32QuietNaNMask = 0x00400000; + uint32_t raw = float_to_rawbits(num); + if (isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) { + return true; + } + return false; +} + + +template <typename T> +inline bool IsQuietNaN(T num) { + return isnan(num) && !IsSignallingNaN(num); +} + + +// Convert the NaN in 'num' to a quiet NaN. +inline double ToQuietNaN(double num) { + const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000); + VIXL_ASSERT(isnan(num)); + return rawbits_to_double(double_to_rawbits(num) | kFP64QuietNaNMask); +} + + +inline float ToQuietNaN(float num) { + const uint32_t kFP32QuietNaNMask = 0x00400000; + VIXL_ASSERT(isnan(num)); + return rawbits_to_float(float_to_rawbits(num) | kFP32QuietNaNMask); +} + + +// Fused multiply-add. +inline double FusedMultiplyAdd(double op1, double op2, double a) { + return fma(op1, op2, a); +} + + +inline float FusedMultiplyAdd(float op1, float op2, float a) { + return fmaf(op1, op2, a); +} + + +// Bit counting. int CountLeadingZeros(uint64_t value, int width); int CountLeadingSignBits(int64_t value, int width); int CountTrailingZeros(uint64_t value, int width); @@ -106,20 +160,30 @@ int CountSetBits(uint64_t value, int width); // TODO: rename/refactor to make it specific to instructions. template<typename T> bool IsWordAligned(T pointer) { - ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof) + VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof) return (reinterpret_cast<intptr_t>(pointer) & 3) == 0; } // Increment a pointer until it has the specified alignment. template<class T> T AlignUp(T pointer, size_t alignment) { - ASSERT(sizeof(pointer) == sizeof(uintptr_t)); + VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t)); uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer); size_t align_step = (alignment - pointer_raw) % alignment; - ASSERT((pointer_raw + align_step) % alignment == 0); + VIXL_ASSERT((pointer_raw + align_step) % alignment == 0); return reinterpret_cast<T>(pointer_raw + align_step); } +// Decrement a pointer until it has the specified alignment. +template<class T> +T AlignDown(T pointer, size_t alignment) { + VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t)); + uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer); + size_t align_step = pointer_raw % alignment; + VIXL_ASSERT((pointer_raw - align_step) % alignment == 0); + return reinterpret_cast<T>(pointer_raw - align_step); +} + } // namespace vixl diff --git a/docs/migration.txt b/docs/migration.txt index fe1f2bb738..0492a4547a 100644 --- a/docs/migration.txt +++ b/docs/migration.txt @@ -139,7 +139,7 @@ static const VMStateDescription vmstate_kbd = { .name = "pckbd", .version_id = 3, .minimum_version_id = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(write_cmd, KBDState), VMSTATE_UINT8(status, KBDState), VMSTATE_UINT8(mode, KBDState), @@ -257,7 +257,7 @@ const VMStateDescription vmstate_ide_drive_pio_state = { .minimum_version_id = 1, .pre_save = ide_drive_pio_pre_save, .post_load = ide_drive_pio_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(req_nb_sectors, IDEState), VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1, vmstate_info_uint8, uint8_t), @@ -275,7 +275,7 @@ const VMStateDescription vmstate_ide_drive = { .version_id = 3, .minimum_version_id = 0, .post_load = ide_drive_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { .... several fields .... VMSTATE_END_OF_LIST() }, @@ -429,9 +429,8 @@ const VMStateDescription vmstate_cpu_common = { .name = "cpu_common", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = cpu_common_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(halted, CPUState), VMSTATE_UINT32(interrupt_request, CPUState), VMSTATE_END_OF_LIST() diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 46b9f1e0c0..24231e5448 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -134,7 +134,6 @@ static VMStateDescription vmstate_highbank_regs = { .name = "highbank-regs", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS), VMSTATE_END_OF_LIST(), diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index de542010aa..2a27a19d76 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -405,7 +405,6 @@ static const VMStateDescription mv88w8618_eth_vmsd = { .name = "mv88w8618_eth", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(smir, mv88w8618_eth_state), VMSTATE_UINT32(icr, mv88w8618_eth_state), @@ -642,7 +641,6 @@ static const VMStateDescription musicpal_lcd_vmsd = { .name = "musicpal_lcd", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(brightness, musicpal_lcd_state), VMSTATE_UINT32(mode, musicpal_lcd_state), @@ -769,7 +767,6 @@ static const VMStateDescription mv88w8618_pic_vmsd = { .name = "mv88w8618_pic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(level, mv88w8618_pic_state), VMSTATE_UINT32(enabled, mv88w8618_pic_state), @@ -940,7 +937,6 @@ static const VMStateDescription mv88w8618_timer_vmsd = { .name = "timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_PTIMER(ptimer, mv88w8618_timer_state), VMSTATE_UINT32(limit, mv88w8618_timer_state), @@ -952,7 +948,6 @@ static const VMStateDescription mv88w8618_pit_vmsd = { .name = "mv88w8618_pit", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1, mv88w8618_timer_vmsd, mv88w8618_timer_state), @@ -1041,7 +1036,6 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = { .name = "mv88w8618_flashcfg", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state), VMSTATE_END_OF_LIST() @@ -1381,7 +1375,6 @@ static const VMStateDescription musicpal_gpio_vmsd = { .name = "musicpal_gpio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state), VMSTATE_UINT32(out_state, musicpal_gpio_state), @@ -1548,7 +1541,6 @@ static const VMStateDescription musicpal_key_vmsd = { .name = "musicpal_key", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(kbd_extended, musicpal_key_state), VMSTATE_UINT32(pressed_keys, musicpal_key_state), diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index b433748c60..b28e0521b4 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -2709,8 +2709,8 @@ static void omap_rtc_write(void *opaque, hwaddr addr, s->ti += ti[1]; } else { /* A less accurate version */ - s->ti -= (s->current_tm.tm_year % 100) * 31536000; - s->ti += from_bcd(value) * 31536000; + s->ti -= (time_t)(s->current_tm.tm_year % 100) * 31536000; + s->ti += (time_t)from_bcd(value) * 31536000; } return; diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index e0cd847b95..2d28a11d5e 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -148,8 +148,7 @@ static const VMStateDescription vmstate_pxa2xx_pm = { .name = "pxa2xx_pm", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40), VMSTATE_END_OF_LIST() } @@ -215,8 +214,7 @@ static const VMStateDescription vmstate_pxa2xx_cm = { .name = "pxa2xx_cm", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4), VMSTATE_UINT32(clkcfg, PXA2xxState), VMSTATE_UINT32(pmnc, PXA2xxState), @@ -440,8 +438,7 @@ static const VMStateDescription vmstate_pxa2xx_mm = { .name = "pxa2xx_mm", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a), VMSTATE_END_OF_LIST() } @@ -1172,7 +1169,6 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = { .name = "pxa2xx_rtc", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .pre_save = pxa2xx_rtc_pre_save, .post_load = pxa2xx_rtc_post_load, .fields = (VMStateField[]) { @@ -1436,8 +1432,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c_slave = { .name = "pxa2xx_i2c_slave", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState), VMSTATE_END_OF_LIST() } @@ -1447,8 +1442,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c = { .name = "pxa2xx_i2c", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(control, PXA2xxI2CState), VMSTATE_UINT16(status, PXA2xxI2CState), VMSTATE_UINT8(ibmr, PXA2xxI2CState), @@ -1705,8 +1699,7 @@ static const VMStateDescription vmstate_pxa2xx_i2s = { .name = "pxa2xx_i2s", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2), VMSTATE_UINT32(status, PXA2xxI2SState), VMSTATE_UINT32(mask, PXA2xxI2SState), diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index 07274285ab..7f75f05137 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -313,8 +313,7 @@ static const VMStateDescription vmstate_pxa2xx_gpio_regs = { .name = "pxa2xx-gpio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(lines, PXA2xxGPIOInfo), VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS), diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index d37fb543e8..9cfc714874 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -296,7 +296,6 @@ static VMStateDescription vmstate_pxa2xx_pic_regs = { .name = "pxa2xx_pic", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = pxa2xx_pic_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2), diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 392ca84c81..a179c1d694 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -1006,8 +1006,7 @@ static VMStateDescription vmstate_sl_nand_info = { .name = "sl-nand", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(ctl, SLNANDState), VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState), VMSTATE_END_OF_LIST(), @@ -1041,9 +1040,8 @@ static VMStateDescription vmstate_spitz_kbd = { .name = "spitz-keyboard", .version_id = 1, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = spitz_keyboard_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(sense_state, SpitzKeyboardState), VMSTATE_UINT16(strobe_state, SpitzKeyboardState), VMSTATE_UNUSED_TEST(is_version_0, 5), @@ -1076,8 +1074,7 @@ static const VMStateDescription vmstate_corgi_ssp_regs = { .name = "corgi-ssp", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState), VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3), VMSTATE_END_OF_LIST(), @@ -1105,8 +1102,7 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = { .name = "spitz-lcdtg", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG), VMSTATE_UINT32(bl_intensity, SpitzLCDTG), VMSTATE_UINT32(bl_power, SpitzLCDTG), diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index d6cc77b458..a2095c0e84 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -185,12 +185,19 @@ static uint64_t gptm_read(void *opaque, hwaddr offset, case 0x44: /* TBPMR */ return s->match_prescale[1]; case 0x48: /* TAR */ - if (s->control == 1) + if (s->config == 1) { return s->rtc; + } + qemu_log_mask(LOG_UNIMP, + "GPTM: read of TAR but timer read not supported"); + return 0; case 0x4c: /* TBR */ - hw_error("TODO: Timer value read\n"); + qemu_log_mask(LOG_UNIMP, + "GPTM: read of TBR but timer read not supported"); + return 0; default: - hw_error("gptm_read: Bad offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "GPTM: read at bad offset 0x%x\n", (int)offset); return 0; } } @@ -286,8 +293,7 @@ static const VMStateDescription vmstate_stellaris_gptm = { .name = "stellaris_gptm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(config, gptm_state), VMSTATE_UINT32_ARRAY(mode, gptm_state, 2), VMSTATE_UINT32(control, gptm_state), @@ -643,9 +649,8 @@ static const VMStateDescription vmstate_stellaris_sys = { .name = "stellaris_sys", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = stellaris_sys_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(pborctl, ssys_state), VMSTATE_UINT32(ldopctl, ssys_state), VMSTATE_UINT32(int_mask, ssys_state), @@ -851,8 +856,7 @@ static const VMStateDescription vmstate_stellaris_i2c = { .name = "stellaris_i2c", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(msa, stellaris_i2c_state), VMSTATE_UINT32(mcs, stellaris_i2c_state), VMSTATE_UINT32(mdr, stellaris_i2c_state), @@ -1121,8 +1125,7 @@ static const VMStateDescription vmstate_stellaris_adc = { .name = "stellaris_adc", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(actss, stellaris_adc_state), VMSTATE_UINT32(ris, stellaris_adc_state), VMSTATE_UINT32(im, stellaris_adc_state), diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index 170d0ce267..0da9015333 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -199,7 +199,6 @@ static VMStateDescription vmstate_strongarm_pic_regs = { .name = "strongarm_pic", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = strongarm_pic_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32(pending, StrongARMPICState), @@ -424,7 +423,6 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = { .name = "strongarm-rtc", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .pre_save = strongarm_rtc_pre_save, .post_load = strongarm_rtc_post_load, .fields = (VMStateField[]) { @@ -670,7 +668,6 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = { .name = "strongarm-gpio", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_UINT32(ilevel, StrongARMGPIOInfo), VMSTATE_UINT32(olevel, StrongARMGPIOInfo), @@ -842,7 +839,6 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = { .name = "strongarm-ppc", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_UINT32(ilevel, StrongARMPPCInfo), VMSTATE_UINT32(olevel, StrongARMPPCInfo), @@ -1293,7 +1289,6 @@ static const VMStateDescription vmstate_strongarm_uart_regs = { .name = "strongarm-uart", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = strongarm_uart_post_load, .fields = (VMStateField[]) { VMSTATE_UINT8(utcr0, StrongARMUARTState), @@ -1553,7 +1548,6 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = { .name = "strongarm-ssp", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = strongarm_ssp_post_load, .fields = (VMStateField[]) { VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2), diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 67c1be84ac..5df014b15e 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -164,7 +164,6 @@ static VMStateDescription vmstate_zipit_lcd_state = { .name = "zipit-lcd", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(ssidev, ZipitLCD), VMSTATE_INT32(selected, ZipitLCD), @@ -275,7 +274,6 @@ static VMStateDescription vmstate_aer915_state = { .name = "aer915", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_INT32(len, AER915State), VMSTATE_BUFFER(buf, AER915State), diff --git a/hw/audio/lm4549.c b/hw/audio/lm4549.c index d75f7ec21f..380ef603bd 100644 --- a/hw/audio/lm4549.c +++ b/hw/audio/lm4549.c @@ -324,9 +324,8 @@ const VMStateDescription vmstate_lm4549_state = { .name = "lm4549_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .post_load = &lm4549_post_load, - .fields = (VMStateField[]) { + .post_load = lm4549_post_load, + .fields = (VMStateField[]) { VMSTATE_UINT32(voice_is_active, lm4549_state), VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128), VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE), diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c index cdce238f55..86992677e3 100644 --- a/hw/audio/marvell_88w8618.c +++ b/hw/audio/marvell_88w8618.c @@ -259,7 +259,6 @@ static const VMStateDescription mv88w8618_audio_vmsd = { .name = "mv88w8618_audio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(playback_mode, mv88w8618_audio_state), VMSTATE_UINT32(status, mv88w8618_audio_state), diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c index 9c0f7a092d..28f55e8535 100644 --- a/hw/audio/milkymist-ac97.c +++ b/hw/audio/milkymist-ac97.c @@ -316,9 +316,8 @@ static const VMStateDescription vmstate_milkymist_ac97 = { .name = "milkymist-ac97", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = ac97_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c index ed82be54e8..19982f2477 100644 --- a/hw/audio/pl041.c +++ b/hw/audio/pl041.c @@ -561,8 +561,7 @@ static const VMStateDescription vmstate_pl041_regfile = { .name = "pl041_regfile", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { #define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile), #include "pl041.hx" #undef REGISTER @@ -574,8 +573,7 @@ static const VMStateDescription vmstate_pl041_fifo = { .name = "pl041_fifo", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(level, pl041_fifo), VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH), VMSTATE_END_OF_LIST() @@ -586,8 +584,7 @@ static const VMStateDescription vmstate_pl041_channel = { .name = "pl041_channel", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_STRUCT(tx_fifo, pl041_channel, 0, vmstate_pl041_fifo, pl041_fifo), VMSTATE_UINT8(tx_enabled, pl041_channel), diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c index c18f2457a1..b50b331402 100644 --- a/hw/audio/wm8750.c +++ b/hw/audio/wm8750.c @@ -583,10 +583,9 @@ static const VMStateDescription vmstate_wm8750 = { .name = CODEC, .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .pre_save = wm8750_pre_save, .post_load = wm8750_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2), VMSTATE_INT32(i2c_len, WM8750State), VMSTATE_INT32(enable, WM8750State), diff --git a/hw/block/ecc.c b/hw/block/ecc.c index 8c888cc12a..10bb233089 100644 --- a/hw/block/ecc.c +++ b/hw/block/ecc.c @@ -81,8 +81,7 @@ VMStateDescription vmstate_ecc_state = { .name = "ecc-state", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(cp, ECCState), VMSTATE_UINT16_ARRAY(lp, ECCState, 2), VMSTATE_UINT16(count, ECCState), diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index e29a738d23..4076114b32 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -653,7 +653,6 @@ static const VMStateDescription vmstate_m25p80 = { .name = "xilinx_spi", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = m25p80_pre_save, .fields = (VMStateField[]) { VMSTATE_UINT8(state, Flash), diff --git a/hw/block/nand.c b/hw/block/nand.c index 6d7c804f01..38eefd436d 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -346,10 +346,9 @@ static const VMStateDescription vmstate_nand = { .name = "nand", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = nand_pre_save, .post_load = nand_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(cle, NANDFlashState), VMSTATE_UINT8(ale, NANDFlashState), VMSTATE_UINT8(ce, NANDFlashState), diff --git a/hw/block/onenand.c b/hw/block/onenand.c index aae9ee7536..60d5311d04 100644 --- a/hw/block/onenand.c +++ b/hw/block/onenand.c @@ -169,7 +169,6 @@ static const VMStateDescription vmstate_onenand = { .name = "onenand", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = onenand_pre_save, .post_load = onenand_post_load, .fields = (VMStateField[]) { diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 1012f1ad64..bf0c853499 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -504,7 +504,6 @@ static const VMStateDescription vmstate_cadence_uart = { .name = "cadence_uart", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .post_load = cadence_uart_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(r, UartState, R_MAX), diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c index fd8e07713d..8abe944de6 100644 --- a/hw/char/digic-uart.c +++ b/hw/char/digic-uart.c @@ -162,7 +162,6 @@ static const VMStateDescription vmstate_digic_uart = { .name = "digic-uart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(reg_rx, DigicUartState), VMSTATE_UINT32(reg_st, DigicUartState), diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 19b59ccddb..7614e5860f 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -560,7 +560,6 @@ static const VMStateDescription vmstate_exynos4210_uart_fifo = { .name = "exynos4210.uart.fifo", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(sp, Exynos4210UartFIFO), VMSTATE_UINT32(rp, Exynos4210UartFIFO), @@ -573,7 +572,6 @@ static const VMStateDescription vmstate_exynos4210_uart = { .name = "exynos4210.uart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(rx, Exynos4210UartState, 1, vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO), diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index 7f16835aeb..f3fbc776be 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -76,7 +76,6 @@ static const VMStateDescription vmstate_imx_serial = { .name = "imx-serial", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_INT32(readbuff, IMXSerialState), VMSTATE_UINT32(usr1, IMXSerialState), diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c index f9c388ed0b..c8d5cdb361 100644 --- a/hw/char/ipoctal232.c +++ b/hw/char/ipoctal232.c @@ -124,8 +124,7 @@ static const VMStateDescription vmstate_scc2698_channel = { .name = "scc2698_channel", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(rx_enabled, SCC2698Channel), VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2), VMSTATE_UINT8(mr_idx, SCC2698Channel), @@ -141,8 +140,7 @@ static const VMStateDescription vmstate_scc2698_block = { .name = "scc2698_block", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(imr, SCC2698Block), VMSTATE_UINT8(isr, SCC2698Block), VMSTATE_END_OF_LIST() @@ -153,8 +151,7 @@ static const VMStateDescription vmstate_ipoctal = { .name = "ipoctal232", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_IPACK_DEVICE(parent_obj, IPOctalState), VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1, vmstate_scc2698_channel, SCC2698Channel), diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c index 380cb5dbea..628a86fc06 100644 --- a/hw/char/lm32_juart.c +++ b/hw/char/lm32_juart.c @@ -129,8 +129,7 @@ static const VMStateDescription vmstate_lm32_juart = { .name = "lm32-juart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(jtx, LM32JuartState), VMSTATE_UINT32(jrx, LM32JuartState), VMSTATE_END_OF_LIST() diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c index 84c2549cb7..4f2096637d 100644 --- a/hw/char/lm32_uart.c +++ b/hw/char/lm32_uart.c @@ -270,8 +270,7 @@ static const VMStateDescription vmstate_lm32_uart = { .name = "lm32-uart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c index da51f82eac..d05b825340 100644 --- a/hw/char/milkymist-uart.c +++ b/hw/char/milkymist-uart.c @@ -221,8 +221,7 @@ static const VMStateDescription vmstate_milkymist_uart = { .name = "milkymist-uart", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 644aad7cf0..0a451150e5 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -251,8 +251,7 @@ static const VMStateDescription vmstate_pl011 = { .name = "pl011", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(readbuff, PL011State), VMSTATE_UINT32(flags, PL011State), VMSTATE_UINT32(lcr, PL011State), diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c index a2dc1c63b0..80dd0a9e13 100644 --- a/hw/char/sclpconsole-lm.c +++ b/hw/char/sclpconsole-lm.c @@ -291,8 +291,7 @@ static const VMStateDescription vmstate_sclplmconsole = { .name = "sclplmconsole", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(event.event_pending, SCLPConsoleLM), VMSTATE_UINT32(write_errors, SCLPConsoleLM), VMSTATE_UINT32(length, SCLPConsoleLM), diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index ce406730a5..fca105db4e 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -185,8 +185,7 @@ static const VMStateDescription vmstate_sclpconsole = { .name = "sclpconsole", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(event.event_pending, SCLPConsole), VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220), VMSTATE_UINT32(iov_sclp, SCLPConsole), diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 3036bde1f3..466e543b3d 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -206,8 +206,7 @@ const VMStateDescription vmstate_ptimer = { .name = "ptimer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(enabled, ptimer_state), VMSTATE_UINT64(limit, ptimer_state), VMSTATE_UINT64(delta, ptimer_state), diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c index 85252a2329..3f35369bb4 100644 --- a/hw/display/ads7846.c +++ b/hw/display/ads7846.c @@ -121,9 +121,8 @@ static const VMStateDescription vmstate_ads7846 = { .name = "ads7846", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = ads7856_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(ssidev, ADS7846State), VMSTATE_INT32_ARRAY(input, ADS7846State, 8), VMSTATE_INT32(noise, ADS7846State), diff --git a/hw/display/cg3.c b/hw/display/cg3.c index a042b9ecbe..f5a8299e5e 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -324,7 +324,7 @@ static const VMStateDescription vmstate_cg3 = { .version_id = 1, .minimum_version_id = 1, .post_load = vmstate_cg3_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT16(height, CG3State), VMSTATE_UINT16(width, CG3State), VMSTATE_UINT16(depth, CG3State), diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 9750330c25..45c62afac1 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -1845,7 +1845,7 @@ static const VMStateDescription exynos4210_fimd_window_vmstate = { .name = "exynos4210.fimd_window", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(wincon, Exynos4210fimdWindow), VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3), VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3), @@ -1875,7 +1875,7 @@ static const VMStateDescription exynos4210_fimd_vmstate = { .version_id = 1, .minimum_version_id = 1, .post_load = exynos4210_fimd_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4), VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4), VMSTATE_UINT32(shadowcon, Exynos4210fimdState), diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index 5c6a2d3605..46f7b41211 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -459,7 +459,6 @@ static const VMStateDescription vmstate_g364fb = { .name = "g364fb", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = g364fb_post_load, .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size), diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c index f9e7d7c981..e9bb005413 100644 --- a/hw/display/jazz_led.c +++ b/hw/display/jazz_led.c @@ -250,7 +250,6 @@ static const VMStateDescription vmstate_jazz_led = { .name = "jazz-led", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = jazz_led_post_load, .fields = (VMStateField[]) { VMSTATE_UINT8(segments, LedState), diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c index b2a5fba0ff..3e1d0b9c20 100644 --- a/hw/display/milkymist-tmu2.c +++ b/hw/display/milkymist-tmu2.c @@ -463,8 +463,7 @@ static const VMStateDescription vmstate_milkymist_tmu2 = { .name = "milkymist-tmu2", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c index 603537aabb..9b35e76ff1 100644 --- a/hw/display/milkymist-vgafb.c +++ b/hw/display/milkymist-vgafb.c @@ -305,9 +305,8 @@ static const VMStateDescription vmstate_milkymist_vgafb = { .name = "milkymist-vgafb", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = vgafb_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c index 09cdf17ab9..80edb70676 100644 --- a/hw/display/pxa2xx_lcd.c +++ b/hw/display/pxa2xx_lcd.c @@ -932,8 +932,7 @@ static const VMStateDescription vmstate_dma_channel = { .name = "dma_channel", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(branch, struct DMAChannel), VMSTATE_UINT8(up, struct DMAChannel), VMSTATE_BUFFER(pbuffer, struct DMAChannel), @@ -959,9 +958,8 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = { .name = "pxa2xx_lcdc", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = pxa2xx_lcdc_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(irqlevel, PXA2xxLCDState), VMSTATE_INT32(transp, PXA2xxLCDState), VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6), diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c index c2eea04934..f6804fb51b 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -272,8 +272,7 @@ static const VMStateDescription vmstate_ssd0303 = { .name = "ssd0303_oled", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(row, ssd0303_state), VMSTATE_INT32(col, ssd0303_state), VMSTATE_INT32(start_line, ssd0303_state), diff --git a/hw/display/tcx.c b/hw/display/tcx.c index 2b37ffac4c..2551b677aa 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -416,9 +416,8 @@ static const VMStateDescription vmstate_tcx = { .name ="tcx", .version_id = 4, .minimum_version_id = 4, - .minimum_version_id_old = 4, .post_load = vmstate_tcx_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(height, TCXState), VMSTATE_UINT16(width, TCXState), VMSTATE_UINT16(depth, TCXState), diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index 0e8cccd27f..0f35c42c05 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -973,7 +973,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, case 0x22: /* DMA_COLOR_U */ ch->color &= 0xffff; - ch->color |= value << 16; + ch->color |= (uint32_t)value << 16; break; case 0x24: /* DMA_CCR2 */ @@ -1043,7 +1043,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0xbca: /* TOP_B1_U */ s->src_f1_top &= 0x0000ffff; - s->src_f1_top |= value << 16; + s->src_f1_top |= (uint32_t)value << 16; break; case 0xbcc: /* BOT_B1_L */ @@ -1265,7 +1265,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ s->src_f1_top &= 0x0000ffff; - s->src_f1_top |= value << 16; + s->src_f1_top |= (uint32_t)value << 16; break; case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ @@ -1275,7 +1275,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ s->src_f1_bottom &= 0x0000ffff; - s->src_f1_bottom |= value << 16; + s->src_f1_bottom |= (uint32_t)value << 16; break; case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ @@ -1285,7 +1285,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ s->src_f2_top &= 0x0000ffff; - s->src_f2_top |= value << 16; + s->src_f2_top |= (uint32_t)value << 16; break; case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ @@ -1295,7 +1295,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ s->src_f2_bottom &= 0x0000ffff; - s->src_f2_bottom |= value << 16; + s->src_f2_bottom |= (uint32_t)value << 16; break; default: diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index 608a58c47d..6b6eaaeb47 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -138,7 +138,6 @@ static const VMStateDescription vmstate_pl330_chan = { .name = "pl330_chan", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(src, PL330Chan), VMSTATE_UINT32(dst, PL330Chan), @@ -170,7 +169,6 @@ static const VMStateDescription vmstate_pl330_fifo = { .name = "pl330_chan", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size), VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size), @@ -195,7 +193,6 @@ static const VMStateDescription vmstate_pl330_queue_entry = { .name = "pl330_queue_entry", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(addr, PL330QueueEntry), VMSTATE_UINT32(len, PL330QueueEntry), @@ -218,7 +215,6 @@ static const VMStateDescription vmstate_pl330_queue = { .name = "pl330_queue", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1, vmstate_pl330_queue_entry, PL330QueueEntry), @@ -279,7 +275,6 @@ static const VMStateDescription vmstate_pl330 = { .name = "pl330", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan), VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0, diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c index c013abb313..d4501fb4cb 100644 --- a/hw/dma/pxa2xx_dma.c +++ b/hw/dma/pxa2xx_dma.c @@ -514,7 +514,6 @@ static VMStateDescription vmstate_pxa2xx_dma_chan = { .name = "pxa2xx_dma_chan", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(descr, PXA2xxDMAChannel), VMSTATE_UINT32(src, PXA2xxDMAChannel), @@ -530,7 +529,6 @@ static VMStateDescription vmstate_pxa2xx_dma = { .name = "pxa2xx_dma", .version_id = 1, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_UNUSED_TEST(is_version_0, 4), VMSTATE_UINT32(stopintr, PXA2xxDMAState), diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index eac338f1bc..e6a453ce5c 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -263,8 +263,7 @@ static const VMStateDescription vmstate_dma = { .name ="sparc32_dma", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(dmaregs, DMAState, DMA_REGS), VMSTATE_END_OF_LIST() } diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c index 899d454353..ec7c2efcd9 100644 --- a/hw/dma/sun4m_iommu.c +++ b/hw/dma/sun4m_iommu.c @@ -327,8 +327,7 @@ static const VMStateDescription vmstate_iommu = { .name ="iommu", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS), VMSTATE_UINT64(iostart, IOMMUState), VMSTATE_END_OF_LIST() diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c index cfcd89ca2b..7fbf313ce8 100644 --- a/hw/gpio/max7310.c +++ b/hw/gpio/max7310.c @@ -152,8 +152,7 @@ static const VMStateDescription vmstate_max7310 = { .name = "max7310", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(i2c_command_byte, MAX7310State), VMSTATE_INT32(len, MAX7310State), VMSTATE_UINT8(level, MAX7310State), diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index 8e2ce049de..94083424f8 100644 --- a/hw/gpio/zaurus.c +++ b/hw/gpio/zaurus.c @@ -216,9 +216,8 @@ static const VMStateDescription vmstate_scoop_regs = { .name = "scoop", .version_id = 1, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = scoop_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(status, ScoopInfo), VMSTATE_UINT16(power, ScoopInfo), VMSTATE_UINT32(gpio_level, ScoopInfo), diff --git a/hw/i2c/core.c b/hw/i2c/core.c index efd8b4fafb..5a64026347 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -52,10 +52,9 @@ static const VMStateDescription vmstate_i2c_bus = { .name = "i2c_bus", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = i2c_bus_pre_save, .post_load = i2c_bus_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(saved_address, I2CBus), VMSTATE_END_OF_LIST() } @@ -194,9 +193,8 @@ const VMStateDescription vmstate_i2c_slave = { .name = "I2CSlave", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = i2c_slave_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(address, I2CSlave), VMSTATE_END_OF_LIST() } diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index 295b62ed29..0803dc4d18 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -48,7 +48,6 @@ static const VMStateDescription vmstate_ich9_smbus = { .name = "ich9_smb", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState), VMSTATE_END_OF_LIST() diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index e55421adcd..de33657563 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -1300,6 +1300,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) if (pos != 0 && kvm_device_msix_supported(kvm_state)) { int bar_nr; uint32_t msix_table_entry; + uint16_t msix_max; verify_irqchip_in_kernel(&local_err); if (local_err) { @@ -1315,9 +1316,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) } pci_dev->msix_cap = pos; - pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, - pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) & - PCI_MSIX_FLAGS_QSIZE); + msix_max = (pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) & + PCI_MSIX_FLAGS_QSIZE) + 1; + msix_max = MIN(msix_max, KVM_MAX_MSIX_PER_DEV); + pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, msix_max - 1); /* Only enable and function mask bits are writable */ pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS, @@ -1327,9 +1329,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK; msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK; dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry; - dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS); - dev->msix_max &= PCI_MSIX_FLAGS_QSIZE; - dev->msix_max += 1; + dev->msix_max = msix_max; } /* Minimal PM support, nothing writable, device appears to NAK changes */ @@ -1664,6 +1664,7 @@ static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp) MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); if (dev->msix_table == MAP_FAILED) { error_setg_errno(errp, errno, "failed to allocate msix_table"); + dev->msix_table = NULL; return; } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 07de2384ad..e6369d5be6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -471,11 +471,12 @@ static void port92_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { Port92State *s = opaque; + int oldval = s->outport; DPRINTF("port92: write 0x%02x\n", val); s->outport = val; qemu_set_irq(*s->a20_out, (val >> 1) & 1); - if (val & 1) { + if ((val & 1) && !(oldval & 1)) { qemu_system_reset_request(); } } diff --git a/hw/ide/core.c b/hw/ide/core.c index c943a4d764..1cac5f53dc 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -2342,8 +2342,7 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = { .name ="ide_drive/atapi/gesn_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_BOOL(events.new_media, IDEState), VMSTATE_BOOL(events.eject_request, IDEState), VMSTATE_END_OF_LIST() @@ -2354,7 +2353,6 @@ static const VMStateDescription vmstate_ide_tray_state = { .name = "ide_drive/tray_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_BOOL(tray_open, IDEState), VMSTATE_BOOL(tray_locked, IDEState), @@ -2366,10 +2364,9 @@ static const VMStateDescription vmstate_ide_drive_pio_state = { .name = "ide_drive/pio_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = ide_drive_pio_pre_save, .post_load = ide_drive_pio_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(req_nb_sectors, IDEState), VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1, vmstate_info_uint8, uint8_t), @@ -2386,9 +2383,8 @@ const VMStateDescription vmstate_ide_drive = { .name = "ide_drive", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = ide_drive_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(mult_sectors, IDEState), VMSTATE_INT32(identify_set, IDEState), VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set), @@ -2431,8 +2427,7 @@ static const VMStateDescription vmstate_ide_error_status = { .name ="ide_bus/error", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(error_status, IDEBus), VMSTATE_END_OF_LIST() } @@ -2442,8 +2437,7 @@ const VMStateDescription vmstate_ide_bus = { .name = "ide_bus", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(cmd, IDEBus), VMSTATE_UINT8(unit, IDEBus), VMSTATE_END_OF_LIST() diff --git a/hw/ide/macio.c b/hw/ide/macio.c index da94580aac..1c20616f5a 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -480,8 +480,7 @@ static const VMStateDescription vmstate_pmac = { .name = "ide", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_IDE_BUS(bus, MACIOIDEState), VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState), VMSTATE_END_OF_LIST() diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 21d6495817..f24946ddf6 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -332,8 +332,7 @@ static const VMStateDescription vmstate_microdrive = { .name = "microdrive", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(opt, MicroDriveState), VMSTATE_UINT8(stat, MicroDriveState), VMSTATE_UINT8(pins, MicroDriveState), diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 9f66a52599..01c1d0e6ce 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -109,8 +109,7 @@ static const VMStateDescription vmstate_ide_mmio = { .name = "mmio-ide", .version_id = 3, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_IDE_BUS(bus, MMIOState), VMSTATE_IDE_DRIVES(bus.ifs, MMIOState), VMSTATE_END_OF_LIST() diff --git a/hw/input/adb.c b/hw/input/adb.c index a75d3fd7b9..34c8058fc2 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -303,8 +303,7 @@ static const VMStateDescription vmstate_adb_kbd = { .name = "adb_kbd", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BUFFER(data, KBDState), VMSTATE_INT32(rptr, KBDState), VMSTATE_INT32(wptr, KBDState), @@ -518,8 +517,7 @@ static const VMStateDescription vmstate_adb_mouse = { .name = "adb_mouse", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(buttons_state, MouseState), VMSTATE_INT32(last_buttons_state, MouseState), VMSTATE_INT32(dx, MouseState), diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c index 4ae1cd9c80..9eb68e87cb 100644 --- a/hw/input/lm832x.c +++ b/hw/input/lm832x.c @@ -432,9 +432,8 @@ static const VMStateDescription vmstate_lm_kbd = { .name = "LM8323", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = lm_kbd_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_I2C_SLAVE(parent_obj, LM823KbdState), VMSTATE_UINT8(i2c_dir, LM823KbdState), VMSTATE_UINT8(i2c_cycle, LM823KbdState), diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c index ecde33cb95..53ba71410d 100644 --- a/hw/input/milkymist-softusb.c +++ b/hw/input/milkymist-softusb.c @@ -295,8 +295,7 @@ static const VMStateDescription vmstate_milkymist_softusb = { .name = "milkymist-softusb", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX), VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState), VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState), diff --git a/hw/input/pxa2xx_keypad.c b/hw/input/pxa2xx_keypad.c index b90b0ba102..85011145e6 100644 --- a/hw/input/pxa2xx_keypad.c +++ b/hw/input/pxa2xx_keypad.c @@ -291,8 +291,7 @@ static const VMStateDescription vmstate_pxa2xx_keypad = { .name = "pxa2xx_keypad", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(kpc, PXA2xxKeyPadState), VMSTATE_UINT32(kpdk, PXA2xxKeyPadState), VMSTATE_UINT32(kprec, PXA2xxKeyPadState), diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c index 4e407922a0..0609e80868 100644 --- a/hw/input/stellaris_input.c +++ b/hw/input/stellaris_input.c @@ -51,8 +51,7 @@ static const VMStateDescription vmstate_stellaris_button = { .name = "stellaris_button", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(pressed, gamepad_button), VMSTATE_END_OF_LIST() } @@ -62,8 +61,7 @@ static const VMStateDescription vmstate_stellaris_gamepad = { .name = "stellaris_gamepad", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(extension, gamepad_state), VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0, vmstate_stellaris_button, gamepad_button), diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c index 0924d9855c..de820b9723 100644 --- a/hw/intc/allwinner-a10-pic.c +++ b/hw/intc/allwinner-a10-pic.c @@ -97,6 +97,7 @@ static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value, switch (offset) { case AW_A10_PIC_BASE_ADDR: s->base_addr = value & ~0x3; + break; case AW_A10_PIC_PROTECT: s->protect = value; break; @@ -141,7 +142,6 @@ static const VMStateDescription vmstate_aw_a10_pic = { .name = "a10.pic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(vector, AwA10PICState), VMSTATE_UINT32(base_addr, AwA10PICState), diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 71376533ca..ce3d903b13 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -200,7 +200,7 @@ void apic_init_reset(DeviceState *dev) s->initial_count = 0; s->initial_count_load_time = 0; s->next_time = 0; - s->wait_for_sipi = 1; + s->wait_for_sipi = !cpu_is_bsp(s->cpu); if (s->timer) { timer_del(s->timer); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 9aa8ab208f..75d9c6e41e 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -443,8 +443,7 @@ static const VMStateDescription vmstate_nvic = { .name = "armv7m_nvic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(systick.control, nvic_state), VMSTATE_UINT32(systick.reload, nvic_state), VMSTATE_INT64(systick.tick, nvic_state), diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index 3287479456..a6b7028906 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -77,7 +77,6 @@ static const VMStateDescription vmstate_exynos4210_combiner_group_state = { .name = "exynos4210.combiner.groupstate", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT8(src_mask, CombinerGroupState), VMSTATE_UINT8(src_pending, CombinerGroupState), @@ -89,7 +88,6 @@ static const VMStateDescription vmstate_exynos4210_combiner = { .name = "exynos4210.combiner", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(group, Exynos4210CombinerState, IIC_NGRP, 0, vmstate_exynos4210_combiner_group_state, CombinerGroupState), diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 5b913f786e..0590d5dfb8 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -394,7 +394,6 @@ static const VMStateDescription vmstate_exynos4210_irq_gate = { .name = "exynos4210.irq_gate", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in), VMSTATE_END_OF_LIST() diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c index fb00e910f6..ec5f9ad815 100644 --- a/hw/intc/imx_avic.c +++ b/hw/intc/imx_avic.c @@ -77,7 +77,6 @@ static const VMStateDescription vmstate_imx_avic = { .name = "imx-avic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT64(pending, IMXAVICState), VMSTATE_UINT64(enabled, IMXAVICState), diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c index 32d009f678..72fc9ef674 100644 --- a/hw/intc/lm32_pic.c +++ b/hw/intc/lm32_pic.c @@ -169,8 +169,7 @@ static const VMStateDescription vmstate_lm32_pic = { .name = "lm32-pic", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(im, LM32PicState), VMSTATE_UINT32(ip, LM32PicState), VMSTATE_UINT32(irq_state, LM32PicState), diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index b10fb66b8d..f22aba0313 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -381,8 +381,7 @@ static const VMStateDescription vmstate_intctl_cpu = { .name ="slavio_intctl_cpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState), VMSTATE_END_OF_LIST() } @@ -392,9 +391,8 @@ static const VMStateDescription vmstate_intctl = { .name ="slavio_intctl", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = vmstate_intctl_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1, vmstate_intctl_cpu, SLAVIO_CPUINTCTLState), VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState), diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c index 1b228ff4e0..c3682f1b20 100644 --- a/hw/intc/xilinx_intc.c +++ b/hw/intc/xilinx_intc.c @@ -121,6 +121,9 @@ pic_write(void *opaque, hwaddr addr, case R_CIE: p->regs[R_IER] &= ~value; /* Atomic clear ie. */ break; + case R_MER: + p->regs[R_MER] = value & 0x3; + break; case R_ISR: if ((p->regs[R_MER] & 2)) { break; diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c index ed63d2ac61..ef032e6604 100644 --- a/hw/ipack/ipack.c +++ b/hw/ipack/ipack.c @@ -89,8 +89,7 @@ const VMStateDescription vmstate_ipack_device = { .name = "ipack_device", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(slot, IPackDevice), VMSTATE_END_OF_LIST() } diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c index e1b69b4552..42ca923c7d 100644 --- a/hw/ipack/tpci200.c +++ b/hw/ipack/tpci200.c @@ -629,8 +629,7 @@ static const VMStateDescription vmstate_tpci200 = { .name = "tpci200", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, TPCI200State), VMSTATE_BOOL_ARRAY(big_endian, TPCI200State, 3), VMSTATE_UINT8_ARRAY(ctrl, TPCI200State, N_MODULES), diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index 48d9e7afa4..6bf36d046f 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -148,7 +148,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, big_endian, ELF_MACHINE, 0); } /* Always boot into physical ram. */ - boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff); + boot_info.bootstrap_pc = (uint32_t)entry; /* If it wasn't an ELF image, try an u-boot image. */ if (kernel_size < 0) { @@ -174,9 +174,15 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, high = ROUND_UP(high + kernel_size, 4); boot_info.initrd_start = high; initrd_offset = boot_info.initrd_start - ddr_base; - initrd_size = load_image_targphys(initrd_filename, - boot_info.initrd_start, - ram_size - initrd_offset); + + initrd_size = load_ramdisk(initrd_filename, + boot_info.initrd_start, + ram_size - initrd_offset); + if (initrd_size < 0) { + initrd_size = load_image_targphys(initrd_filename, + boot_info.initrd_start, + ram_size - initrd_offset); + } if (initrd_size < 0) { error_report("qemu: could not load initrd '%s'\n", initrd_filename); diff --git a/hw/misc/eccmemctl.c b/hw/misc/eccmemctl.c index 549431cb13..8bad6f682b 100644 --- a/hw/misc/eccmemctl.c +++ b/hw/misc/eccmemctl.c @@ -266,8 +266,7 @@ static const VMStateDescription vmstate_ecc = { .name ="ECC", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS), VMSTATE_BUFFER(diag, ECCState), VMSTATE_UINT32(version, ECCState), diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c index 5ec14d1c86..2b118c7255 100644 --- a/hw/misc/exynos4210_pmu.c +++ b/hw/misc/exynos4210_pmu.c @@ -471,7 +471,7 @@ static const VMStateDescription exynos4210_pmu_vmstate = { .name = "exynos4210.pmu", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(reg, Exynos4210PmuState, PMU_NUM_OF_REGISTERS), VMSTATE_END_OF_LIST() } diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index 63e33a41da..750b9061db 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -57,7 +57,6 @@ static const VMStateDescription vmstate_imx_ccm = { .name = "imx-ccm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(ccmr, IMXCCMState), VMSTATE_UINT32(pdr0, IMXCCMState), diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c index e394f2e63b..778eb6e042 100644 --- a/hw/misc/lm32_sys.c +++ b/hw/misc/lm32_sys.c @@ -141,8 +141,7 @@ static const VMStateDescription vmstate_lm32_sys = { .name = "lm32-sys", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX), VMSTATE_BUFFER(testname, LM32SysState), VMSTATE_END_OF_LIST() diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index bc71aa7ccd..ff6051defe 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -617,8 +617,7 @@ static const VMStateDescription vmstate_cuda_timer = { .name = "cuda_timer", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT16(latch, CUDATimer), VMSTATE_UINT16(counter_value, CUDATimer), VMSTATE_INT64(load_time, CUDATimer), @@ -632,8 +631,7 @@ static const VMStateDescription vmstate_cuda = { .name = "cuda", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT8(a, CUDAState), VMSTATE_UINT8(b, CUDAState), VMSTATE_UINT8(dira, CUDAState), diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index f47a736182..3335476c29 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -719,8 +719,7 @@ static const VMStateDescription vmstate_dbdma_channel = { .name = "dbdma_channel", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS), VMSTATE_END_OF_LIST() } @@ -730,8 +729,7 @@ static const VMStateDescription vmstate_dbdma = { .name = "dbdma", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1, vmstate_dbdma_channel, DBDMA_channel), VMSTATE_END_OF_LIST() diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index bba87c2ec5..bef3651d6e 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -110,8 +110,7 @@ static const VMStateDescription vmstate_max111x = { .name = "max111x", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_SSI_SLAVE(parent_obj, MAX111xState), VMSTATE_UINT8(tb1, MAX111xState), VMSTATE_UINT8(rb2, MAX111xState), diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c index aef135e572..f5f4c1b343 100644 --- a/hw/misc/milkymist-hpdmc.c +++ b/hw/misc/milkymist-hpdmc.c @@ -143,8 +143,7 @@ static const VMStateDescription vmstate_milkymist_hpdmc = { .name = "milkymist-hpdmc", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX), VMSTATE_END_OF_LIST() } diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c index b3b2143d51..609f33f9cd 100644 --- a/hw/misc/milkymist-pfpu.c +++ b/hw/misc/milkymist-pfpu.c @@ -513,8 +513,7 @@ static const VMStateDescription vmstate_milkymist_pfpu = { .name = "milkymist-pfpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX), VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128), VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS), diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c index c96810fec1..d5090799f8 100644 --- a/hw/misc/mst_fpga.c +++ b/hw/misc/mst_fpga.c @@ -219,12 +219,11 @@ static int mst_fpga_init(SysBusDevice *sbd) } static VMStateDescription vmstate_mst_fpga_regs = { - .name = "mainstone_fpga", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, - .post_load = mst_fpga_post_load, - .fields = (VMStateField []) { + .name = "mainstone_fpga", + .version_id = 0, + .minimum_version_id = 0, + .post_load = mst_fpga_post_load, + .fields = (VMStateField[]) { VMSTATE_UINT32(prev_level, mst_irq_state), VMSTATE_UINT32(leddat1, mst_irq_state), VMSTATE_UINT32(leddat2, mst_irq_state), diff --git a/hw/misc/omap_gpmc.c b/hw/misc/omap_gpmc.c index 2047274123..cddea241d4 100644 --- a/hw/misc/omap_gpmc.c +++ b/hw/misc/omap_gpmc.c @@ -242,6 +242,10 @@ static void fill_prefetch_fifo(struct omap_gpmc_s *s) if (bytes > s->prefetch.count) { bytes = s->prefetch.count; } + if (is16bit) { + bytes &= ~1; + } + s->prefetch.count -= bytes; s->prefetch.fifopointer += bytes; fptr = 64 - s->prefetch.fifopointer; diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c index 767544eca1..50985958a4 100644 --- a/hw/misc/slavio_misc.c +++ b/hw/misc/slavio_misc.c @@ -400,8 +400,7 @@ static const VMStateDescription vmstate_misc = { .name ="slavio_misc", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(dummy, MiscState), VMSTATE_UINT8(config, MiscState), VMSTATE_UINT8(aux1, MiscState), diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c index 636ee97b16..f3fe8b81fd 100644 --- a/hw/misc/tmp105.c +++ b/hw/misc/tmp105.c @@ -199,9 +199,8 @@ static const VMStateDescription vmstate_tmp105 = { .name = "TMP105", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = tmp105_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(len, TMP105State), VMSTATE_UINT8_ARRAY(buf, TMP105State, 2), VMSTATE_UINT8(pointer, TMP105State), diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 2e53a2e21f..964f2532ff 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -428,8 +428,7 @@ static const VMStateDescription vmstate_zynq_slcr = { .name = "zynq_slcr", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, ZynqSLCRState, ZYNQ_SLCR_NUM_REGS), VMSTATE_END_OF_LIST() } diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index cdb18253b6..47e70381fe 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -717,7 +717,6 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) rxbuf_ptr = (void *)buf; } else { unsigned crc_val; - int crc_offset; /* The application wants the FCS field, which QEMU does not provide. * We must try and caclculate one. @@ -727,12 +726,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) memset(rxbuf + size, 0, sizeof(rxbuf) - size); rxbuf_ptr = rxbuf; crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60))); - if (size < 60) { - crc_offset = 60; - } else { - crc_offset = size; - } - memcpy(rxbuf + crc_offset, &crc_val, sizeof(crc_val)); + memcpy(rxbuf + size, &crc_val, sizeof(crc_val)); bytes_to_copy += 4; size += 4; @@ -1257,8 +1251,7 @@ static const VMStateDescription vmstate_cadence_gem = { .name = "cadence_gem", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, GemState, GEM_MAXREG), VMSTATE_UINT16_ARRAY(phy_regs, GemState, 32), VMSTATE_UINT8(phy_loop, GemState), diff --git a/hw/net/lance.c b/hw/net/lance.c index fe18564e1e..7811a9edc2 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -110,8 +110,7 @@ static const VMStateDescription vmstate_lance = { .name = "pcnet", .version_id = 3, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState), VMSTATE_END_OF_LIST() } diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c index 1e9237984d..c023351c0d 100644 --- a/hw/net/milkymist-minimac2.c +++ b/hw/net/milkymist-minimac2.c @@ -492,8 +492,7 @@ static const VMStateDescription vmstate_milkymist_minimac2_mdio = { .name = "milkymist-minimac2-mdio", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState), VMSTATE_INT32(count, MilkymistMinimac2MdioState), VMSTATE_UINT32(data, MilkymistMinimac2MdioState), @@ -509,8 +508,7 @@ static const VMStateDescription vmstate_milkymist_minimac2 = { .name = "milkymist-minimac2", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX), VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX), VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0, diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index e421b867e7..b26c369178 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -198,8 +198,7 @@ static const VMStateDescription vmstate_mipsnet = { .name = "mipsnet", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(busy, MIPSnetState), VMSTATE_UINT32(rx_count, MIPSnetState), VMSTATE_UINT32(rx_read, MIPSnetState), diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index a8e29b3b42..d1dca8f4e2 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -54,7 +54,7 @@ static const VMStateDescription vmstate_smc91c111 = { .name = "smc91c111", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(tcr, smc91c111_state), VMSTATE_UINT16(rcr, smc91c111_state), VMSTATE_UINT16(cr, smc91c111_state), diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index d04e6a46f8..c9ee5d3f10 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -47,6 +47,11 @@ do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0) OBJECT_CHECK(stellaris_enet_state, (obj), TYPE_STELLARIS_ENET) typedef struct { + uint8_t data[2048]; + uint32_t len; +} StellarisEnetRxFrame; + +typedef struct { SysBusDevice parent_obj; uint32_t ris; @@ -59,29 +64,159 @@ typedef struct { uint32_t mtxd; uint32_t mrxd; uint32_t np; - int tx_frame_len; - int tx_fifo_len; + uint32_t tx_fifo_len; uint8_t tx_fifo[2048]; /* Real hardware has a 2k fifo, which works out to be at most 31 packets. We implement a full 31 packet fifo. */ - struct { - uint8_t data[2048]; - int len; - } rx[31]; - uint8_t *rx_fifo; - int rx_fifo_len; - int next_packet; + StellarisEnetRxFrame rx[31]; + uint32_t rx_fifo_offset; + uint32_t next_packet; NICState *nic; NICConf conf; qemu_irq irq; MemoryRegion mmio; } stellaris_enet_state; +static const VMStateDescription vmstate_rx_frame = { + .name = "stellaris_enet/rx_frame", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(data, StellarisEnetRxFrame, 2048), + VMSTATE_UINT32(len, StellarisEnetRxFrame), + VMSTATE_END_OF_LIST() + } +}; + +static int stellaris_enet_post_load(void *opaque, int version_id) +{ + stellaris_enet_state *s = opaque; + int i; + + /* Sanitize inbound state. Note that next_packet is an index but + * np is a size; hence their valid upper bounds differ. + */ + if (s->next_packet >= ARRAY_SIZE(s->rx)) { + return -1; + } + + if (s->np > ARRAY_SIZE(s->rx)) { + return -1; + } + + for (i = 0; i < ARRAY_SIZE(s->rx); i++) { + if (s->rx[i].len > ARRAY_SIZE(s->rx[i].data)) { + return -1; + } + } + + if (s->rx_fifo_offset > ARRAY_SIZE(s->rx[0].data) - 4) { + return -1; + } + + if (s->tx_fifo_len > ARRAY_SIZE(s->tx_fifo)) { + return -1; + } + + return 0; +} + +static const VMStateDescription vmstate_stellaris_enet = { + .name = "stellaris_enet", + .version_id = 2, + .minimum_version_id = 2, + .post_load = stellaris_enet_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(ris, stellaris_enet_state), + VMSTATE_UINT32(im, stellaris_enet_state), + VMSTATE_UINT32(rctl, stellaris_enet_state), + VMSTATE_UINT32(tctl, stellaris_enet_state), + VMSTATE_UINT32(thr, stellaris_enet_state), + VMSTATE_UINT32(mctl, stellaris_enet_state), + VMSTATE_UINT32(mdv, stellaris_enet_state), + VMSTATE_UINT32(mtxd, stellaris_enet_state), + VMSTATE_UINT32(mrxd, stellaris_enet_state), + VMSTATE_UINT32(np, stellaris_enet_state), + VMSTATE_UINT32(tx_fifo_len, stellaris_enet_state), + VMSTATE_UINT8_ARRAY(tx_fifo, stellaris_enet_state, 2048), + VMSTATE_STRUCT_ARRAY(rx, stellaris_enet_state, 31, 1, + vmstate_rx_frame, StellarisEnetRxFrame), + VMSTATE_UINT32(rx_fifo_offset, stellaris_enet_state), + VMSTATE_UINT32(next_packet, stellaris_enet_state), + VMSTATE_END_OF_LIST() + } +}; + static void stellaris_enet_update(stellaris_enet_state *s) { qemu_set_irq(s->irq, (s->ris & s->im) != 0); } +/* Return the data length of the packet currently being assembled + * in the TX fifo. + */ +static inline int stellaris_txpacket_datalen(stellaris_enet_state *s) +{ + return s->tx_fifo[0] | (s->tx_fifo[1] << 8); +} + +/* Return true if the packet currently in the TX FIFO is complete, +* ie the FIFO holds enough bytes for the data length, ethernet header, +* payload and optionally CRC. +*/ +static inline bool stellaris_txpacket_complete(stellaris_enet_state *s) +{ + int framelen = stellaris_txpacket_datalen(s); + framelen += 16; + if (!(s->tctl & SE_TCTL_CRC)) { + framelen += 4; + } + /* Cover the corner case of a 2032 byte payload with auto-CRC disabled: + * this requires more bytes than will fit in the FIFO. It's not totally + * clear how the h/w handles this, but if using threshold-based TX + * it will definitely try to transmit something. + */ + framelen = MIN(framelen, ARRAY_SIZE(s->tx_fifo)); + return s->tx_fifo_len >= framelen; +} + +/* Return true if the TX FIFO threshold is enabled and the FIFO + * has filled enough to reach it. + */ +static inline bool stellaris_tx_thr_reached(stellaris_enet_state *s) +{ + return (s->thr < 0x3f && + (s->tx_fifo_len >= 4 * (s->thr * 8 + 1))); +} + +/* Send the packet currently in the TX FIFO */ +static void stellaris_enet_send(stellaris_enet_state *s) +{ + int framelen = stellaris_txpacket_datalen(s); + + /* Ethernet header is in the FIFO but not in the datacount. + * We don't implement explicit CRC, so just ignore any + * CRC value in the FIFO. + */ + framelen += 14; + if ((s->tctl & SE_TCTL_PADEN) && framelen < 60) { + memset(&s->tx_fifo[framelen + 2], 0, 60 - framelen); + framelen = 60; + } + /* This MIN will have no effect unless the FIFO data is corrupt + * (eg bad data from an incoming migration); otherwise the check + * on the datalen at the start of writing the data into the FIFO + * will have caught this. Silently write a corrupt half-packet, + * which is what the hardware does in FIFO underrun situations. + */ + framelen = MIN(framelen, ARRAY_SIZE(s->tx_fifo) - 2); + qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo + 2, framelen); + s->tx_fifo_len = 0; + s->ris |= SE_INT_TXEMP; + stellaris_enet_update(s); + DPRINTF("Done TX\n"); +} + /* TODO: Implement MAC address filtering. */ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size) { @@ -97,7 +232,7 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si return -1; } - DPRINTF("Received packet len=%d\n", size); + DPRINTF("Received packet len=%zu\n", size); n = s->next_packet + s->np; if (n >= 31) n -= 31; @@ -152,21 +287,21 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset, case 0x0c: /* TCTL */ return s->tctl; case 0x10: /* DATA */ - if (s->rx_fifo_len == 0) { - if (s->np == 0) { - BADF("RX underflow\n"); - return 0; - } - s->rx_fifo_len = s->rx[s->next_packet].len; - s->rx_fifo = s->rx[s->next_packet].data; - DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len); + { + uint8_t *rx_fifo; + + if (s->np == 0) { + BADF("RX underflow\n"); + return 0; } - val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16) - | (s->rx_fifo[3] << 24); - s->rx_fifo += 4; - s->rx_fifo_len -= 4; - if (s->rx_fifo_len <= 0) { - s->rx_fifo_len = 0; + + rx_fifo = s->rx[s->next_packet].data + s->rx_fifo_offset; + + val = rx_fifo[0] | (rx_fifo[1] << 8) | (rx_fifo[2] << 16) + | (rx_fifo[3] << 24); + s->rx_fifo_offset += 4; + if (s->rx_fifo_offset >= s->rx[s->next_packet].len) { + s->rx_fifo_offset = 0; s->next_packet++; if (s->next_packet >= 31) s->next_packet = 0; @@ -174,6 +309,7 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset, DPRINTF("RX done np=%d\n", s->np); } return val; + } case 0x14: /* IA0 */ return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8) | (s->conf.macaddr.a[2] << 16) @@ -212,22 +348,23 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, switch (offset) { case 0x00: /* IACK */ s->ris &= ~value; - DPRINTF("IRQ ack %02x/%02x\n", value, s->ris); + DPRINTF("IRQ ack %02" PRIx64 "/%02x\n", value, s->ris); stellaris_enet_update(s); /* Clearing TXER also resets the TX fifo. */ - if (value & SE_INT_TXER) - s->tx_frame_len = -1; + if (value & SE_INT_TXER) { + s->tx_fifo_len = 0; + } break; case 0x04: /* IM */ - DPRINTF("IRQ mask %02x/%02x\n", value, s->ris); + DPRINTF("IRQ mask %02" PRIx64 "/%02x\n", value, s->ris); s->im = value; stellaris_enet_update(s); break; case 0x08: /* RCTL */ s->rctl = value; if (value & SE_RCTL_RSTFIFO) { - s->rx_fifo_len = 0; s->np = 0; + s->rx_fifo_offset = 0; stellaris_enet_update(s); } break; @@ -235,43 +372,26 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, s->tctl = value; break; case 0x10: /* DATA */ - if (s->tx_frame_len == -1) { - s->tx_frame_len = value & 0xffff; - if (s->tx_frame_len > 2032) { - DPRINTF("TX frame too long (%d)\n", s->tx_frame_len); - s->tx_frame_len = 0; + if (s->tx_fifo_len == 0) { + /* The first word is special, it contains the data length */ + int framelen = value & 0xffff; + if (framelen > 2032) { + DPRINTF("TX frame too long (%d)\n", framelen); s->ris |= SE_INT_TXER; stellaris_enet_update(s); - } else { - DPRINTF("Start TX frame len=%d\n", s->tx_frame_len); - /* The value written does not include the ethernet header. */ - s->tx_frame_len += 14; - if ((s->tctl & SE_TCTL_CRC) == 0) - s->tx_frame_len += 4; - s->tx_fifo_len = 0; - s->tx_fifo[s->tx_fifo_len++] = value >> 16; - s->tx_fifo[s->tx_fifo_len++] = value >> 24; + break; } - } else { + } + + if (s->tx_fifo_len + 4 <= ARRAY_SIZE(s->tx_fifo)) { s->tx_fifo[s->tx_fifo_len++] = value; s->tx_fifo[s->tx_fifo_len++] = value >> 8; s->tx_fifo[s->tx_fifo_len++] = value >> 16; s->tx_fifo[s->tx_fifo_len++] = value >> 24; - if (s->tx_fifo_len >= s->tx_frame_len) { - /* We don't implement explicit CRC, so just chop it off. */ - if ((s->tctl & SE_TCTL_CRC) == 0) - s->tx_frame_len -= 4; - if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) { - memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len); - s->tx_fifo_len = 60; - } - qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo, - s->tx_frame_len); - s->tx_frame_len = -1; - s->ris |= SE_INT_TXEMP; - stellaris_enet_update(s); - DPRINTF("Done TX\n"); - } + } + + if (stellaris_tx_thr_reached(s) && stellaris_txpacket_complete(s)) { + stellaris_enet_send(s); } break; case 0x14: /* IA0 */ @@ -299,9 +419,13 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, case 0x2c: /* MTXD */ s->mtxd = value & 0xff; break; + case 0x38: /* TR */ + if (value & 1) { + stellaris_enet_send(s); + } + break; case 0x30: /* MRXD */ case 0x34: /* NP */ - case 0x38: /* TR */ /* Ignored. */ case 0x3c: /* Undocuented: Timestamp? */ /* Ignored. */ @@ -324,68 +448,7 @@ static void stellaris_enet_reset(stellaris_enet_state *s) s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP | SE_INT_TXER | SE_INT_RX; s->thr = 0x3f; - s->tx_frame_len = -1; -} - -static void stellaris_enet_save(QEMUFile *f, void *opaque) -{ - stellaris_enet_state *s = (stellaris_enet_state *)opaque; - int i; - - qemu_put_be32(f, s->ris); - qemu_put_be32(f, s->im); - qemu_put_be32(f, s->rctl); - qemu_put_be32(f, s->tctl); - qemu_put_be32(f, s->thr); - qemu_put_be32(f, s->mctl); - qemu_put_be32(f, s->mdv); - qemu_put_be32(f, s->mtxd); - qemu_put_be32(f, s->mrxd); - qemu_put_be32(f, s->np); - qemu_put_be32(f, s->tx_frame_len); - qemu_put_be32(f, s->tx_fifo_len); - qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); - for (i = 0; i < 31; i++) { - qemu_put_be32(f, s->rx[i].len); - qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); - - } - qemu_put_be32(f, s->next_packet); - qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data); - qemu_put_be32(f, s->rx_fifo_len); -} - -static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) -{ - stellaris_enet_state *s = (stellaris_enet_state *)opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - s->ris = qemu_get_be32(f); - s->im = qemu_get_be32(f); - s->rctl = qemu_get_be32(f); - s->tctl = qemu_get_be32(f); - s->thr = qemu_get_be32(f); - s->mctl = qemu_get_be32(f); - s->mdv = qemu_get_be32(f); - s->mtxd = qemu_get_be32(f); - s->mrxd = qemu_get_be32(f); - s->np = qemu_get_be32(f); - s->tx_frame_len = qemu_get_be32(f); - s->tx_fifo_len = qemu_get_be32(f); - qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); - for (i = 0; i < 31; i++) { - s->rx[i].len = qemu_get_be32(f); - qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); - - } - s->next_packet = qemu_get_be32(f); - s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f); - s->rx_fifo_len = qemu_get_be32(f); - - return 0; + s->tx_fifo_len = 0; } static void stellaris_enet_cleanup(NetClientState *nc) @@ -419,8 +482,6 @@ static int stellaris_enet_init(SysBusDevice *sbd) qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); stellaris_enet_reset(s); - register_savevm(dev, "stellaris_enet", -1, 1, - stellaris_enet_save, stellaris_enet_load, s); return 0; } @@ -428,8 +489,6 @@ static void stellaris_enet_unrealize(DeviceState *dev, Error **errp) { stellaris_enet_state *s = STELLARIS_ENET(dev); - unregister_savevm(DEVICE(s), "stellaris_enet", s); - memory_region_destroy(&s->mmio); } @@ -446,6 +505,7 @@ static void stellaris_enet_class_init(ObjectClass *klass, void *data) k->init = stellaris_enet_init; dc->unrealize = stellaris_enet_unrealize; dc->props = stellaris_enet_properties; + dc->vmsd = &vmstate_stellaris_enet; } static const TypeInfo stellaris_enet_info = { diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index 88349ac6a2..aeffcb58b7 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -156,7 +156,7 @@ static const VMStateDescription vmstate_rxtx_stats = { .name = "xgmac_stats", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT64(rx_bytes, RxTxStats), VMSTATE_UINT64(tx_bytes, RxTxStats), VMSTATE_UINT64(rx, RxTxStats), diff --git a/hw/nvram/ds1225y.c b/hw/nvram/ds1225y.c index f9a700b01c..332598b257 100644 --- a/hw/nvram/ds1225y.c +++ b/hw/nvram/ds1225y.c @@ -95,7 +95,6 @@ static const VMStateDescription vmstate_nvram = { .name = "nvram", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .post_load = nvram_post_load, .fields = (VMStateField[]) { VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0, diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index 2eb008179a..170b10b766 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -96,8 +96,7 @@ static const VMStateDescription vmstate_macio_nvram = { .name = "macio_nvram", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size), VMSTATE_END_OF_LIST() } diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 902441f10b..56292adb03 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -687,8 +687,7 @@ static const VMStateDescription vmstate_bonito = { .name = "Bonito", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, PCIBonitoState), VMSTATE_END_OF_LIST() } diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 2e9e62fe1f..597db34019 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -319,8 +319,7 @@ static const VMStateDescription vmstate_event_facility = { .name = "vmstate-event-facility", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(receive_mask, SCLPEventFacility), VMSTATE_END_OF_LIST() } diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index a3c4bd6272..1a399bd1f0 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -69,8 +69,7 @@ static const VMStateDescription vmstate_sclpquiesce = { .name = "sclpquiesce", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(event_pending, SCLPEvent), VMSTATE_END_OF_LIST() } diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index 48c8b82350..9971bbf92d 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -310,7 +310,6 @@ static const VMStateDescription vmstate_esp_pci_scsi = { .name = "pciespscsi", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, PCIESPState), VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)), diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 2d150bfe48..5ab44d860b 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -560,8 +560,7 @@ const VMStateDescription vmstate_esp = { .name ="esp", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_BUFFER(rregs, ESPState), VMSTATE_BUFFER(wregs, ESPState), VMSTATE_INT32(ti_size, ESPState), @@ -706,7 +705,6 @@ static const VMStateDescription vmstate_sysbus_esp_scsi = { .name = "sysbusespscsi", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState), VMSTATE_END_OF_LIST() diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index d1168c9e04..2a40f92732 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -272,8 +272,7 @@ static const VMStateDescription vmstate_milkymist_memcard = { .name = "milkymist-memcard", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32(command_write_ptr, MilkymistMemcardState), VMSTATE_INT32(response_read_ptr, MilkymistMemcardState), VMSTATE_INT32(response_len, MilkymistMemcardState), diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 843e697bfe..e2951e6e95 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1197,7 +1197,7 @@ const VMStateDescription sdhci_vmstate = { .name = "sdhci", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(sdmasysad, SDHCIState), VMSTATE_UINT16(blksize, SDHCIState), VMSTATE_UINT16(blkcnt, SDHCIState), diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c index b19bc7174a..61d568f36e 100644 --- a/hw/ssi/pl022.c +++ b/hw/ssi/pl022.c @@ -257,9 +257,8 @@ static const VMStateDescription vmstate_pl022 = { .name = "pl022_ssp", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = pl022_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(cr0, PL022State), VMSTATE_UINT32(cr1, PL022State), VMSTATE_UINT32(bitmask, PL022State), diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 017f0221fb..1c82a93590 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -126,8 +126,7 @@ const VMStateDescription vmstate_ssi_slave = { .name = "SSISlave", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_BOOL(cs, SSISlave), VMSTATE_END_OF_LIST() } diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index d44caae8ad..207f47a1c0 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -351,7 +351,6 @@ static const VMStateDescription vmstate_xilinx_spi = { .name = "xilinx_spi", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_FIFO8(tx_fifo, XilinxSPI), VMSTATE_FIFO8(rx_fifo, XilinxSPI), diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 8977243725..0910f5479a 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -704,7 +704,6 @@ static const VMStateDescription vmstate_xilinx_spips = { .name = "xilinx_spips", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .post_load = xilinx_spips_post_load, .fields = (VMStateField[]) { VMSTATE_FIFO8(tx_fifo, XilinxSPIPS), diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index d3c02ea18f..34124fe3d1 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -190,7 +190,6 @@ static const VMStateDescription vmstate_a10_pit = { .name = "a10.pit", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(irq_enable, AwA10PITState), VMSTATE_UINT32(irq_status, AwA10PITState), diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index fb0a45c889..145291016b 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -150,8 +150,7 @@ static const VMStateDescription vmstate_arm_timer = { .name = "arm_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(control, arm_timer_state), VMSTATE_UINT32(limit, arm_timer_state), VMSTATE_INT32(int_level, arm_timer_state), @@ -271,8 +270,7 @@ static const VMStateDescription vmstate_sp804 = { .name = "sp804", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_INT32_ARRAY(level, SP804State, 2), VMSTATE_END_OF_LIST() } diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c index 28cb328f9b..52bbbbca7f 100644 --- a/hw/timer/cadence_ttc.c +++ b/hw/timer/cadence_ttc.c @@ -443,7 +443,6 @@ static const VMStateDescription vmstate_cadence_timer = { .name = "cadence_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .pre_save = cadence_timer_pre_save, .post_load = cadence_timer_post_load, .fields = (VMStateField[]) { @@ -464,7 +463,6 @@ static const VMStateDescription vmstate_cadence_ttc = { .name = "cadence_TTC", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0, vmstate_cadence_timer, diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index 1fde22c67f..7e28e7e5f5 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -36,7 +36,6 @@ static const VMStateDescription vmstate_digic_timer = { .name = "digic.timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_PTIMER(ptimer, DigicTimerState), VMSTATE_UINT32(control, DigicTimerState), diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c index bb2f8ee8b3..ec6dbeeab0 100644 --- a/hw/timer/ds1338.c +++ b/hw/timer/ds1338.c @@ -40,7 +40,6 @@ static const VMStateDescription vmstate_ds1338 = { .name = "ds1338", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_I2C_SLAVE(parent_obj, DS1338State), VMSTATE_INT64(offset, DS1338State), diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 86f4fcd3e8..015bbaf1bd 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -264,7 +264,6 @@ static const VMStateDescription vmstate_tick_timer = { .name = "exynos4210.mct.tick_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(cnt_run, struct tick_timer), VMSTATE_UINT32(int_run, struct tick_timer), @@ -284,7 +283,6 @@ static const VMStateDescription vmstate_lregs = { .name = "exynos4210.mct.lregs", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT), VMSTATE_UINT32(tcon, struct lregs), @@ -299,7 +297,6 @@ static const VMStateDescription vmstate_exynos4210_mct_lt = { .name = "exynos4210.mct.lt", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_INT32(id, Exynos4210MCTLT), VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0, @@ -317,7 +314,6 @@ static const VMStateDescription vmstate_gregs = { .name = "exynos4210.mct.lregs", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT64(cnt, struct gregs), VMSTATE_UINT32(cnt_wstat, struct gregs), @@ -336,7 +332,6 @@ static const VMStateDescription vmstate_exynos4210_mct_gt = { .name = "exynos4210.mct.lt", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs, struct gregs), @@ -351,7 +346,6 @@ static const VMStateDescription vmstate_exynos4210_mct_state = { .name = "exynos4210.mct", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState), VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0, @@ -824,14 +818,14 @@ static void exynos4210_ltick_recalc_count(struct tick_timer *s) */ if (s->last_tcnto) { - to_count = s->last_tcnto * s->last_icnto; + to_count = (uint64_t)s->last_tcnto * s->last_icnto; } else { to_count = s->last_icnto; } } else { /* distance is passed, recalculate with tcnto * icnto */ if (s->icntb) { - s->distance = s->tcntb * s->icntb; + s->distance = (uint64_t)s->tcntb * s->icntb; } else { s->distance = s->tcntb; } diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 1aa8f4d07a..1c1a2b8ff6 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -120,7 +120,6 @@ static const VMStateDescription vmstate_exynos4210_pwm = { .name = "exynos4210.pwm.pwm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(id, Exynos4210PWM), VMSTATE_UINT32(freq, Exynos4210PWM), @@ -135,7 +134,6 @@ static const VMStateDescription vmstate_exynos4210_pwm_state = { .name = "exynos4210.pwm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(reg_tcfg, Exynos4210PWMState, 2), VMSTATE_UINT32(reg_tcon, Exynos4210PWMState), diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index 026f81a2e3..bf2ee9f80e 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -118,7 +118,6 @@ static const VMStateDescription vmstate_exynos4210_rtc_state = { .name = "exynos4210.rtc", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(reg_intp, Exynos4210RTCState), VMSTATE_UINT32(reg_rtccon, Exynos4210RTCState), diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index 0dbe15c99b..c855eba43c 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -353,8 +353,7 @@ static const VMStateDescription vmstate_imx_timer_epit = { .name = "imx.epit", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(cr, IMXEPITState), VMSTATE_UINT32(sr, IMXEPITState), VMSTATE_UINT32(lr, IMXEPITState), diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index f2d1975e70..56ee4db991 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -146,8 +146,7 @@ static const VMStateDescription vmstate_imx_timer_gpt = { .name = "imx.gpt", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(cr, IMXGPTState), VMSTATE_UINT32(pr, IMXGPTState), VMSTATE_UINT32(sr, IMXGPTState), diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index 8ed138cc0e..d2ab1e74b2 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -196,8 +196,7 @@ static const VMStateDescription vmstate_lm32_timer = { .name = "lm32-timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_PTIMER(ptimer, LM32TimerState), VMSTATE_UINT32(freq_hz, LM32TimerState), VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX), diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 94246e56f6..30535a4e3d 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -295,8 +295,7 @@ static const VMStateDescription vmstate_milkymist_sysctl = { .name = "milkymist-sysctl", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX), VMSTATE_PTIMER(ptimer0, MilkymistSysctlState), VMSTATE_PTIMER(ptimer1, MilkymistSysctlState), diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 0f546c4121..130e9dc345 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -476,7 +476,6 @@ static const VMStateDescription vmstate_pxa2xx_timer0_regs = { .name = "pxa2xx_timer0", .version_id = 2, .minimum_version_id = 2, - .minimum_version_id_old = 2, .fields = (VMStateField[]) { VMSTATE_UINT32(value, PXA2xxTimer0), VMSTATE_END_OF_LIST(), @@ -487,7 +486,6 @@ static const VMStateDescription vmstate_pxa2xx_timer4_regs = { .name = "pxa2xx_timer4", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), @@ -509,7 +507,6 @@ static const VMStateDescription vmstate_pxa2xx_timer_regs = { .name = "pxa2xx_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = pxa25x_timer_post_load, .fields = (VMStateField[]) { VMSTATE_INT32(clock, PXA2xxTimerInfo), diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index e4dcceaf23..45d97e6678 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -329,8 +329,7 @@ static const VMStateDescription vmstate_timer = { .name ="timer", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT64(limit, CPUTimerState), VMSTATE_UINT32(count, CPUTimerState), VMSTATE_UINT32(counthigh, CPUTimerState), @@ -345,8 +344,7 @@ static const VMStateDescription vmstate_slavio_timer = { .name ="slavio_timer", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3, vmstate_timer, CPUTimerState), VMSTATE_END_OF_LIST() diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c index 85d59909da..7ded4ba2ad 100644 --- a/hw/timer/twl92230.c +++ b/hw/timer/twl92230.c @@ -772,8 +772,7 @@ static const VMStateDescription vmstate_menelaus_tm = { .name = "menelaus_tm", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16_HACK(tm_sec, struct tm), VMSTATE_UINT16_HACK(tm_min, struct tm), VMSTATE_UINT16_HACK(tm_hour, struct tm), @@ -811,10 +810,9 @@ static const VMStateDescription vmstate_menelaus = { .name = "menelaus", .version_id = 0, .minimum_version_id = 0, - .minimum_version_id_old = 0, .pre_save = menelaus_pre_save, .post_load = menelaus_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_INT32(firstbyte, MenelausState), VMSTATE_UINT8(reg, MenelausState), VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5), diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 6113b975bf..3ff1da9caf 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -169,7 +169,7 @@ timer_write(void *opaque, hwaddr addr, if (value & TCSR_TINT) value &= ~TCSR_TINT; - xt->regs[addr] = value; + xt->regs[addr] = value & 0x7ff; if (value & TCSR_ENT) timer_enable(xt); break; diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 17d460cb04..3fe4dff3bd 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -24,6 +24,7 @@ ifeq ($(CONFIG_USB_SMARTCARD),y) common-obj-y += dev-smartcard-reader.o common-obj-y += ccid-card-passthru.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o +ccid-card-emulated.o-cflags := -I$(SRC_PATH)/libcacard endif ifeq ($(CONFIG_POSIX),y) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index e48b19fc29..927a47bbff 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -51,8 +51,8 @@ static int usb_device_post_load(void *opaque, int version_id) } if (dev->setup_index < 0 || dev->setup_len < 0 || - dev->setup_index >= sizeof(dev->data_buf) || - dev->setup_len >= sizeof(dev->data_buf)) { + dev->setup_index > dev->setup_len || + dev->setup_len > sizeof(dev->data_buf)) { return -EINVAL; } return 0; @@ -63,7 +63,7 @@ const VMStateDescription vmstate_usb_device = { .version_id = 1, .minimum_version_id = 1, .post_load = usb_device_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(addr, USBDevice), VMSTATE_INT32(state, USBDevice), VMSTATE_INT32(remote_wakeup, USBDevice), diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index f36e617632..d097d937ea 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -622,7 +622,7 @@ static const VMStateDescription vmstate_usb_ptr = { .version_id = 1, .minimum_version_id = 1, .post_load = usb_ptr_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, USBHIDState), VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState), VMSTATE_END_OF_LIST() @@ -633,7 +633,7 @@ static const VMStateDescription vmstate_usb_kbd = { .name = "usb-kbd", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, USBHIDState), VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState), VMSTATE_END_OF_LIST() diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index bc03531666..749217497a 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -540,7 +540,7 @@ static const VMStateDescription vmstate_usb_hub_port = { .name = "usb-hub-port", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(wPortStatus, USBHubPort), VMSTATE_UINT16(wPortChange, USBHubPort), VMSTATE_END_OF_LIST() @@ -551,7 +551,7 @@ static const VMStateDescription vmstate_usb_hub = { .name = "usb-hub", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, USBHubState), VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0, vmstate_usb_hub_port, USBHubPort), diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 2852669d57..e919100637 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -716,7 +716,7 @@ static const VMStateDescription vmstate_usb_msd = { .name = "usb-storage", .version_id = 1, .minimum_version_id = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_USB_DEVICE(dev, MSDState), VMSTATE_UINT32(mode, MSDState), VMSTATE_UINT32(scsi_len, MSDState), diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 484a9bd059..505741a783 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -108,7 +108,7 @@ static const VMStateDescription vmstate_ehci_pci = { .name = "ehci", .version_id = 2, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState), VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState), VMSTATE_END_OF_LIST() diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index fe6eea5908..19ed2c26aa 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -21,7 +21,7 @@ static const VMStateDescription vmstate_ehci_sysbus = { .name = "ehci-sysbus", .version_id = 2, .minimum_version_id = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState), VMSTATE_END_OF_LIST() } diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 355bbd6bed..a3ae9f260a 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2492,7 +2492,7 @@ const VMStateDescription vmstate_ehci = { .minimum_version_id = 1, .pre_save = usb_ehci_pre_save, .post_load = usb_ehci_post_load, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { /* mmio registers */ VMSTATE_UINT32(usbcmd, EHCIState), VMSTATE_UINT32(usbsts, EHCIState), diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 0820244905..9b1166b2ef 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -422,8 +422,7 @@ static const VMStateDescription vmstate_uhci_port = { .name = "uhci port", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT16(ctrl, UHCIPort), VMSTATE_END_OF_LIST() } @@ -444,9 +443,8 @@ static const VMStateDescription vmstate_uhci = { .name = "uhci", .version_id = 3, .minimum_version_id = 1, - .minimum_version_id_old = 1, .post_load = uhci_post_load, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, UHCIState), VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState), VMSTATE_STRUCT_ARRAY(ports, UHCIState, NB_PORTS, 1, diff --git a/include/block/block.h b/include/block/block.h index 467fb2ba0a..1b119aac24 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -34,6 +34,10 @@ typedef struct BlockDriverInfo { * opened with BDRV_O_UNMAP flag for this to work. */ bool can_write_zeroes_with_unmap; + /* + * True if this block driver only supports compressed writes + */ + bool needs_compressed_writes; } BlockDriverInfo; typedef struct BlockFragInfo { @@ -191,7 +195,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename, QDict *options, const char *bdref_key, int flags, bool allow_none, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp); -void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp); +void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp); int bdrv_open(BlockDriverState **pbs, const char *filename, const char *reference, QDict *options, int flags, BlockDriver *drv, Error **errp); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index fb649a4029..9cab592dc5 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -381,6 +381,9 @@ CPUArchState *cpu_copy(CPUArchState *env); /* Debug event pending. */ #define CPU_INTERRUPT_DEBUG 0x0080 +/* Reset signal. */ +#define CPU_INTERRUPT_RESET 0x0400 + /* Several target-specific external hardware interrupts. Each target/cpu.h should define proper names based on these defines. */ #define CPU_INTERRUPT_TGT_EXT_0 0x0008 @@ -395,9 +398,8 @@ CPUArchState *cpu_copy(CPUArchState *env); instruction being executed. These, therefore, are not masked while single-stepping within the debugger. */ #define CPU_INTERRUPT_TGT_INT_0 0x0100 -#define CPU_INTERRUPT_TGT_INT_1 0x0400 -#define CPU_INTERRUPT_TGT_INT_2 0x0800 -#define CPU_INTERRUPT_TGT_INT_3 0x2000 +#define CPU_INTERRUPT_TGT_INT_1 0x0800 +#define CPU_INTERRUPT_TGT_INT_2 0x2000 /* First unused bit: 0x4000. */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index f9ac332f9d..444b4d9a1d 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -145,7 +145,7 @@ struct TranslationBlock { #define CF_COUNT_MASK 0x7fff #define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */ - uint8_t *tc_ptr; /* pointer to the translated code */ + void *tc_ptr; /* pointer to the translated code */ /* next matching tb for physical address. */ struct TranslationBlock *phys_hash_next; /* first and second physical page containing code. The lower bit @@ -229,7 +229,7 @@ void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr); static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) { /* patch the branch destination */ - *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); + stl_le_p((void*)jmp_addr, addr - (jmp_addr + 4)); /* no need to flush icache explicitly */ } #elif defined(__aarch64__) diff --git a/include/glib-compat.h b/include/glib-compat.h index 8d25900700..1280fb2c1f 100644 --- a/include/glib-compat.h +++ b/include/glib-compat.h @@ -24,7 +24,14 @@ static inline guint g_timeout_add_seconds(guint interval, GSourceFunc function, } #endif -#if !GLIB_CHECK_VERSION(2, 20, 0) +#ifdef _WIN32 +/* + * g_poll has a problem on Windows when using + * timeouts < 10ms, so use wrapper. + */ +#define g_poll(fds, nfds, timeout) g_poll_fixed(fds, nfds, timeout) +gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout); +#elif !GLIB_CHECK_VERSION(2, 20, 0) /* * Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly * on older systems. diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 5ad4e0e1e2..e7ad9d159a 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -245,8 +245,6 @@ int kvm_arch_init_vcpu(CPUState *cpu); /* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */ unsigned long kvm_arch_vcpu_id(CPUState *cpu); -void kvm_arch_reset_vcpu(CPUState *cpu); - int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); int kvm_arch_on_sigbus(int code, void *addr); @@ -383,4 +381,24 @@ void kvm_init_irq_routing(KVMState *s); * > 0: irq chip was created */ int kvm_arch_irqchip_create(KVMState *s); + +/** + * kvm_set_one_reg - set a register value in KVM via KVM_SET_ONE_REG ioctl + * @id: The register ID + * @source: The pointer to the value to be set. It must point to a variable + * of the correct type/size for the register being accessed. + * + * Returns: 0 on success, or a negative errno on failure. + */ +int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source); + +/** + * kvm_get_one_reg - get a register value from KVM via KVM_GET_ONE_REG ioctl + * @id: The register ID + * @target: The pointer where the value is to be stored. It must point to a + * variable of the correct type/size for the register being accessed. + * + * Returns: 0 on success, or a negative errno on failure. + */ +int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target); #endif @@ -223,13 +223,6 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); } -static void kvm_reset_vcpu(void *opaque) -{ - CPUState *cpu = opaque; - - kvm_arch_reset_vcpu(cpu); -} - int kvm_init_vcpu(CPUState *cpu) { KVMState *s = kvm_state; @@ -269,10 +262,6 @@ int kvm_init_vcpu(CPUState *cpu) } ret = kvm_arch_init_vcpu(cpu); - if (ret == 0) { - qemu_register_reset(kvm_reset_vcpu, cpu); - kvm_arch_reset_vcpu(cpu); - } err: return ret; } @@ -2114,3 +2103,31 @@ int kvm_create_device(KVMState *s, uint64_t type, bool test) return test ? 0 : create_dev.fd; } + +int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source) +{ + struct kvm_one_reg reg; + int r; + + reg.id = id; + reg.addr = (uintptr_t) source; + r = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (r) { + trace_kvm_failed_reg_set(id, strerror(r)); + } + return r; +} + +int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target) +{ + struct kvm_one_reg reg; + int r; + + reg.id = id; + reg.addr = (uintptr_t) target; + r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (r) { + trace_kvm_failed_reg_get(id, strerror(r)); + } + return r; +} diff --git a/libcacard/Makefile b/libcacard/Makefile index 6b064485fa..881b222f93 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -25,7 +25,6 @@ vscclient$(EXESUF): libcacard/vscclient.o libcacard.la libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined \ -export-syms $(SRC_PATH)/libcacard/libcacard.syms -libcacard.la: LIBS = $(libcacard_libs) libcacard.la: $(libcacard-lobj-y) $(call LINK,$^) diff --git a/linux-user/main.c b/linux-user/main.c index c38fecfdd9..882186e1a0 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4051,8 +4051,6 @@ int main(int argc, char **argv, char **envp) #endif #if defined(TARGET_I386) - cpu_x86_set_cpl(env, 3); - env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; env->hflags |= HF_PE_MASK; if (env->features[FEAT_1_EDX] & CPUID_SSE) { diff --git a/migration.c b/migration.c index 52cda279af..3fc03d6687 100644 --- a/migration.c +++ b/migration.c @@ -662,8 +662,13 @@ static void *migration_thread(void *opaque) qemu_mutex_lock_iothread(); if (s->state == MIG_STATE_COMPLETED) { int64_t end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + uint64_t transferred_bytes = qemu_ftell(s->file); s->total_time = end_time - s->total_time; s->downtime = end_time - start_time; + if (s->total_time) { + s->mbps = (((double) transferred_bytes * 8.0) / + ((double) s->total_time)) / 1000; + } runstate_set(RUN_STATE_POSTMIGRATE); } else { if (old_vm_running) { diff --git a/qemu-img.c b/qemu-img.c index 96f44638b7..04ce02aeb4 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -32,6 +32,7 @@ #include "block/block_int.h" #include "block/qapi.h" #include <getopt.h> +#include <glib.h> #define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION \ ", Copyright (c) 2004-2008 Fabrice Bellard\n" @@ -55,9 +56,25 @@ typedef enum OutputFormat { #define BDRV_O_FLAGS BDRV_O_CACHE_WB #define BDRV_DEFAULT_CACHE "writeback" -static void format_print(void *opaque, const char *name) +static gint compare_data(gconstpointer a, gconstpointer b, gpointer user) { - printf(" %s", name); + return g_strcmp0(a, b); +} + +static void print_format(gpointer data, gpointer user) +{ + printf(" %s", (char *)data); +} + +static void add_format_to_seq(void *opaque, const char *fmt_name) +{ + GSequence *seq = opaque; + + if (!g_sequence_lookup(seq, (gpointer)fmt_name, + compare_data, NULL)) { + g_sequence_insert_sorted(seq, (gpointer)fmt_name, + compare_data, NULL); + } } static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...) @@ -142,10 +159,15 @@ static void QEMU_NORETURN help(void) " '-f' first image format\n" " '-F' second image format\n" " '-s' run in Strict mode - fail on different image size or sector allocation\n"; + GSequence *seq; printf("%s\nSupported formats:", help_msg); - bdrv_iterate_format(format_print, NULL); + seq = g_sequence_new(NULL); + bdrv_iterate_format(add_format_to_seq, seq); + g_sequence_foreach(seq, print_format, NULL); printf("\n"); + g_sequence_free(seq); + exit(EXIT_SUCCESS); } @@ -1480,6 +1502,7 @@ static int img_convert(int argc, char **argv) goto out; } } else { + compress = compress || bdi.needs_compressed_writes; cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; } diff --git a/qemu-timer.c b/qemu-timer.c index 9be1a4131d..00a5d35c3f 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -126,6 +126,9 @@ static void qemu_clock_init(QEMUClockType type) { QEMUClock *clock = qemu_clock_ptr(type); + /* Assert that the clock of type TYPE has not been initialized yet. */ + assert(main_loop_tlg.tl[type] == NULL); + clock->type = type; clock->enabled = true; clock->last = INT64_MIN; @@ -45,7 +45,7 @@ LINK = $(call quiet-command,$(LINKPROG) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $ else LIBTOOL += $(if $(V),,--quiet) %.lo: %.c - $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," lt CC $@") + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($*.o-cflags) -c -o $@ $<," lt CC $@") %.lo: %.rc $(call quiet-command,$(LIBTOOL) --mode=compile --tag=RC $(WINDRES) -I. -o $@ $<,"lt RC $(TARGET_DIR)$@") %.lo: %.dtrace @@ -57,7 +57,7 @@ LINK = $(call quiet-command,\ $(call expand-objs,$1) \ $(if $(filter %.lo %.la,$1),$(version-lobj-y),$(version-obj-y)) \ $(if $(filter %.lo %.la,$1),$(LIBTOOLFLAGS)) \ - $(call extract-libs,$1) $(LIBS),$(if $(filter %.lo %.la,$1),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") + $(call extract-libs,$(1:.lo=.o)) $(LIBS),$(if $(filter %.lo %.la,$1),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") endif %.asm: %.S @@ -67,13 +67,13 @@ endif $(call quiet-command,$(AS) $(ASFLAGS) -o $@ $<," AS $(TARGET_DIR)$@") %.o: %.cc - $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CXX $(TARGET_DIR)$@") + $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," CXX $(TARGET_DIR)$@") %.o: %.cpp - $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CXX $(TARGET_DIR)$@") + $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," CXX $(TARGET_DIR)$@") %.o: %.m - $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@") + $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) $($@-cflags) -c -o $@ $<," OBJC $(TARGET_DIR)$@") %.o: %.dtrace $(call quiet-command,dtrace -o $@ -G -s $<, " GEN $(TARGET_DIR)$@") @@ -175,16 +175,16 @@ $(eval save-$2-$1 :=) endef define fix-obj-vars -$(foreach v,$($1), \ +$(if $2, $(foreach v,$($1), \ $(if $($v-cflags), \ - $(eval $2$v-cflags := $($v-cflags)) \ + $(eval $2/$v-cflags := $($v-cflags)) \ $(eval $v-cflags := )) \ $(if $($v-libs), \ - $(eval $2$v-libs := $($v-libs)) \ + $(eval $2/$v-libs := $($v-libs)) \ $(eval $v-libs := )) \ $(if $($v-objs), \ - $(eval $2$v-objs := $(addprefix $2,$($v-objs))) \ - $(eval $v-objs := ))) + $(eval $2/$v-objs := $(addprefix $2/,$($v-objs))) \ + $(eval $v-objs := )))) endef define unnest-dir @@ -192,7 +192,7 @@ $(foreach var,$(nested-vars),$(call push-var,$(var),$1/)) $(eval obj-parent-$1 := $(obj)) $(eval obj := $(if $(obj),$(obj)/$1,$1)) $(eval include $(SRC_PATH)/$1/Makefile.objs) -$(foreach v,$(nested-vars),$(call fix-obj-vars,$v,$(if $(obj),$(obj)/))) +$(foreach v,$(nested-vars),$(call fix-obj-vars,$v,$(obj))) $(eval obj := $(obj-parent-$1)) $(eval obj-parent-$1 := ) $(foreach var,$(nested-vars),$(call pop-var,$(var),$1/)) @@ -228,6 +228,7 @@ endef define unnest-vars $(eval obj := $1) $(eval nested-vars := $2) +$(foreach v,$(nested-vars),$(call fix-obj-vars,$v,$(obj))) $(eval old-nested-dirs := ) $(call unnest-vars-1) $(if $1,$(foreach v,$(nested-vars),$(eval \ diff --git a/target-alpha/machine.c b/target-alpha/machine.c index 889f2fcd03..e796bbe27d 100644 --- a/target-alpha/machine.c +++ b/target-alpha/machine.c @@ -72,7 +72,6 @@ static const VMStateDescription vmstate_env = { .name = "env", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = vmstate_env_fields, }; @@ -86,6 +85,5 @@ const VMStateDescription vmstate_alpha_cpu = { .name = "cpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = vmstate_cpu_fields, }; diff --git a/target-arm/cpu.c b/target-arm/cpu.c index c0ddc3e3df..6c6f2b3d46 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -29,6 +29,7 @@ #include "hw/arm/arm.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" +#include "kvm_arm.h" static void arm_cpu_set_pc(CPUState *cs, vaddr value) { @@ -165,6 +166,12 @@ static void arm_cpu_reset(CPUState *s) * tb_flush(). */ tb_flush(env); + +#ifndef CONFIG_USER_ONLY + if (kvm_enabled()) { + kvm_arm_reset_vcpu(cpu); + } +#endif } #ifndef CONFIG_USER_ONLY diff --git a/target-arm/helper.c b/target-arm/helper.c index 3be917c22e..417161e216 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2081,6 +2081,13 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, { ARMCPU *cpu = arm_env_get_cpu(env); + if (env->cp15.c1_sys == value) { + /* Skip the TLB flush if nothing actually changed; Linux likes + * to do a lot of pointless SCTLR writes. + */ + return; + } + env->cp15.c1_sys = value; /* ??? Lots of these bits are not implemented. */ /* This may enable/disable the MMU, so do a TLB flush. */ diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index a690d9935f..b79750c57e 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -510,11 +510,9 @@ int kvm_arch_get_registers(CPUState *cs) return 0; } -void kvm_arch_reset_vcpu(CPUState *cs) +void kvm_arm_reset_vcpu(ARMCPU *cpu) { /* Feed the kernel back its initial register state */ - ARMCPU *cpu = ARM_CPU(cs); - memmove(cpu->cpreg_values, cpu->cpreg_reset_values, cpu->cpreg_array_len * sizeof(cpu->cpreg_values[0])); diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index e115879d9a..c729b9ec9f 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -260,6 +260,6 @@ int kvm_arch_get_registers(CPUState *cs) return ret; } -void kvm_arch_reset_vcpu(CPUState *cs) +void kvm_arm_reset_vcpu(ARMCPU *cpu) { } diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index 137c5671e9..dc4e2336fa 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -67,6 +67,14 @@ bool write_list_to_kvmstate(ARMCPU *cpu); */ bool write_kvmstate_to_list(ARMCPU *cpu); +/** + * kvm_arm_reset_vcpu: + * @cpu: ARMCPU + * + * Called at reset time to kernel registers to their initial values. + */ +void kvm_arm_reset_vcpu(ARMCPU *cpu); + #ifdef CONFIG_KVM /** * kvm_arm_create_scratch_host_vcpu: diff --git a/target-arm/machine.c b/target-arm/machine.c index 810ba27f40..5092dcda79 100644 --- a/target-arm/machine.c +++ b/target-arm/machine.c @@ -39,7 +39,6 @@ static const VMStateDescription vmstate_vfp = { .name = "cpu/vfp", .version_id = 3, .minimum_version_id = 3, - .minimum_version_id_old = 3, .fields = (VMStateField[]) { VMSTATE_FLOAT64_ARRAY(env.vfp.regs, ARMCPU, 64), /* The xregs array is a little awkward because element 1 (FPSCR) @@ -72,7 +71,6 @@ static const VMStateDescription vmstate_iwmmxt = { .name = "cpu/iwmmxt", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT64_ARRAY(env.iwmmxt.regs, ARMCPU, 16), VMSTATE_UINT32_ARRAY(env.iwmmxt.cregs, ARMCPU, 16), @@ -92,7 +90,6 @@ static const VMStateDescription vmstate_m = { .name = "cpu/m", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(env.v7m.other_sp, ARMCPU), VMSTATE_UINT32(env.v7m.vecbase, ARMCPU), @@ -116,7 +113,6 @@ static const VMStateDescription vmstate_thumb2ee = { .name = "cpu/thumb2ee", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(env.teecr, ARMCPU), VMSTATE_UINT32(env.teehbr, ARMCPU), @@ -224,7 +220,6 @@ const VMStateDescription vmstate_arm_cpu = { .name = "cpu", .version_id = 17, .minimum_version_id = 17, - .minimum_version_id_old = 17, .pre_save = cpu_pre_save, .post_load = cpu_post_load, .fields = (VMStateField[]) { diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 8f193a9330..042a48d703 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -24,6 +24,7 @@ #include "cpu.h" #include "sysemu/kvm.h" #include "sysemu/cpus.h" +#include "kvm_i386.h" #include "topology.h" #include "qemu/option.h" @@ -2417,8 +2418,7 @@ static void x86_cpu_reset(CPUState *s) xcc->parent_reset(s); - - memset(env, 0, offsetof(CPUX86State, pat)); + memset(env, 0, offsetof(CPUX86State, cpuid_level)); tlb_flush(s, 1); @@ -2484,8 +2484,7 @@ static void x86_cpu_reset(CPUState *s) cpu_breakpoint_remove_all(s, BP_CPU); cpu_watchpoint_remove_all(s, BP_CPU); - env->tsc_adjust = 0; - env->tsc = 0; + env->xcr0 = 1; #if !defined(CONFIG_USER_ONLY) /* We hard-wire the BSP to the first CPU. */ @@ -2494,6 +2493,10 @@ static void x86_cpu_reset(CPUState *s) } s->halted = !cpu_is_bsp(cpu); + + if (kvm_enabled()) { + kvm_arch_reset_vcpu(cpu); + } #endif } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 2a22a7d64e..e9cbdabc03 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -124,9 +124,9 @@ #define ID_MASK 0x00200000 /* hidden flags - used internally by qemu to represent additional cpu - states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not - redundant. We avoid using the IOPL_MASK, TF_MASK, VM_MASK and AC_MASK - bit positions to ease oring with eflags. */ + states. Only the INHIBIT_IRQ, SMM and SVMI are not redundant. We + avoid using the IOPL_MASK, TF_MASK, VM_MASK and AC_MASK bit + positions to ease oring with eflags. */ /* current cpl */ #define HF_CPL_SHIFT 0 /* true if soft mmu is being used */ @@ -606,10 +606,11 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3 #define CPU_INTERRUPT_MCE CPU_INTERRUPT_TGT_EXT_4 #define CPU_INTERRUPT_VIRQ CPU_INTERRUPT_TGT_INT_0 -#define CPU_INTERRUPT_INIT CPU_INTERRUPT_TGT_INT_1 -#define CPU_INTERRUPT_SIPI CPU_INTERRUPT_TGT_INT_2 -#define CPU_INTERRUPT_TPR CPU_INTERRUPT_TGT_INT_3 +#define CPU_INTERRUPT_SIPI CPU_INTERRUPT_TGT_INT_1 +#define CPU_INTERRUPT_TPR CPU_INTERRUPT_TGT_INT_2 +/* Use a clearer name for this. */ +#define CPU_INTERRUPT_INIT CPU_INTERRUPT_RESET typedef enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ @@ -797,6 +798,13 @@ typedef struct CPUX86State { target_ulong cr[5]; /* NOTE: cr1 is unused */ int32_t a20_mask; + BNDReg bnd_regs[4]; + BNDCSReg bndcs_regs; + uint64_t msr_bndcfgs; + + /* Beginning of state preserved by INIT (dummy marker). */ + struct {} start_init_save; + /* FPU state */ unsigned int fpstt; /* top of stack index */ uint16_t fpus; @@ -819,6 +827,8 @@ typedef struct CPUX86State { XMMReg xmm_t0; MMXReg mmx_t0; + XMMReg ymmh_regs[CPU_NB_REGS]; + /* sysenter registers */ uint32_t sysenter_cs; target_ulong sysenter_esp; @@ -827,15 +837,6 @@ typedef struct CPUX86State { uint64_t star; uint64_t vm_hsave; - uint64_t vm_vmcb; - uint64_t tsc_offset; - uint64_t intercept; - uint16_t intercept_cr_read; - uint16_t intercept_cr_write; - uint16_t intercept_dr_read; - uint16_t intercept_dr_write; - uint32_t intercept_exceptions; - uint8_t v_tpr; #ifdef TARGET_X86_64 target_ulong lstar; @@ -843,11 +844,6 @@ typedef struct CPUX86State { target_ulong fmask; target_ulong kernelgsbase; #endif - uint64_t system_time_msr; - uint64_t wall_clock_msr; - uint64_t steal_time_msr; - uint64_t async_pf_en_msr; - uint64_t pv_eoi_en_msr; uint64_t tsc; uint64_t tsc_adjust; @@ -864,6 +860,19 @@ typedef struct CPUX86State { uint64_t msr_fixed_counters[MAX_FIXED_COUNTERS]; uint64_t msr_gp_counters[MAX_GP_COUNTERS]; uint64_t msr_gp_evtsel[MAX_GP_COUNTERS]; + + uint64_t pat; + uint32_t smbase; + + /* End of state preserved by INIT (dummy marker). */ + struct {} end_init_save; + + uint64_t system_time_msr; + uint64_t wall_clock_msr; + uint64_t steal_time_msr; + uint64_t async_pf_en_msr; + uint64_t pv_eoi_en_msr; + uint64_t msr_hv_hypercall; uint64_t msr_hv_guest_os_id; uint64_t msr_hv_vapic; @@ -878,9 +887,18 @@ typedef struct CPUX86State { struct CPUBreakpoint *cpu_breakpoint[4]; struct CPUWatchpoint *cpu_watchpoint[4]; }; /* break/watchpoints for dr[0..3] */ - uint32_t smbase; int old_exception; /* exception in flight */ + uint64_t vm_vmcb; + uint64_t tsc_offset; + uint64_t intercept; + uint16_t intercept_cr_read; + uint16_t intercept_cr_write; + uint16_t intercept_dr_read; + uint16_t intercept_dr_write; + uint32_t intercept_exceptions; + uint8_t v_tpr; + /* KVM states, automatically cleared on reset */ uint8_t nmi_injected; uint8_t nmi_pending; @@ -888,7 +906,6 @@ typedef struct CPUX86State { CPU_COMMON /* Fields from here on are preserved across CPU reset. */ - uint64_t pat; /* processor features (e.g. for CPUID insn) */ uint32_t cpuid_level; @@ -928,12 +945,7 @@ typedef struct CPUX86State { uint16_t fpus_vmstate; uint16_t fptag_vmstate; uint16_t fpregs_format_vmstate; - uint64_t xstate_bv; - XMMReg ymmh_regs[CPU_NB_REGS]; - BNDReg bnd_regs[4]; - BNDCSReg bndcs_regs; - uint64_t msr_bndcfgs; uint64_t xcr0; @@ -974,6 +986,7 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, /* update the hidden flags */ { if (seg_reg == R_CS) { + int cpl = selector & 3; #ifdef TARGET_X86_64 if ((env->hflags & HF_LMA_MASK) && (flags & DESC_L_MASK)) { /* long mode */ @@ -983,11 +996,19 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, #endif { /* legacy / compatibility case */ + if (!(env->cr[0] & CR0_PE_MASK)) + cpl = 0; + else if (env->eflags & VM_MASK) + cpl = 3; new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) >> (DESC_B_SHIFT - HF_CS32_SHIFT); env->hflags = (env->hflags & ~(HF_CS32_MASK | HF_CS64_MASK)) | new_hflags; } +#if HF_CPL_MASK != 3 +#error HF_CPL_MASK is hardcoded +#endif + env->hflags = (env->hflags & ~HF_CPL_MASK) | cpl; } new_hflags = (env->segs[R_SS].flags & DESC_B_MASK) >> (DESC_B_SHIFT - HF_SS32_SHIFT); @@ -1031,16 +1052,6 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector, target_ulong *base, unsigned int *limit, unsigned int *flags); -/* wrapper, just in case memory mappings must be changed */ -static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) -{ -#if HF_CPL_MASK == 3 - s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl; -#else -#error HF_CPL_MASK is hardcoded -#endif -} - /* op_helper.c */ /* used for debug or cpu save/restore */ void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f); diff --git a/target-i386/helper.c b/target-i386/helper.c index 372f0e3ecb..46d20e4b89 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "sysemu/kvm.h" +#include "kvm_i386.h" #ifndef CONFIG_USER_ONLY #include "sysemu/sysemu.h" #include "monitor/monitor.h" @@ -1329,12 +1330,21 @@ void do_cpu_init(X86CPU *cpu) { CPUState *cs = CPU(cpu); CPUX86State *env = &cpu->env; + CPUX86State *save = g_new(CPUX86State, 1); int sipi = cs->interrupt_request & CPU_INTERRUPT_SIPI; - uint64_t pat = env->pat; + + *save = *env; cpu_reset(cs); cs->interrupt_request = sipi; - env->pat = pat; + memcpy(&env->start_init_save, &save->start_init_save, + offsetof(CPUX86State, end_init_save) - + offsetof(CPUX86State, start_init_save)); + g_free(save); + + if (kvm_enabled()) { + kvm_arch_do_init_vcpu(cpu); + } apic_init_reset(cpu->apic_state); } diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 4389959f61..0d894ef4aa 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -30,6 +30,8 @@ #include "qemu/config-file.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" +#include "hw/i386/apic_internal.h" +#include "hw/i386/apic-msidef.h" #include "exec/ioport.h" #include <asm/hyperv.h> #include "hw/pci/pci.h" @@ -130,14 +132,13 @@ static const struct kvm_para_features { { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY }, { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP }, { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF }, - { -1, -1 } }; static int get_para_features(KVMState *s) { int i, features = 0; - for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) { + for (i = 0; i < ARRAY_SIZE(para_features); i++) { if (kvm_check_extension(s, para_features[i].cap)) { features |= (1 << para_features[i].feature); } @@ -724,9 +725,8 @@ int kvm_arch_init_vcpu(CPUState *cs) return 0; } -void kvm_arch_reset_vcpu(CPUState *cs) +void kvm_arch_reset_vcpu(X86CPU *cpu) { - X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; env->exception_injected = -1; @@ -740,6 +740,16 @@ void kvm_arch_reset_vcpu(CPUState *cs) } } +void kvm_arch_do_init_vcpu(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + + /* APs get directly into wait-for-SIPI state. */ + if (env->mp_state == KVM_MP_STATE_UNINITIALIZED) { + env->mp_state = KVM_MP_STATE_INIT_RECEIVED; + } +} + static int kvm_get_supported_msrs(KVMState *s) { static int kvm_supported_msrs; @@ -2005,14 +2015,15 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) } } - if (!kvm_irqchip_in_kernel()) { - /* Force the VCPU out of its inner loop to process any INIT requests - * or pending TPR access reports. */ - if (cpu->interrupt_request & - (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { - cpu->exit_request = 1; - } + /* Force the VCPU out of its inner loop to process any INIT requests + * or (for userspace APIC, but it is cheap to combine the checks here) + * pending TPR access reports. + */ + if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { + cpu->exit_request = 1; + } + if (!kvm_irqchip_in_kernel()) { /* Try to inject an interrupt if the guest can accept it */ if (run->ready_for_interrupt_injection && (cpu->interrupt_request & CPU_INTERRUPT_HARD) && @@ -2092,6 +2103,11 @@ int kvm_arch_process_async_events(CPUState *cs) } } + if (cs->interrupt_request & CPU_INTERRUPT_INIT) { + kvm_cpu_synchronize_state(cs); + do_cpu_init(cpu); + } + if (kvm_irqchip_in_kernel()) { return 0; } @@ -2105,10 +2121,6 @@ int kvm_arch_process_async_events(CPUState *cs) (cs->interrupt_request & CPU_INTERRUPT_NMI)) { cs->halted = 0; } - if (cs->interrupt_request & CPU_INTERRUPT_INIT) { - kvm_cpu_synchronize_state(cs); - do_cpu_init(cpu); - } if (cs->interrupt_request & CPU_INTERRUPT_SIPI) { kvm_cpu_synchronize_state(cs); do_cpu_sipi(cpu); diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h index 4392ab4359..cac30fd381 100644 --- a/target-i386/kvm_i386.h +++ b/target-i386/kvm_i386.h @@ -14,6 +14,8 @@ #include "sysemu/kvm.h" bool kvm_allows_irq0_override(void); +void kvm_arch_reset_vcpu(X86CPU *cs); +void kvm_arch_do_init_vcpu(X86CPU *cs); int kvm_device_pci_assign(KVMState *s, PCIHostDeviceAddress *dev_addr, uint32_t flags, uint32_t *dev_id); diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 8c3f92c22b..3cf862ee60 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -409,11 +409,7 @@ static void switch_tss(CPUX86State *env, int tss_selector, for (i = 0; i < 6; i++) { load_seg_vm(env, i, new_segs[i]); } - /* in vm86, CPL is always 3 */ - cpu_x86_set_cpl(env, 3); } else { - /* CPL is set the RPL of CS */ - cpu_x86_set_cpl(env, new_segs[R_CS] & 3); /* first just selectors as the rest may trigger exceptions */ for (i = 0; i < 6; i++) { cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0); @@ -739,6 +735,12 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int, } } + /* interrupt gate clear IF mask */ + if ((type & 1) == 0) { + env->eflags &= ~IF_MASK; + } + env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); + if (new_stack) { if (env->eflags & VM_MASK) { cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0); @@ -757,14 +759,7 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); - cpu_x86_set_cpl(env, dpl); env->eip = offset; - - /* interrupt gate clear IF mask */ - if ((type & 1) == 0) { - env->eflags &= ~IF_MASK; - } - env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); } #ifdef TARGET_X86_64 @@ -911,6 +906,12 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, PUSHQ(esp, error_code); } + /* interrupt gate clear IF mask */ + if ((type & 1) == 0) { + env->eflags &= ~IF_MASK; + } + env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); + if (new_stack) { ss = 0 | dpl; cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); @@ -922,14 +923,7 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); - cpu_x86_set_cpl(env, dpl); env->eip = offset; - - /* interrupt gate clear IF mask */ - if ((type & 1) == 0) { - env->eflags &= ~IF_MASK; - } - env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); } #endif @@ -960,7 +954,8 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) code64 = env->hflags & HF_CS64_MASK; - cpu_x86_set_cpl(env, 0); + env->eflags &= ~env->fmask; + cpu_load_eflags(env, env->eflags, 0); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_P_MASK | @@ -972,8 +967,6 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK); - env->eflags &= ~env->fmask; - cpu_load_eflags(env, env->eflags, 0); if (code64) { env->eip = env->lstar; } else { @@ -982,7 +975,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) } else { env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend); - cpu_x86_set_cpl(env, 0); + env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | @@ -993,7 +986,6 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK); - env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); env->eip = (uint32_t)env->star; } } @@ -1014,6 +1006,9 @@ void helper_sysret(CPUX86State *env, int dflag) } selector = (env->star >> 48) & 0xffff; if (env->hflags & HF_LMA_MASK) { + cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK + | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | + NT_MASK); if (dflag == 2) { cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, 0, 0xffffffff, @@ -1035,11 +1030,8 @@ void helper_sysret(CPUX86State *env, int dflag) DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); - cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK - | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | - NT_MASK); - cpu_x86_set_cpl(env, 3); } else { + env->eflags |= IF_MASK; cpu_x86_load_seg_cache(env, R_CS, selector | 3, 0, 0xffffffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | @@ -1051,8 +1043,6 @@ void helper_sysret(CPUX86State *env, int dflag) DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); - env->eflags |= IF_MASK; - cpu_x86_set_cpl(env, 3); } } #endif @@ -1905,7 +1895,6 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); - cpu_x86_set_cpl(env, dpl); SET_ESP(sp, sp_mask); env->eip = offset; } @@ -2134,7 +2123,6 @@ static inline void helper_ret_protected(CPUX86State *env, int shift, get_seg_base(e1, e2), get_seg_limit(e1, e2), e2); - cpu_x86_set_cpl(env, rpl); sp = new_esp; #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { @@ -2185,7 +2173,6 @@ static inline void helper_ret_protected(CPUX86State *env, int shift, IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK); load_seg_vm(env, R_CS, new_cs & 0xffff); - cpu_x86_set_cpl(env, 3); load_seg_vm(env, R_SS, new_ss & 0xffff); load_seg_vm(env, R_ES, new_es & 0xffff); load_seg_vm(env, R_DS, new_ds & 0xffff); @@ -2238,7 +2225,6 @@ void helper_sysenter(CPUX86State *env) raise_exception_err(env, EXCP0D_GPF, 0); } env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); - cpu_x86_set_cpl(env, 0); #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { @@ -2274,7 +2260,6 @@ void helper_sysexit(CPUX86State *env, int dflag) if (env->sysenter_cs == 0 || cpl != 0) { raise_exception_err(env, EXCP0D_GPF, 0); } - cpu_x86_set_cpl(env, 3); #ifdef TARGET_X86_64 if (dflag == 2) { cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c index 35901c9e89..4841d53b24 100644 --- a/target-i386/smm_helper.c +++ b/target-i386/smm_helper.c @@ -163,6 +163,13 @@ void do_smm_enter(X86CPU *cpu) cpu_load_eflags(env, 0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); env->eip = 0x00008000; + cpu_x86_update_cr0(env, + env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | + CR0_PG_MASK)); + cpu_x86_update_cr4(env, 0); + env->dr[7] = 0x00000400; + CC_OP = CC_OP_EFLAGS; + cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, 0xffffffff, 0); cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, 0); @@ -170,13 +177,6 @@ void do_smm_enter(X86CPU *cpu) cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0); cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0); cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0); - - cpu_x86_update_cr0(env, - env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | - CR0_PG_MASK)); - cpu_x86_update_cr4(env, 0); - env->dr[7] = 0x00000400; - CC_OP = CC_OP_EFLAGS; } void helper_rsm(CPUX86State *env) @@ -191,16 +191,6 @@ void helper_rsm(CPUX86State *env) #ifdef TARGET_X86_64 cpu_load_efer(env, ldq_phys(cs->as, sm_state + 0x7ed0)); - for (i = 0; i < 6; i++) { - offset = 0x7e00 + i * 16; - cpu_x86_load_seg_cache(env, i, - lduw_phys(cs->as, sm_state + offset), - ldq_phys(cs->as, sm_state + offset + 8), - ldl_phys(cs->as, sm_state + offset + 4), - (lduw_phys(cs->as, sm_state + offset + 2) & - 0xf0ff) << 8); - } - env->gdt.base = ldq_phys(cs->as, sm_state + 0x7e68); env->gdt.limit = ldl_phys(cs->as, sm_state + 0x7e64); @@ -238,6 +228,16 @@ void helper_rsm(CPUX86State *env) cpu_x86_update_cr3(env, ldl_phys(cs->as, sm_state + 0x7f50)); cpu_x86_update_cr0(env, ldl_phys(cs->as, sm_state + 0x7f58)); + for (i = 0; i < 6; i++) { + offset = 0x7e00 + i * 16; + cpu_x86_load_seg_cache(env, i, + lduw_phys(cs->as, sm_state + offset), + ldq_phys(cs->as, sm_state + offset + 8), + ldl_phys(cs->as, sm_state + offset + 4), + (lduw_phys(cs->as, sm_state + offset + 2) & + 0xf0ff) << 8); + } + val = ldl_phys(cs->as, sm_state + 0x7efc); /* revision ID */ if (val & 0x20000) { env->smbase = ldl_phys(cs->as, sm_state + 0x7f00) & ~0x7fff; diff --git a/target-i386/svm_helper.c b/target-i386/svm_helper.c index aa17ecdece..846eaa5918 100644 --- a/target-i386/svm_helper.c +++ b/target-i386/svm_helper.c @@ -282,9 +282,6 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->vm_vmcb + offsetof(struct vmcb, save.dr7)); env->dr[6] = ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.dr6)); - cpu_x86_set_cpl(env, ldub_phys(cs->as, - env->vm_vmcb + offsetof(struct vmcb, - save.cpl))); /* FIXME: guest state consistency checks */ @@ -703,7 +700,8 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) cpu_load_eflags(env, ldq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.rflags)), - ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); + ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK | + VM_MASK)); CC_OP = CC_OP_EFLAGS; svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es), @@ -728,7 +726,6 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) env->vm_hsave + offsetof(struct vmcb, save.dr7)); /* other setups */ - cpu_x86_set_cpl(env, 0); stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code); stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), @@ -756,10 +753,6 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) from the page table indicated the host's CR3. If the PDPEs contain illegal state, the processor causes a shutdown. */ - /* Forces CR0.PE = 1, RFLAGS.VM = 0. */ - env->cr[0] |= CR0_PE_MASK; - env->eflags &= ~VM_MASK; - /* Disables all breakpoints in the host DR7 register. */ /* Checks the reloaded host state for consistency. */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 02625e31c2..032b0fdffc 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6708,41 +6708,63 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } bt_op: tcg_gen_andi_tl(cpu_T[1], cpu_T[1], (1 << (3 + ot)) - 1); + tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); switch(op) { case 0: - tcg_gen_shr_tl(cpu_cc_src, cpu_T[0], cpu_T[1]); - tcg_gen_movi_tl(cpu_cc_dst, 0); break; case 1: - tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; case 2: - tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); - tcg_gen_not_tl(cpu_tmp0, cpu_tmp0); - tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + tcg_gen_andc_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; default: case 3: - tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]); tcg_gen_movi_tl(cpu_tmp0, 1); tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]); tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; } - set_cc_op(s, CC_OP_SARB + ot); if (op != 0) { if (mod != 3) { gen_op_st_v(s, ot, cpu_T[0], cpu_A0); } else { gen_op_mov_reg_v(ot, rm, cpu_T[0]); } + } + + /* Delay all CC updates until after the store above. Note that + C is the result of the test, Z is unchanged, and the others + are all undefined. */ + switch (s->cc_op) { + case CC_OP_MULB ... CC_OP_MULQ: + case CC_OP_ADDB ... CC_OP_ADDQ: + case CC_OP_ADCB ... CC_OP_ADCQ: + case CC_OP_SUBB ... CC_OP_SUBQ: + case CC_OP_SBBB ... CC_OP_SBBQ: + case CC_OP_LOGICB ... CC_OP_LOGICQ: + case CC_OP_INCB ... CC_OP_INCQ: + case CC_OP_DECB ... CC_OP_DECQ: + case CC_OP_SHLB ... CC_OP_SHLQ: + case CC_OP_SARB ... CC_OP_SARQ: + case CC_OP_BMILGB ... CC_OP_BMILGQ: + /* Z was going to be computed from the non-zero status of CC_DST. + We can get that same Z value (and the new C value) by leaving + CC_DST alone, setting CC_SRC, and using a CC_OP_SAR of the + same width. */ tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4); - tcg_gen_movi_tl(cpu_cc_dst, 0); + set_cc_op(s, ((s->cc_op - CC_OP_MULB) & 3) + CC_OP_SARB); + break; + default: + /* Otherwise, generate EFLAGS and replace the C bit. */ + gen_compute_eflags(s); + tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, cpu_tmp4, + ctz32(CC_C), 1); + break; } break; case 0x1bc: /* bsf / tzcnt */ diff --git a/target-lm32/machine.c b/target-lm32/machine.c index 9e0919c254..8327c6d97c 100644 --- a/target-lm32/machine.c +++ b/target-lm32/machine.c @@ -5,8 +5,7 @@ static const VMStateDescription vmstate_env = { .name = "env", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, CPULM32State, 32), VMSTATE_UINT32(pc, CPULM32State), VMSTATE_UINT32(ie, CPULM32State), @@ -26,8 +25,7 @@ const VMStateDescription vmstate_lm32_cpu = { .name = "cpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_STRUCT(env, LM32CPU, 1, vmstate_env, CPULM32State), VMSTATE_END_OF_LIST() } diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 8e0481186a..0379f2be2c 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -96,6 +96,8 @@ static void mb_cpu_reset(CPUState *s) env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */ env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17); + env->sregs[SR_PC] = cpu->base_vectors; + #if defined(CONFIG_USER_ONLY) /* start in user mode with interrupts enabled. */ env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM; diff --git a/target-moxie/machine.c b/target-moxie/machine.c index 0f5992b6a0..da1a8572a8 100644 --- a/target-moxie/machine.c +++ b/target-moxie/machine.c @@ -5,8 +5,7 @@ const VMStateDescription vmstate_moxie_cpu = { .name = "cpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(flags, CPUMoxieState), VMSTATE_UINT32_ARRAY(gregs, CPUMoxieState, 16), VMSTATE_UINT32_ARRAY(sregs, CPUMoxieState, 256), diff --git a/target-openrisc/machine.c b/target-openrisc/machine.c index 6f864fe7b4..9f66a9cef2 100644 --- a/target-openrisc/machine.c +++ b/target-openrisc/machine.c @@ -24,7 +24,6 @@ static const VMStateDescription vmstate_env = { .name = "env", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(gpr, CPUOpenRISCState, 32), VMSTATE_UINT32(sr, CPUOpenRISCState), @@ -43,7 +42,6 @@ const VMStateDescription vmstate_openrisc_cpu = { .name = "cpu", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_CPU(), VMSTATE_STRUCT(env, OpenRISCCPU, 1, vmstate_env, CPUOpenRISCState), diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index d4983405a2..75ed5fa636 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -2042,9 +2042,6 @@ enum { PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */ }; -/* CPU should be reset next, restart from scratch afterwards */ -#define CPU_INTERRUPT_RESET CPU_INTERRUPT_TGT_INT_0 - /*****************************************************************************/ static inline target_ulong cpu_read_xer(CPUPPCState *env) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 4b81e5f253..8ff1777dcb 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -430,10 +430,6 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } -void kvm_arch_reset_vcpu(CPUState *cpu) -{ -} - static void kvm_sw_tlb_put(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index dfd83e8aef..c3082b73c5 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -152,6 +152,10 @@ static void s390_cpu_full_reset(CPUState *s) * after incrementing the cpu counter */ #if !defined(CONFIG_USER_ONLY) s->halted = 1; + + if (kvm_enabled()) { + kvm_s390_reset_vcpu(cpu); + } #endif tlb_flush(s, 1); } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index aad277af49..06454d6da5 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -359,11 +359,16 @@ void s390x_cpu_timer(void *opaque); int s390_virtio_hypercall(CPUS390XState *env); #ifdef CONFIG_KVM +void kvm_s390_reset_vcpu(S390CPU *cpu); 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_reset_vcpu(S390CPU *cpu) +{ +} + static inline void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code) { } diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index b7b0edc4f1..56179afece 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -117,47 +117,20 @@ int kvm_arch_init_vcpu(CPUState *cpu) return 0; } -void kvm_arch_reset_vcpu(CPUState *cpu) +void kvm_s390_reset_vcpu(S390CPU *cpu) { + CPUState *cs = CPU(cpu); + /* The initial reset call is needed here to reset in-kernel * vcpu data that we can't access directly from QEMU * (i.e. with older kernels which don't support sync_regs/ONE_REG). * Before this ioctl cpu_synchronize_state() is called in common kvm * code (kvm-all) */ - if (kvm_vcpu_ioctl(cpu, KVM_S390_INITIAL_RESET, NULL)) { + if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL)) { perror("Can't reset vcpu\n"); } } -static int kvm_set_one_reg(CPUState *cs, uint64_t id, void *source) -{ - struct kvm_one_reg reg; - int r; - - reg.id = id; - reg.addr = (uint64_t) source; - r = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); - if (r) { - trace_kvm_failed_reg_set(id, strerror(errno)); - } - return r; -} - -static int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target) -{ - struct kvm_one_reg reg; - int r; - - reg.id = id; - reg.addr = (uint64_t) target; - r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); - if (r) { - trace_kvm_failed_reg_get(id, strerror(errno)); - } - return r; -} - - int kvm_arch_put_registers(CPUState *cs, int level) { S390CPU *cpu = S390_CPU(cs); diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c index 0a580b65ea..77bb6d97de 100644 --- a/tcg/aarch64/tcg-target.c +++ b/tcg/aarch64/tcg-target.c @@ -63,40 +63,34 @@ static const int tcg_target_call_oarg_regs[1] = { # endif #endif -static inline void reloc_pc26(void *code_ptr, intptr_t target) +static inline void reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target) { - intptr_t offset = (target - (intptr_t)code_ptr) / 4; + ptrdiff_t offset = target - code_ptr; + assert(offset == sextract64(offset, 0, 26)); /* read instruction, mask away previous PC_REL26 parameter contents, set the proper offset, then write back the instruction. */ - uint32_t insn = *(uint32_t *)code_ptr; - insn = deposit32(insn, 0, 26, offset); - *(uint32_t *)code_ptr = insn; + *code_ptr = deposit32(*code_ptr, 0, 26, offset); } -static inline void reloc_pc19(void *code_ptr, intptr_t target) +static inline void reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target) { - intptr_t offset = (target - (intptr_t)code_ptr) / 4; - /* read instruction, mask away previous PC_REL19 parameter contents, - set the proper offset, then write back the instruction. */ - uint32_t insn = *(uint32_t *)code_ptr; - insn = deposit32(insn, 5, 19, offset); - *(uint32_t *)code_ptr = insn; + ptrdiff_t offset = target - code_ptr; + assert(offset == sextract64(offset, 0, 19)); + *code_ptr = deposit32(*code_ptr, 5, 19, offset); } -static inline void patch_reloc(uint8_t *code_ptr, int type, +static inline void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { - value += addend; - + assert(addend == 0); switch (type) { case R_AARCH64_JUMP26: case R_AARCH64_CALL26: - reloc_pc26(code_ptr, value); + reloc_pc26(code_ptr, (tcg_insn_unit *)value); break; case R_AARCH64_CONDBR19: - reloc_pc19(code_ptr, value); + reloc_pc19(code_ptr, (tcg_insn_unit *)value); break; - default: tcg_abort(); } @@ -794,15 +788,10 @@ static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg a, } } -static inline void tcg_out_goto(TCGContext *s, intptr_t target) +static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target) { - intptr_t offset = (target - (intptr_t)s->code_ptr) / 4; - - if (offset < -0x02000000 || offset >= 0x02000000) { - /* out of 26bit range */ - tcg_abort(); - } - + ptrdiff_t offset = target - s->code_ptr; + assert(offset == sextract64(offset, 0, 26)); tcg_out_insn(s, 3206, B, offset); } @@ -828,29 +817,23 @@ static inline void tcg_out_callr(TCGContext *s, TCGReg reg) tcg_out_insn(s, 3207, BLR, reg); } -static inline void tcg_out_call(TCGContext *s, intptr_t target) +static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target) { - intptr_t offset = (target - (intptr_t)s->code_ptr) / 4; - - if (offset < -0x02000000 || offset >= 0x02000000) { /* out of 26bit rng */ - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, target); - tcg_out_callr(s, TCG_REG_TMP); - } else { + ptrdiff_t offset = target - s->code_ptr; + if (offset == sextract64(offset, 0, 26)) { tcg_out_insn(s, 3206, BL, offset); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); + tcg_out_callr(s, TCG_REG_TMP); } } void aarch64_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr) { - intptr_t target = addr; - intptr_t offset = (target - (intptr_t)jmp_addr) / 4; + tcg_insn_unit *code_ptr = (tcg_insn_unit *)jmp_addr; + tcg_insn_unit *target = (tcg_insn_unit *)addr; - if (offset < -0x02000000 || offset >= 0x02000000) { - /* out of 26bit range */ - tcg_abort(); - } - - patch_reloc((uint8_t *)jmp_addr, R_AARCH64_JUMP26, target, 0); + reloc_pc26(code_ptr, target); flush_icache_range(jmp_addr, jmp_addr + 4); } @@ -862,7 +845,7 @@ static inline void tcg_out_goto_label(TCGContext *s, int label_index) tcg_out_reloc(s, s->code_ptr, R_AARCH64_JUMP26, label_index, 0); tcg_out_goto_noaddr(s); } else { - tcg_out_goto(s, l->u.value); + tcg_out_goto(s, l->u.value_ptr); } } @@ -884,9 +867,8 @@ static void tcg_out_brcond(TCGContext *s, TCGMemOp ext, TCGCond c, TCGArg a, tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, label, 0); offset = tcg_in32(s) >> 5; } else { - offset = l->u.value - (uintptr_t)s->code_ptr; - offset >>= 2; - assert(offset >= -0x40000 && offset < 0x40000); + offset = l->u.value_ptr - s->code_ptr; + assert(offset == sextract64(offset, 0, 19)); } if (need_cmp) { @@ -982,7 +964,7 @@ static inline void tcg_out_addsub2(TCGContext *s, int ext, TCGReg rl, /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, * int mmu_idx, uintptr_t ra) */ -static const void * const qemu_ld_helpers[16] = { +static void * const qemu_ld_helpers[16] = { [MO_UB] = helper_ret_ldub_mmu, [MO_LEUW] = helper_le_lduw_mmu, [MO_LEUL] = helper_le_ldul_mmu, @@ -995,7 +977,7 @@ static const void * const qemu_ld_helpers[16] = { /* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, * uintxx_t val, int mmu_idx, uintptr_t ra) */ -static const void * const qemu_st_helpers[16] = { +static void * const qemu_st_helpers[16] = { [MO_UB] = helper_ret_stb_mmu, [MO_LEUW] = helper_le_stw_mmu, [MO_LEUL] = helper_le_stl_mmu, @@ -1005,11 +987,11 @@ static const void * const qemu_st_helpers[16] = { [MO_BEQ] = helper_be_stq_mmu, }; -static inline void tcg_out_adr(TCGContext *s, TCGReg rd, uintptr_t addr) +static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target) { - addr -= (uintptr_t)s->code_ptr; - assert(addr == sextract64(addr, 0, 21)); - tcg_out_insn(s, 3406, ADR, rd, addr); + ptrdiff_t offset = tcg_pcrel_diff(s, target); + assert(offset == sextract64(offset, 0, 21)); + tcg_out_insn(s, 3406, ADR, rd, offset); } static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) @@ -1017,20 +999,20 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) TCGMemOp opc = lb->opc; TCGMemOp size = opc & MO_SIZE; - reloc_pc19(lb->label_ptr[0], (intptr_t)s->code_ptr); + reloc_pc19(lb->label_ptr[0], s->code_ptr); tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_X0, TCG_AREG0); tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X1, lb->addrlo_reg); tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, lb->mem_index); - tcg_out_adr(s, TCG_REG_X3, (intptr_t)lb->raddr); - tcg_out_call(s, (intptr_t)qemu_ld_helpers[opc & ~MO_SIGN]); + tcg_out_adr(s, TCG_REG_X3, lb->raddr); + tcg_out_call(s, qemu_ld_helpers[opc & ~MO_SIGN]); if (opc & MO_SIGN) { tcg_out_sxt(s, TCG_TYPE_I64, size, lb->datalo_reg, TCG_REG_X0); } else { tcg_out_mov(s, size == MO_64, lb->datalo_reg, TCG_REG_X0); } - tcg_out_goto(s, (intptr_t)lb->raddr); + tcg_out_goto(s, lb->raddr); } static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) @@ -1038,21 +1020,21 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) TCGMemOp opc = lb->opc; TCGMemOp size = opc & MO_SIZE; - reloc_pc19(lb->label_ptr[0], (intptr_t)s->code_ptr); + reloc_pc19(lb->label_ptr[0], s->code_ptr); tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_X0, TCG_AREG0); tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X1, lb->addrlo_reg); tcg_out_mov(s, size == MO_64, TCG_REG_X2, lb->datalo_reg); tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, lb->mem_index); - tcg_out_adr(s, TCG_REG_X4, (intptr_t)lb->raddr); - tcg_out_call(s, (intptr_t)qemu_st_helpers[opc]); - tcg_out_goto(s, (intptr_t)lb->raddr); + tcg_out_adr(s, TCG_REG_X4, lb->raddr); + tcg_out_call(s, qemu_st_helpers[opc]); + tcg_out_goto(s, lb->raddr); } static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc, TCGReg data_reg, TCGReg addr_reg, - int mem_index, - uint8_t *raddr, uint8_t *label_ptr) + int mem_index, tcg_insn_unit *raddr, + tcg_insn_unit *label_ptr) { TCGLabelQemuLdst *label = new_ldst_label(s); @@ -1070,7 +1052,8 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc, the slow path. Generated code returns the host addend in X1, clobbers X0,X2,X3,TMP. */ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp s_bits, - uint8_t **label_ptr, int mem_index, bool is_read) + tcg_insn_unit **label_ptr, int mem_index, + bool is_read) { TCGReg base = TCG_AREG0; int tlb_offset = is_read ? @@ -1218,7 +1201,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, { #ifdef CONFIG_SOFTMMU TCGMemOp s_bits = memop & MO_SIZE; - uint8_t *label_ptr; + tcg_insn_unit *label_ptr; tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 1); tcg_out_qemu_ld_direct(s, memop, data_reg, addr_reg, TCG_REG_X1); @@ -1235,7 +1218,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, { #ifdef CONFIG_SOFTMMU TCGMemOp s_bits = memop & MO_SIZE; - uint8_t *label_ptr; + tcg_insn_unit *label_ptr; tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 0); tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_REG_X1); @@ -1247,7 +1230,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, #endif /* CONFIG_SOFTMMU */ } -static uint8_t *tb_ret_addr; +static tcg_insn_unit *tb_ret_addr; static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1270,7 +1253,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_exit_tb: tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0); - tcg_out_goto(s, (intptr_t)tb_ret_addr); + tcg_out_goto(s, tb_ret_addr); break; case INDEX_op_goto_tb: @@ -1278,19 +1261,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, #error "USE_DIRECT_JUMP required for aarch64" #endif assert(s->tb_jmp_offset != NULL); /* consistency for USE_DIRECT_JUMP */ - s->tb_jmp_offset[a0] = s->code_ptr - s->code_buf; + s->tb_jmp_offset[a0] = tcg_current_code_size(s); /* actual branch destination will be patched by aarch64_tb_set_jmp_target later, beware retranslation. */ tcg_out_goto_noaddr(s); - s->tb_next_offset[a0] = s->code_ptr - s->code_buf; - break; - - case INDEX_op_call: - if (const_args[0]) { - tcg_out_call(s, a0); - } else { - tcg_out_callr(s, a0); - } + s->tb_next_offset[a0] = tcg_current_code_size(s); break; case INDEX_op_br: @@ -1613,13 +1588,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_insn(s, 3508, SMULH, TCG_TYPE_I64, a0, a1, a2); break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: - case INDEX_op_mov_i32: + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ case INDEX_op_movi_i64: - case INDEX_op_movi_i32: - /* Always implemented with tcg_out_mov/i, never with tcg_out_op. */ + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: - /* Opcode not implemented. */ tcg_abort(); } @@ -1629,15 +1603,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, static const TCGTargetOpDef aarch64_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "ri" } }, { INDEX_op_br, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_mov_i64, { "r", "r" } }, - - { INDEX_op_movi_i32, { "r" } }, - { INDEX_op_movi_i64, { "r" } }, - { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index a1d4322165..a32aea66fa 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -13,6 +13,7 @@ #ifndef TCG_TARGET_AARCH64 #define TCG_TARGET_AARCH64 1 +#define TCG_TARGET_INSN_UNIT_SIZE 4 #undef TCG_TARGET_STACK_GROWSUP typedef enum { diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 7535175f9c..538ca2aed0 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -115,36 +115,18 @@ static const int tcg_target_call_oarg_regs[2] = { #define TCG_REG_TMP TCG_REG_R12 -static inline void reloc_abs32(void *code_ptr, intptr_t target) +static inline void reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target) { - *(uint32_t *) code_ptr = target; + ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2; + *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff); } -static inline void reloc_pc24(void *code_ptr, intptr_t target) -{ - uint32_t offset = ((target - ((intptr_t)code_ptr + 8)) >> 2); - - *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & ~0xffffff) - | (offset & 0xffffff); -} - -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { - switch (type) { - case R_ARM_ABS32: - reloc_abs32(code_ptr, value); - break; - - case R_ARM_CALL: - case R_ARM_JUMP24: - default: - tcg_abort(); - - case R_ARM_PC24: - reloc_pc24(code_ptr, value); - break; - } + assert(type == R_ARM_PC24); + assert(addend == 0); + reloc_pc24(code_ptr, (tcg_insn_unit *)value); } #define TCG_CT_CONST_ARM 0x100 @@ -379,20 +361,18 @@ static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset) static inline void tcg_out_b_noaddr(TCGContext *s, int cond) { - /* We pay attention here to not modify the branch target by skipping - the corresponding bytes. This ensure that caches and memory are + /* We pay attention here to not modify the branch target by masking + the corresponding bytes. This ensure that caches and memory are kept coherent during retranslation. */ - s->code_ptr += 3; - tcg_out8(s, (cond << 4) | 0x0a); + tcg_out32(s, deposit32(*s->code_ptr, 24, 8, (cond << 4) | 0x0a)); } static inline void tcg_out_bl_noaddr(TCGContext *s, int cond) { - /* We pay attention here to not modify the branch target by skipping - the corresponding bytes. This ensure that caches and memory are + /* We pay attention here to not modify the branch target by masking + the corresponding bytes. This ensure that caches and memory are kept coherent during retranslation. */ - s->code_ptr += 3; - tcg_out8(s, (cond << 4) | 0x0b); + tcg_out32(s, deposit32(*s->code_ptr, 24, 8, (cond << 4) | 0x0b)); } static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset) @@ -1010,20 +990,21 @@ static inline void tcg_out_st8(TCGContext *s, int cond, * with the code buffer limited to 16MB we wouldn't need the long case. * But we also use it for the tail-call to the qemu_ld/st helpers, which does. */ -static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr) +static inline void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr) { - int32_t disp = addr - (tcg_target_long) s->code_ptr; + intptr_t addri = (intptr_t)addr; + ptrdiff_t disp = tcg_pcrel_diff(s, addr); - if ((addr & 1) == 0 && disp - 8 < 0x01fffffd && disp - 8 > -0x01fffffd) { + if ((addri & 1) == 0 && disp - 8 < 0x01fffffd && disp - 8 > -0x01fffffd) { tcg_out_b(s, cond, disp); return; } - tcg_out_movi32(s, cond, TCG_REG_TMP, addr); + tcg_out_movi32(s, cond, TCG_REG_TMP, addri); if (use_armv5t_instructions) { tcg_out_bx(s, cond, TCG_REG_TMP); } else { - if (addr & 1) { + if (addri & 1) { tcg_abort(); } tcg_out_mov_reg(s, cond, TCG_REG_PC, TCG_REG_TMP); @@ -1032,39 +1013,28 @@ static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr) /* The call case is mostly used for helpers - so it's not unreasonable * for them to be beyond branch range */ -static inline void tcg_out_call(TCGContext *s, uint32_t addr) +static void tcg_out_call(TCGContext *s, tcg_insn_unit *addr) { - int32_t val; + intptr_t addri = (intptr_t)addr; + ptrdiff_t disp = tcg_pcrel_diff(s, addr); - val = addr - (tcg_target_long) s->code_ptr; - if (val - 8 < 0x02000000 && val - 8 >= -0x02000000) { - if (addr & 1) { + if (disp - 8 < 0x02000000 && disp - 8 >= -0x02000000) { + if (addri & 1) { /* Use BLX if the target is in Thumb mode */ if (!use_armv5t_instructions) { tcg_abort(); } - tcg_out_blx_imm(s, val); + tcg_out_blx_imm(s, disp); } else { - tcg_out_bl(s, COND_AL, val); + tcg_out_bl(s, COND_AL, disp); } } else if (use_armv7_instructions) { - tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addr); + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri); tcg_out_blx(s, COND_AL, TCG_REG_TMP); } else { tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R14, TCG_REG_PC, 4); tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4); - tcg_out32(s, addr); - } -} - -static inline void tcg_out_callr(TCGContext *s, int cond, int arg) -{ - if (use_armv5t_instructions) { - tcg_out_blx(s, cond, arg); - } else { - tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R14, 0, - TCG_REG_PC, SHIFT_IMM_LSL(0)); - tcg_out_bx(s, cond, arg); + tcg_out32(s, addri); } } @@ -1073,9 +1043,9 @@ static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index) TCGLabel *l = &s->labels[label_index]; if (l->has_value) { - tcg_out_goto(s, cond, l->u.value); + tcg_out_goto(s, cond, l->u.value_ptr); } else { - tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337); + tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 0); tcg_out_b_noaddr(s, cond); } } @@ -1084,7 +1054,7 @@ static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index) /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, * int mmu_idx, uintptr_t ra) */ -static const void * const qemu_ld_helpers[16] = { +static void * const qemu_ld_helpers[16] = { [MO_UB] = helper_ret_ldub_mmu, [MO_SB] = helper_ret_ldsb_mmu, @@ -1104,7 +1074,7 @@ static const void * const qemu_ld_helpers[16] = { /* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, * uintxx_t val, int mmu_idx, uintptr_t ra) */ -static const void * const qemu_st_helpers[16] = { +static void * const qemu_st_helpers[16] = { [MO_UB] = helper_ret_stb_mmu, [MO_LEUW] = helper_le_stw_mmu, [MO_LEUL] = helper_le_stl_mmu, @@ -1256,7 +1226,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi, static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc, TCGReg datalo, TCGReg datahi, TCGReg addrlo, TCGReg addrhi, int mem_index, - uint8_t *raddr, uint8_t *label_ptr) + tcg_insn_unit *raddr, tcg_insn_unit *label_ptr) { TCGLabelQemuLdst *label = new_ldst_label(s); @@ -1275,9 +1245,9 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGReg argreg, datalo, datahi; TCGMemOp opc = lb->opc; - uintptr_t func; + void *func; - reloc_pc24(lb->label_ptr[0], (tcg_target_long)s->code_ptr); + reloc_pc24(lb->label_ptr[0], s->code_ptr); argreg = tcg_out_arg_reg32(s, TCG_REG_R0, TCG_AREG0); if (TARGET_LONG_BITS == 64) { @@ -1292,9 +1262,9 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) icache usage. For pre-armv6, use the signed helpers since we do not have a single insn sign-extend. */ if (use_armv6_instructions) { - func = (uintptr_t)qemu_ld_helpers[opc & ~MO_SIGN]; + func = qemu_ld_helpers[opc & ~MO_SIGN]; } else { - func = (uintptr_t)qemu_ld_helpers[opc]; + func = qemu_ld_helpers[opc]; if (opc & MO_SIGN) { opc = MO_UL; } @@ -1328,7 +1298,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) break; } - tcg_out_goto(s, COND_AL, (tcg_target_long)lb->raddr); + tcg_out_goto(s, COND_AL, lb->raddr); } static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) @@ -1336,7 +1306,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) TCGReg argreg, datalo, datahi; TCGMemOp opc = lb->opc; - reloc_pc24(lb->label_ptr[0], (tcg_target_long)s->code_ptr); + reloc_pc24(lb->label_ptr[0], s->code_ptr); argreg = TCG_REG_R0; argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0); @@ -1368,7 +1338,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) argreg = tcg_out_arg_reg32(s, argreg, TCG_REG_R14); /* Tail-call to the helper, which will return to the fast path. */ - tcg_out_goto(s, COND_AL, (uintptr_t)qemu_st_helpers[opc]); + tcg_out_goto(s, COND_AL, qemu_st_helpers[opc]); } #endif /* SOFTMMU */ @@ -1499,7 +1469,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64) #ifdef CONFIG_SOFTMMU int mem_index; TCGReg addend; - uint8_t *label_ptr; + tcg_insn_unit *label_ptr; #endif datalo = *args++; @@ -1628,7 +1598,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) #ifdef CONFIG_SOFTMMU int mem_index; TCGReg addend; - uint8_t *label_ptr; + tcg_insn_unit *label_ptr; #endif datalo = *args++; @@ -1660,7 +1630,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) #endif } -static uint8_t *tb_ret_addr; +static tcg_insn_unit *tb_ret_addr; static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args) @@ -1670,51 +1640,21 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_exit_tb: - if (use_armv7_instructions || check_fit_imm(args[0])) { - tcg_out_movi32(s, COND_AL, TCG_REG_R0, args[0]); - tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr); - } else { - uint8_t *ld_ptr = s->code_ptr; - tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_PC, 0); - tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr); - *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8; - tcg_out32(s, args[0]); - } + tcg_out_movi32(s, COND_AL, TCG_REG_R0, args[0]); + tcg_out_goto(s, COND_AL, tb_ret_addr); break; case INDEX_op_goto_tb: if (s->tb_jmp_offset) { /* Direct jump method */ -#if defined(USE_DIRECT_JUMP) - s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->tb_jmp_offset[args[0]] = tcg_current_code_size(s); tcg_out_b_noaddr(s, COND_AL); -#else - tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4); - s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; - tcg_out32(s, 0); -#endif } else { /* Indirect jump method */ -#if 1 - c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8); - if (c > 0xfff || c < -0xfff) { - tcg_out_movi32(s, COND_AL, TCG_REG_R0, - (tcg_target_long) (s->tb_next + args[0])); - tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, 0); - } else - tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, c); -#else - tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_PC, 0); - tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, 0); - tcg_out32(s, (tcg_target_long) (s->tb_next + args[0])); -#endif + intptr_t ptr = (intptr_t)(s->tb_next + args[0]); + tcg_out_movi32(s, COND_AL, TCG_REG_R0, ptr & ~0xfff); + tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, ptr & 0xfff); } - s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; - break; - case INDEX_op_call: - if (const_args[0]) - tcg_out_call(s, args[0]); - else - tcg_out_callr(s, COND_AL, args[0]); + s->tb_next_offset[args[0]] = tcg_current_code_size(s); break; case INDEX_op_br: tcg_out_goto_label(s, COND_AL, args[0]); @@ -1745,13 +1685,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); break; - case INDEX_op_mov_i32: - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, - args[0], 0, args[1], SHIFT_IMM_LSL(0)); - break; - case INDEX_op_movi_i32: - tcg_out_movi32(s, COND_AL, args[0], args[1]); - break; case INDEX_op_movcond_i32: /* Constraints mean that v2 is always in the same register as dest, * so we only need to do "if condition passed, move v1 to dest". @@ -1967,6 +1900,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_udiv(s, COND_AL, args[0], args[1], args[2]); break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: tcg_abort(); } @@ -1975,12 +1911,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "ri" } }, { INDEX_op_br, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_movi_i32, { "r" } }, - { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 1bc5dacec0..73f10c4424 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -26,6 +26,7 @@ #define TCG_TARGET_ARM 1 #undef TCG_TARGET_STACK_GROWSUP +#define TCG_TARGET_INSN_UNIT_SIZE 4 typedef enum { TCG_REG_R0 = 0, diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 34ece1f80b..a373073ff8 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -139,9 +139,9 @@ static bool have_bmi2; # define have_bmi2 0 #endif -static uint8_t *tb_ret_addr; +static tcg_insn_unit *tb_ret_addr; -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { value += addend; @@ -151,14 +151,14 @@ static void patch_reloc(uint8_t *code_ptr, int type, if (value != (int32_t)value) { tcg_abort(); } - *(uint32_t *)code_ptr = value; + tcg_patch32(code_ptr, value); break; case R_386_PC8: value -= (uintptr_t)code_ptr; if (value != (int8_t)value) { tcg_abort(); } - *(uint8_t *)code_ptr = value; + tcg_patch8(code_ptr, value); break; default: tcg_abort(); @@ -859,7 +859,7 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small) TCGLabel *l = &s->labels[label_index]; if (l->has_value) { - val = l->u.value - (intptr_t)s->code_ptr; + val = tcg_pcrel_diff(s, l->u.value_ptr); val1 = val - 2; if ((int8_t)val1 == val1) { if (opc == -1) { @@ -1099,26 +1099,26 @@ static void tcg_out_movcond64(TCGContext *s, TCGCond cond, TCGArg dest, } #endif -static void tcg_out_branch(TCGContext *s, int call, uintptr_t dest) +static void tcg_out_branch(TCGContext *s, int call, tcg_insn_unit *dest) { - intptr_t disp = dest - (intptr_t)s->code_ptr - 5; + intptr_t disp = tcg_pcrel_diff(s, dest) - 5; if (disp == (int32_t)disp) { tcg_out_opc(s, call ? OPC_CALL_Jz : OPC_JMP_long, 0, 0, 0); tcg_out32(s, disp); } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, dest); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, (uintptr_t)dest); tcg_out_modrm(s, OPC_GRP5, call ? EXT5_CALLN_Ev : EXT5_JMPN_Ev, TCG_REG_R10); } } -static inline void tcg_out_calli(TCGContext *s, uintptr_t dest) +static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *dest) { tcg_out_branch(s, 1, dest); } -static void tcg_out_jmp(TCGContext *s, uintptr_t dest) +static void tcg_out_jmp(TCGContext *s, tcg_insn_unit *dest) { tcg_out_branch(s, 0, dest); } @@ -1127,7 +1127,7 @@ static void tcg_out_jmp(TCGContext *s, uintptr_t dest) /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, * int mmu_idx, uintptr_t ra) */ -static const void * const qemu_ld_helpers[16] = { +static void * const qemu_ld_helpers[16] = { [MO_UB] = helper_ret_ldub_mmu, [MO_LEUW] = helper_le_lduw_mmu, [MO_LEUL] = helper_le_ldul_mmu, @@ -1140,7 +1140,7 @@ static const void * const qemu_ld_helpers[16] = { /* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, * uintxx_t val, int mmu_idx, uintptr_t ra) */ -static const void * const qemu_st_helpers[16] = { +static void * const qemu_st_helpers[16] = { [MO_UB] = helper_ret_stb_mmu, [MO_LEUW] = helper_le_stw_mmu, [MO_LEUL] = helper_le_stl_mmu, @@ -1173,7 +1173,7 @@ static const void * const qemu_st_helpers[16] = { static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, int mem_index, TCGMemOp s_bits, - uint8_t **label_ptr, int which) + tcg_insn_unit **label_ptr, int which) { const TCGReg r0 = TCG_REG_L0; const TCGReg r1 = TCG_REG_L1; @@ -1247,8 +1247,8 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi, static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc, TCGReg datalo, TCGReg datahi, TCGReg addrlo, TCGReg addrhi, - int mem_index, uint8_t *raddr, - uint8_t **label_ptr) + int mem_index, tcg_insn_unit *raddr, + tcg_insn_unit **label_ptr) { TCGLabelQemuLdst *label = new_ldst_label(s); @@ -1273,12 +1273,12 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { TCGMemOp opc = l->opc; TCGReg data_reg; - uint8_t **label_ptr = &l->label_ptr[0]; + tcg_insn_unit **label_ptr = &l->label_ptr[0]; /* resolve label address */ - *(uint32_t *)label_ptr[0] = (uint32_t)(s->code_ptr - label_ptr[0] - 4); + tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4); if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) { - *(uint32_t *)label_ptr[1] = (uint32_t)(s->code_ptr - label_ptr[1] - 4); + tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4); } if (TCG_TARGET_REG_BITS == 32) { @@ -1308,7 +1308,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) (uintptr_t)l->raddr); } - tcg_out_calli(s, (uintptr_t)qemu_ld_helpers[opc & ~MO_SIGN]); + tcg_out_call(s, qemu_ld_helpers[opc & ~MO_SIGN]); data_reg = l->datalo_reg; switch (opc & MO_SSIZE) { @@ -1346,7 +1346,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) } /* Jump to the code corresponding to next IR of qemu_st */ - tcg_out_jmp(s, (uintptr_t)l->raddr); + tcg_out_jmp(s, l->raddr); } /* @@ -1356,13 +1356,13 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) { TCGMemOp opc = l->opc; TCGMemOp s_bits = opc & MO_SIZE; - uint8_t **label_ptr = &l->label_ptr[0]; + tcg_insn_unit **label_ptr = &l->label_ptr[0]; TCGReg retaddr; /* resolve label address */ - *(uint32_t *)label_ptr[0] = (uint32_t)(s->code_ptr - label_ptr[0] - 4); + tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4); if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) { - *(uint32_t *)label_ptr[1] = (uint32_t)(s->code_ptr - label_ptr[1] - 4); + tcg_patch32(label_ptr[1], s->code_ptr - label_ptr[1] - 4); } if (TCG_TARGET_REG_BITS == 32) { @@ -1413,7 +1413,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) /* "Tail call" to the helper, with the return address back inline. */ tcg_out_push(s, retaddr); - tcg_out_jmp(s, (uintptr_t)qemu_st_helpers[opc]); + tcg_out_jmp(s, qemu_st_helpers[opc]); } #elif defined(__x86_64__) && defined(__linux__) # include <asm/prctl.h> @@ -1534,7 +1534,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64) #if defined(CONFIG_SOFTMMU) int mem_index; TCGMemOp s_bits; - uint8_t *label_ptr[2]; + tcg_insn_unit *label_ptr[2]; #endif datalo = *args++; @@ -1665,7 +1665,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) #if defined(CONFIG_SOFTMMU) int mem_index; TCGMemOp s_bits; - uint8_t *label_ptr[2]; + tcg_insn_unit *label_ptr[2]; #endif datalo = *args++; @@ -1731,35 +1731,24 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, switch(opc) { case INDEX_op_exit_tb: tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, args[0]); - tcg_out_jmp(s, (uintptr_t)tb_ret_addr); + tcg_out_jmp(s, tb_ret_addr); break; case INDEX_op_goto_tb: if (s->tb_jmp_offset) { /* direct jump method */ tcg_out8(s, OPC_JMP_long); /* jmp im */ - s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->tb_jmp_offset[args[0]] = tcg_current_code_size(s); tcg_out32(s, 0); } else { /* indirect jump method */ tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, -1, (intptr_t)(s->tb_next + args[0])); } - s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; - break; - case INDEX_op_call: - if (const_args[0]) { - tcg_out_calli(s, args[0]); - } else { - /* call *reg */ - tcg_out_modrm(s, OPC_GRP5, EXT5_CALLN_Ev, args[0]); - } + s->tb_next_offset[args[0]] = tcg_current_code_size(s); break; case INDEX_op_br: tcg_out_jxx(s, JCC_JMP, args[0], 0); break; - case INDEX_op_movi_i32: - tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); - break; OP_32_64(ld8u): /* Note that we can ignore REXW for the zero-extend to 64-bit. */ tcg_out_modrm_offset(s, OPC_MOVZBL, args[0], args[1], args[2]); @@ -2009,9 +1998,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_setcond2(s, args, const_args); break; #else /* TCG_TARGET_REG_BITS == 64 */ - case INDEX_op_movi_i64: - tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); - break; case INDEX_op_ld32s_i64: tcg_out_modrm_offset(s, OPC_MOVSLQ, args[0], args[1], args[2]); break; @@ -2068,6 +2054,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_mov_i64: + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ + case INDEX_op_movi_i64: + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: tcg_abort(); } @@ -2078,10 +2069,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "ri" } }, { INDEX_op_br, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_movi_i32, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, @@ -2135,8 +2123,6 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } }, { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } }, #else - { INDEX_op_mov_i64, { "r", "r" } }, - { INDEX_op_movi_i64, { "r" } }, { INDEX_op_ld8u_i64, { "r", "r" } }, { INDEX_op_ld8s_i64, { "r", "r" } }, { INDEX_op_ld16u_i64, { "r", "r" } }, diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index dbeb16d3ac..6c94e5cde0 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -24,6 +24,8 @@ #ifndef TCG_TARGET_I386 #define TCG_TARGET_I386 1 +#define TCG_TARGET_INSN_UNIT_SIZE 1 + #ifdef __x86_64__ # define TCG_TARGET_REG_BITS 64 # define TCG_TARGET_NB_REGS 16 diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 1f523d6466..6bc9924641 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -692,112 +692,32 @@ static inline uint64_t tcg_opc_x4(int qp, uint64_t opc, int b1, uint64_t imm) /* - * Relocations + * Relocations - Note that we never encode branches elsewhere than slot 2. */ -static inline void reloc_pcrel21b(void *pc, intptr_t target) +static void reloc_pcrel21b_slot2(tcg_insn_unit *pc, tcg_insn_unit *target) { - uint64_t imm; - int64_t disp; - int slot; - - slot = (intptr_t)pc & 3; - pc = (void *)((intptr_t)pc & ~3); - - disp = target - (intptr_t)pc; - imm = (uint64_t) disp >> 4; - - switch(slot) { - case 0: - *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 8) & 0xfffffdc00003ffffull) - | ((imm & 0x100000) << 21) /* s */ - | ((imm & 0x0fffff) << 18); /* imm20b */ - break; - case 1: - *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xfffffffffffb8000ull) - | ((imm & 0x100000) >> 2) /* s */ - | ((imm & 0x0fffe0) >> 5); /* imm20b */ - *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 0) & 0x07ffffffffffffffull) - | ((imm & 0x00001f) << 59); /* imm20b */ - break; - case 2: - *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xf700000fffffffffull) - | ((imm & 0x100000) << 39) /* s */ - | ((imm & 0x0fffff) << 36); /* imm20b */ - break; - } -} + uint64_t imm = target - pc; -static inline uint64_t get_reloc_pcrel21b (void *pc) -{ - int64_t low, high; - int slot; - - slot = (tcg_target_long) pc & 3; - pc = (void *)((tcg_target_long) pc & ~3); - - low = (*(uint64_t *)(pc + 0)); - high = (*(uint64_t *)(pc + 8)); - - switch(slot) { - case 0: - return ((low >> 21) & 0x100000) + /* s */ - ((low >> 18) & 0x0fffff); /* imm20b */ - case 1: - return ((high << 2) & 0x100000) + /* s */ - ((high << 5) & 0x0fffe0) + /* imm20b */ - ((low >> 59) & 0x00001f); /* imm20b */ - case 2: - return ((high >> 39) & 0x100000) + /* s */ - ((high >> 36) & 0x0fffff); /* imm20b */ - default: - tcg_abort(); - } + pc->hi = (pc->hi & 0xf700000fffffffffull) + | ((imm & 0x100000) << 39) /* s */ + | ((imm & 0x0fffff) << 36); /* imm20b */ } -static inline void reloc_pcrel60b(void *pc, intptr_t target) +static uint64_t get_reloc_pcrel21b_slot2(tcg_insn_unit *pc) { - int64_t disp; - uint64_t imm; - - disp = target - (intptr_t)pc; - imm = (uint64_t) disp >> 4; + int64_t high = pc->hi; - *(uint64_t *)(pc + 8) = (*(uint64_t *)(pc + 8) & 0xf700000fff800000ull) - | (imm & 0x0800000000000000ull) /* s */ - | ((imm & 0x07fffff000000000ull) >> 36) /* imm39 */ - | ((imm & 0x00000000000fffffull) << 36); /* imm20b */ - *(uint64_t *)(pc + 0) = (*(uint64_t *)(pc + 0) & 0x00003fffffffffffull) - | ((imm & 0x0000000ffff00000ull) << 28); /* imm39 */ + return ((high >> 39) & 0x100000) + /* s */ + ((high >> 36) & 0x0fffff); /* imm20b */ } -static inline uint64_t get_reloc_pcrel60b (void *pc) -{ - int64_t low, high; - - low = (*(uint64_t *)(pc + 0)); - high = (*(uint64_t *)(pc + 8)); - - return ((high) & 0x0800000000000000ull) + /* s */ - ((high >> 36) & 0x00000000000fffffull) + /* imm20b */ - ((high << 36) & 0x07fffff000000000ull) + /* imm39 */ - ((low >> 28) & 0x0000000ffff00000ull); /* imm39 */ -} - - -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { - value += addend; - switch (type) { - case R_IA64_PCREL21B: - reloc_pcrel21b(code_ptr, value); - break; - case R_IA64_PCREL60B: - reloc_pcrel60b(code_ptr, value); - default: - tcg_abort(); - } + assert(addend == 0); + assert(type == R_IA64_PCREL21B); + reloc_pcrel21b_slot2(code_ptr, (tcg_insn_unit *)value); } /* @@ -861,7 +781,7 @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type, * Code generation */ -static uint8_t *tb_ret_addr; +static tcg_insn_unit *tb_ret_addr; static inline void tcg_out_bundle(TCGContext *s, int template, uint64_t slot0, uint64_t slot1, @@ -872,9 +792,10 @@ static inline void tcg_out_bundle(TCGContext *s, int template, slot1 &= 0x1ffffffffffull; /* 41 bits */ slot2 &= 0x1ffffffffffull; /* 41 bits */ - *(uint64_t *)(s->code_ptr + 0) = (slot1 << 46) | (slot0 << 5) | template; - *(uint64_t *)(s->code_ptr + 8) = (slot2 << 23) | (slot1 >> 18); - s->code_ptr += 16; + *s->code_ptr++ = (tcg_insn_unit){ + (slot1 << 46) | (slot0 << 5) | template, + (slot2 << 23) | (slot1 >> 18) + }; } static inline uint64_t tcg_opc_mov_a(int qp, TCGReg dst, TCGReg src) @@ -909,33 +830,34 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, static void tcg_out_br(TCGContext *s, int label_index) { TCGLabel *l = &s->labels[label_index]; + uint64_t imm; /* We pay attention here to not modify the branch target by reading the existing value and using it again. This ensure that caches and memory are kept coherent during retranslation. */ - tcg_out_bundle(s, mmB, - INSN_NOP_M, - INSN_NOP_M, - tcg_opc_b1 (TCG_REG_P0, OPC_BR_SPTK_MANY_B1, - get_reloc_pcrel21b(s->code_ptr + 2))); - if (l->has_value) { - reloc_pcrel21b((s->code_ptr - 16) + 2, l->u.value); + imm = l->u.value_ptr - s->code_ptr; } else { - tcg_out_reloc(s, (s->code_ptr - 16) + 2, - R_IA64_PCREL21B, label_index, 0); + imm = get_reloc_pcrel21b_slot2(s->code_ptr); + tcg_out_reloc(s, s->code_ptr, R_IA64_PCREL21B, label_index, 0); } + + tcg_out_bundle(s, mmB, + INSN_NOP_M, + INSN_NOP_M, + tcg_opc_b1(TCG_REG_P0, OPC_BR_SPTK_MANY_B1, imm)); } -static inline void tcg_out_calli(TCGContext *s, uintptr_t addr) +static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *desc) { + uintptr_t func = desc->lo, gp = desc->hi, disp; + /* Look through the function descriptor. */ - uintptr_t disp, *desc = (uintptr_t *)addr; tcg_out_bundle(s, mlx, INSN_NOP_M, - tcg_opc_l2 (desc[1]), - tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2, TCG_REG_R1, desc[1])); - disp = (desc[0] - (uintptr_t)s->code_ptr) >> 4; + tcg_opc_l2 (gp), + tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2, TCG_REG_R1, gp)); + disp = (tcg_insn_unit *)func - s->code_ptr; tcg_out_bundle(s, mLX, INSN_NOP_M, tcg_opc_l4 (disp), @@ -943,23 +865,8 @@ static inline void tcg_out_calli(TCGContext *s, uintptr_t addr) TCG_REG_B0, disp)); } -static inline void tcg_out_callr(TCGContext *s, TCGReg addr) -{ - tcg_out_bundle(s, MmI, - tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1, TCG_REG_R2, addr), - tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R3, 8, addr), - tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21, - TCG_REG_B6, TCG_REG_R2, 0)); - tcg_out_bundle(s, mmB, - tcg_opc_m1 (TCG_REG_P0, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R3), - INSN_NOP_M, - tcg_opc_b5 (TCG_REG_P0, OPC_BR_CALL_SPTK_MANY_B5, - TCG_REG_B0, TCG_REG_B6)); -} - static void tcg_out_exit_tb(TCGContext *s, tcg_target_long arg) { - int64_t disp; uint64_t imm, opc1; /* At least arg == 0 is a common operation. */ @@ -970,8 +877,7 @@ static void tcg_out_exit_tb(TCGContext *s, tcg_target_long arg) opc1 = INSN_NOP_M; } - disp = tb_ret_addr - s->code_ptr; - imm = (uint64_t)disp >> 4; + imm = tb_ret_addr - s->code_ptr; tcg_out_bundle(s, mLX, opc1, @@ -1000,7 +906,7 @@ static inline void tcg_out_goto_tb(TCGContext *s, TCGArg arg) tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6)); } - s->tb_next_offset[arg] = s->code_ptr - s->code_buf; + s->tb_next_offset[arg] = tcg_current_code_size(s); } static inline void tcg_out_jmp(TCGContext *s, TCGArg addr) @@ -1521,19 +1427,22 @@ static inline void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, TCGReg arg2, int label_index, int cmp4) { TCGLabel *l = &s->labels[label_index]; + uint64_t imm; - tcg_out_bundle(s, miB, - INSN_NOP_M, - tcg_opc_cmp_a(TCG_REG_P0, cond, arg1, arg2, cmp4), - tcg_opc_b1(TCG_REG_P6, OPC_BR_DPTK_FEW_B1, - get_reloc_pcrel21b(s->code_ptr + 2))); - + /* We pay attention here to not modify the branch target by reading + the existing value and using it again. This ensure that caches and + memory are kept coherent during retranslation. */ if (l->has_value) { - reloc_pcrel21b((s->code_ptr - 16) + 2, l->u.value); + imm = l->u.value_ptr - s->code_ptr; } else { - tcg_out_reloc(s, (s->code_ptr - 16) + 2, - R_IA64_PCREL21B, label_index, 0); + imm = get_reloc_pcrel21b_slot2(s->code_ptr); + tcg_out_reloc(s, s->code_ptr, R_IA64_PCREL21B, label_index, 0); } + + tcg_out_bundle(s, miB, + INSN_NOP_M, + tcg_opc_cmp_a(TCG_REG_P0, cond, arg1, arg2, cmp4), + tcg_opc_b1(TCG_REG_P6, OPC_BR_DPTK_FEW_B1, imm)); } static inline void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGArg ret, @@ -1646,7 +1555,7 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGReg addr_reg, typedef struct TCGLabelQemuLdst { bool is_ld; TCGMemOp size; - uint8_t *label_ptr; /* label pointers to be updated */ + tcg_insn_unit *label_ptr; /* label pointers to be updated */ } TCGLabelQemuLdst; typedef struct TCGBackendData { @@ -1660,7 +1569,7 @@ static inline void tcg_out_tb_init(TCGContext *s) } static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc, - uint8_t *label_ptr) + tcg_insn_unit *label_ptr) { TCGBackendData *be = s->be; TCGLabelQemuLdst *l = &be->ldst_labels[be->nb_ldst_labels++]; @@ -1683,43 +1592,44 @@ static void tcg_out_tb_finalize(TCGContext *s) helper_le_ldul_mmu, helper_le_ldq_mmu, }; - uintptr_t thunks[8] = { }; + tcg_insn_unit *thunks[8] = { }; TCGBackendData *be = s->be; size_t i, n = be->nb_ldst_labels; for (i = 0; i < n; i++) { TCGLabelQemuLdst *l = &be->ldst_labels[i]; long x = l->is_ld * 4 + l->size; - uintptr_t dest = thunks[x]; + tcg_insn_unit *dest = thunks[x]; /* The out-of-line thunks are all the same; load the return address from B0, load the GP, and branch to the code. Note that we are always post-call, so the register window has rolled, so we're using incomming parameter register numbers, not outgoing. */ - if (dest == 0) { - uintptr_t disp, *desc = (uintptr_t *)helpers[x]; + if (dest == NULL) { + uintptr_t *desc = (uintptr_t *)helpers[x]; + uintptr_t func = desc[0], gp = desc[1], disp; - thunks[x] = dest = (uintptr_t)s->code_ptr; + thunks[x] = dest = s->code_ptr; tcg_out_bundle(s, mlx, INSN_NOP_M, - tcg_opc_l2 (desc[1]), + tcg_opc_l2 (gp), tcg_opc_x2 (TCG_REG_P0, OPC_MOVL_X2, - TCG_REG_R1, desc[1])); + TCG_REG_R1, gp)); tcg_out_bundle(s, mii, INSN_NOP_M, INSN_NOP_I, tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22, l->is_ld ? TCG_REG_R35 : TCG_REG_R36, TCG_REG_B0)); - disp = (desc[0] - (uintptr_t)s->code_ptr) >> 4; + disp = (tcg_insn_unit *)func - s->code_ptr; tcg_out_bundle(s, mLX, INSN_NOP_M, tcg_opc_l3 (disp), tcg_opc_x3 (TCG_REG_P0, OPC_BRL_SPTK_MANY_X3, disp)); } - reloc_pcrel21b(l->label_ptr, dest); + reloc_pcrel21b_slot2(l->label_ptr, dest); } } @@ -1731,7 +1641,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args) int addr_reg, data_reg, mem_index; TCGMemOp opc, s_bits; uint64_t fin1, fin2; - uint8_t *label_ptr; + tcg_insn_unit *label_ptr; data_reg = args[0]; addr_reg = args[1]; @@ -1765,13 +1675,13 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args) tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R2, TCG_REG_R2, TCG_REG_R57), tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R58, mem_index)); - label_ptr = s->code_ptr + 2; + label_ptr = s->code_ptr; tcg_out_bundle(s, miB, tcg_opc_m1 (TCG_REG_P6, opc_ld_m1[s_bits], TCG_REG_R8, TCG_REG_R2), INSN_NOP_I, tcg_opc_b3 (TCG_REG_P7, OPC_BR_CALL_SPNT_FEW_B3, TCG_REG_B0, - get_reloc_pcrel21b(label_ptr))); + get_reloc_pcrel21b_slot2(label_ptr))); add_qemu_ldst_label(s, 1, opc, label_ptr); @@ -1792,7 +1702,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args) int mem_index; uint64_t pre1, pre2; TCGMemOp opc, s_bits; - uint8_t *label_ptr; + tcg_insn_unit *label_ptr; data_reg = args[0]; addr_reg = args[1]; @@ -1827,13 +1737,13 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args) tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R2, TCG_REG_R2, TCG_REG_R57), tcg_opc_movi_a(TCG_REG_P7, TCG_REG_R59, mem_index)); - label_ptr = s->code_ptr + 2; + label_ptr = s->code_ptr; tcg_out_bundle(s, miB, tcg_opc_m4 (TCG_REG_P6, opc_st_m4[s_bits], TCG_REG_R58, TCG_REG_R2), INSN_NOP_I, tcg_opc_b3 (TCG_REG_P7, OPC_BR_CALL_SPNT_FEW_B3, TCG_REG_B0, - get_reloc_pcrel21b(label_ptr))); + get_reloc_pcrel21b_slot2(label_ptr))); add_qemu_ldst_label(s, 0, opc, label_ptr); } @@ -2085,24 +1995,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_br: tcg_out_br(s, args[0]); break; - case INDEX_op_call: - if (likely(const_args[0])) { - tcg_out_calli(s, args[0]); - } else { - tcg_out_callr(s, args[0]); - } - break; case INDEX_op_goto_tb: tcg_out_goto_tb(s, args[0]); break; - case INDEX_op_movi_i32: - tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); - break; - case INDEX_op_movi_i64: - tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); - break; - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: tcg_out_ld_rel(s, OPC_LD1_M1, args[0], args[1], args[2]); @@ -2312,6 +2208,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_qemu_st(s, args); break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_mov_i64: + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ + case INDEX_op_movi_i64: + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: tcg_abort(); } @@ -2319,13 +2220,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_br, { } }, - { INDEX_op_call, { "ri" } }, { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_movi_i32, { "r" } }, - { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, @@ -2367,9 +2264,6 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rI", "rI" } }, - { INDEX_op_mov_i64, { "r", "r" } }, - { INDEX_op_movi_i64, { "r" } }, - { INDEX_op_ld8u_i64, { "r", "r" } }, { INDEX_op_ld8s_i64, { "r", "r" } }, { INDEX_op_ld16u_i64, { "r", "r" } }, @@ -2442,8 +2336,11 @@ static void tcg_target_qemu_prologue(TCGContext *s) CPU_TEMP_BUF_NLONGS * sizeof(long)); /* First emit adhoc function descriptor */ - *(uint64_t *)(s->code_ptr) = (uint64_t)s->code_ptr + 16; /* entry point */ - s->code_ptr += 16; /* skip GP */ + *s->code_ptr = (tcg_insn_unit){ + (uint64_t)(s->code_ptr + 1), /* entry point */ + 0 /* skip gp */ + }; + s->code_ptr++; /* prologue */ tcg_out_bundle(s, miI, diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index d834beb323..3a59b50349 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -25,6 +25,12 @@ #ifndef TCG_TARGET_IA64 #define TCG_TARGET_IA64 1 +#define TCG_TARGET_INSN_UNIT_SIZE 16 +typedef struct { + uint64_t lo __attribute__((aligned(16))); + uint64_t hi; +} tcg_insn_unit; + /* We only map the first 64 registers */ #define TCG_TARGET_NB_REGS 64 typedef enum { diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 37241b224b..0ae495c586 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -108,83 +108,38 @@ static const TCGReg tcg_target_call_oarg_regs[2] = { TCG_REG_V1 }; -static uint8_t *tb_ret_addr; +static tcg_insn_unit *tb_ret_addr; -static inline uint32_t reloc_lo16_val(void *pc, intptr_t target) +static inline uint32_t reloc_pc16_val(tcg_insn_unit *pc, tcg_insn_unit *target) { - return target & 0xffff; + /* Let the compiler perform the right-shift as part of the arithmetic. */ + ptrdiff_t disp = target - (pc + 1); + assert(disp == (int16_t)disp); + return disp & 0xffff; } -static inline void reloc_lo16(void *pc, intptr_t target) +static inline void reloc_pc16(tcg_insn_unit *pc, tcg_insn_unit *target) { - *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) - | reloc_lo16_val(pc, target); + *pc = deposit32(*pc, 0, 16, reloc_pc16_val(pc, target)); } -static inline uint32_t reloc_hi16_val(void *pc, intptr_t target) +static inline uint32_t reloc_26_val(tcg_insn_unit *pc, tcg_insn_unit *target) { - return (target >> 16) & 0xffff; + assert((((uintptr_t)pc ^ (uintptr_t)target) & 0xf0000000) == 0); + return ((uintptr_t)target >> 2) & 0x3ffffff; } -static inline void reloc_hi16(void *pc, intptr_t target) +static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target) { - *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) - | reloc_hi16_val(pc, target); + *pc = deposit32(*pc, 0, 26, reloc_26_val(pc, target)); } -static inline uint32_t reloc_pc16_val(void *pc, intptr_t target) -{ - int32_t disp; - - disp = target - (intptr_t)pc - 4; - if (disp != (disp << 14) >> 14) { - tcg_abort (); - } - - return (disp >> 2) & 0xffff; -} - -static inline void reloc_pc16 (void *pc, tcg_target_long target) -{ - *(uint32_t *) pc = (*(uint32_t *) pc & ~0xffff) - | reloc_pc16_val(pc, target); -} - -static inline uint32_t reloc_26_val (void *pc, tcg_target_long target) -{ - if ((((tcg_target_long)pc + 4) & 0xf0000000) != (target & 0xf0000000)) { - tcg_abort (); - } - - return (target >> 2) & 0x3ffffff; -} - -static inline void reloc_pc26(void *pc, intptr_t target) -{ - *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3ffffff) - | reloc_26_val(pc, target); -} - -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { - value += addend; - switch(type) { - case R_MIPS_LO16: - reloc_lo16(code_ptr, value); - break; - case R_MIPS_HI16: - reloc_hi16(code_ptr, value); - break; - case R_MIPS_PC16: - reloc_pc16(code_ptr, value); - break; - case R_MIPS_26: - reloc_pc26(code_ptr, value); - break; - default: - tcg_abort(); - } + assert(type == R_MIPS_PC16); + assert(addend == 0); + reloc_pc16(code_ptr, (tcg_insn_unit *)value); } /* parse target specific constraints */ @@ -198,11 +153,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) ct->ct |= TCG_CT_REG; tcg_regset_set(ct->u.regs, 0xffffffff); break; - case 'C': - ct->ct |= TCG_CT_REG; - tcg_regset_clear(ct->u.regs); - tcg_regset_set_reg(ct->u.regs, TCG_REG_T9); - break; case 'L': /* qemu_ld output arg constraint */ ct->ct |= TCG_CT_REG; tcg_regset_set(ct->u.regs, 0xffffffff); @@ -374,7 +324,7 @@ static inline void tcg_out_opc_br(TCGContext *s, int opc, /* We pay attention here to not modify the branch target by reading the existing value and using it again. This ensure that caches and memory are kept coherent during retranslation. */ - uint16_t offset = (uint16_t)(*(uint32_t *) s->code_ptr); + uint16_t offset = (uint16_t)*s->code_ptr; tcg_out_opc_imm(s, opc, rt, rs, offset); } @@ -663,9 +613,9 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGArg arg1, break; } if (l->has_value) { - reloc_pc16(s->code_ptr - 4, l->u.value); + reloc_pc16(s->code_ptr - 1, l->u.value_ptr); } else { - tcg_out_reloc(s, s->code_ptr - 4, R_MIPS_PC16, label_index, 0); + tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, label_index, 0); } tcg_out_nop(s); } @@ -676,7 +626,7 @@ static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGArg arg1, TCGArg arg2, TCGArg arg3, TCGArg arg4, int label_index) { - void *label_ptr; + tcg_insn_unit *label_ptr; switch(cond) { case TCG_COND_NE: @@ -733,7 +683,7 @@ static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGArg arg1, tcg_abort(); } - reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr); + reloc_pc16(label_ptr, s->code_ptr); } static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, @@ -945,12 +895,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, { TCGReg addr_regl, data_regl, data_regh, data_reg1, data_reg2; #if defined(CONFIG_SOFTMMU) - void *label1_ptr, *label2_ptr; + tcg_insn_unit *label1_ptr, *label2_ptr; int arg_num; int mem_index, s_bits; int addr_meml; # if TARGET_LONG_BITS == 64 - uint8_t *label3_ptr; + tcg_insn_unit *label3_ptr; TCGReg addr_regh; int addr_memh; # endif @@ -1011,7 +961,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT); tcg_out_nop(s); - reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); + reloc_pc16(label3_ptr, s->code_ptr); # else label1_ptr = s->code_ptr; tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT); @@ -1060,7 +1010,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, tcg_out_nop(s); /* label1: fast path */ - reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); + reloc_pc16(label1_ptr, s->code_ptr); tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, offsetof(CPUArchState, tlb_table[mem_index][0].addend)); @@ -1121,7 +1071,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, } #if defined(CONFIG_SOFTMMU) - reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr); + reloc_pc16(label2_ptr, s->code_ptr); #endif } @@ -1130,14 +1080,14 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, { TCGReg addr_regl, data_regl, data_regh, data_reg1, data_reg2; #if defined(CONFIG_SOFTMMU) - uint8_t *label1_ptr, *label2_ptr; + tcg_insn_unit *label1_ptr, *label2_ptr; int arg_num; int mem_index, s_bits; int addr_meml; #endif #if TARGET_LONG_BITS == 64 # if defined(CONFIG_SOFTMMU) - uint8_t *label3_ptr; + tcg_insn_unit *label3_ptr; TCGReg addr_regh; int addr_memh; # endif @@ -1200,7 +1150,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT); tcg_out_nop(s); - reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); + reloc_pc16(label3_ptr, s->code_ptr); # else label1_ptr = s->code_ptr; tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT); @@ -1241,7 +1191,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, tcg_out_nop(s); /* label1: fast path */ - reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr); + reloc_pc16(label1_ptr, s->code_ptr); tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, offsetof(CPUArchState, tlb_table[mem_index][0].addend)); @@ -1293,17 +1243,24 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, } #if defined(CONFIG_SOFTMMU) - reloc_pc16(label2_ptr, (tcg_target_long) s->code_ptr); + reloc_pc16(label2_ptr, s->code_ptr); #endif } +static void tcg_out_call(TCGContext *s, tcg_insn_unit *target) +{ + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T9, (intptr_t)target); + tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); + tcg_out_nop(s); +} + static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args) { switch(opc) { case INDEX_op_exit_tb: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_V0, args[0]); - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, (tcg_target_long)tb_ret_addr); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (uintptr_t)tb_ret_addr); tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0); tcg_out_nop(s); break; @@ -1313,28 +1270,18 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_abort(); } else { /* indirect jump method */ - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (tcg_target_long)(s->tb_next + args[0])); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, + (uintptr_t)(s->tb_next + args[0])); tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_AT, TCG_REG_AT, 0); tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0); } tcg_out_nop(s); - s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; - break; - case INDEX_op_call: - tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0); - tcg_out_nop(s); + s->tb_next_offset[args[0]] = tcg_current_code_size(s); break; case INDEX_op_br: tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]); break; - case INDEX_op_mov_i32: - tcg_out_mov(s, TCG_TYPE_I32, args[0], args[1]); - break; - case INDEX_op_movi_i32: - tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); - break; - case INDEX_op_ld8u_i32: tcg_out_ldst(s, OPC_LBU, args[0], args[1], args[2]); break; @@ -1582,6 +1529,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_qemu_st(s, args, 3); break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: tcg_abort(); } @@ -1590,11 +1540,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "C" } }, { INDEX_op_br, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_movi_i32, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 9576db514d..c6d2267d77 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -26,6 +26,7 @@ #ifndef TCG_TARGET_MIPS #define TCG_TARGET_MIPS 1 +#define TCG_TARGET_INSN_UNIT_SIZE 4 #define TCG_TARGET_NB_REGS 32 typedef enum { diff --git a/tcg/optimize.c b/tcg/optimize.c index 0302f4f99a..3a504a1961 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -513,12 +513,8 @@ static bool swap_commutative2(TCGArg *p1, TCGArg *p2) static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args, TCGOpDef *tcg_op_defs) { - int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args; - tcg_target_ulong mask, affected; - TCGOpcode op; - const TCGOpDef *def; + int nb_ops, op_index, nb_temps, nb_globals; TCGArg *gen_args; - TCGArg tmp; /* Array VALS has an element for each temp. If this temp holds a constant then its value is kept in VALS' element. @@ -532,22 +528,27 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, nb_ops = tcg_opc_ptr - s->gen_opc_buf; gen_args = args; for (op_index = 0; op_index < nb_ops; op_index++) { - op = s->gen_opc_buf[op_index]; - def = &tcg_op_defs[op]; - /* Do copy propagation */ + TCGOpcode op = s->gen_opc_buf[op_index]; + const TCGOpDef *def = &tcg_op_defs[op]; + tcg_target_ulong mask, affected; + int nb_oargs, nb_iargs, nb_args, i; + TCGArg tmp; + if (op == INDEX_op_call) { - int nb_oargs = args[0] >> 16; - int nb_iargs = args[0] & 0xffff; - for (i = nb_oargs + 1; i < nb_oargs + nb_iargs + 1; i++) { - if (temps[args[i]].state == TCG_TEMP_COPY) { - args[i] = find_better_copy(s, args[i]); - } - } + *gen_args++ = tmp = *args++; + nb_oargs = tmp >> 16; + nb_iargs = tmp & 0xffff; + nb_args = nb_oargs + nb_iargs + def->nb_cargs; } else { - for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) { - if (temps[args[i]].state == TCG_TEMP_COPY) { - args[i] = find_better_copy(s, args[i]); - } + nb_oargs = def->nb_oargs; + nb_iargs = def->nb_iargs; + nb_args = def->nb_args; + } + + /* Do copy propagation */ + for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { + if (temps[args[i]].state == TCG_TEMP_COPY) { + args[i] = find_better_copy(s, args[i]); } } @@ -882,7 +883,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(qemu_ld): { - TCGMemOp mop = args[def->nb_oargs + def->nb_iargs]; + TCGMemOp mop = args[nb_oargs + nb_iargs]; if (!(mop & MO_SIGN)) { mask = (2ULL << ((8 << (mop & MO_SIZE)) - 1)) - 1; } @@ -900,15 +901,15 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, } if (mask == 0) { - assert(def->nb_oargs == 1); + assert(nb_oargs == 1); s->gen_opc_buf[op_index] = op_to_movi(op); tcg_opt_gen_movi(gen_args, args[0], 0); - args += def->nb_oargs + def->nb_iargs + def->nb_cargs; + args += nb_args; gen_args += 2; continue; } if (affected == 0) { - assert(def->nb_oargs == 1); + assert(nb_oargs == 1); if (temps_are_copies(args[0], args[1])) { s->gen_opc_buf[op_index] = INDEX_op_nop; } else if (temps[args[1]].state != TCG_TEMP_CONST) { @@ -920,7 +921,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, tcg_opt_gen_movi(gen_args, args[0], temps[args[1]].val); gen_args += 2; } - args += def->nb_iargs + 1; + args += nb_args; continue; } @@ -1246,24 +1247,13 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, break; case INDEX_op_call: - nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); - if (!(args[nb_call_args + 1] & (TCG_CALL_NO_READ_GLOBALS | - TCG_CALL_NO_WRITE_GLOBALS))) { + if (!(args[nb_oargs + nb_iargs + 1] + & (TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_WRITE_GLOBALS))) { for (i = 0; i < nb_globals; i++) { reset_temp(i); } } - for (i = 0; i < (args[0] >> 16); i++) { - reset_temp(args[i + 1]); - } - i = nb_call_args + 3; - while (i) { - *gen_args = *args; - args++; - gen_args++; - i--; - } - break; + goto do_reset_output; default: do_default: @@ -1275,7 +1265,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, if (def->flags & TCG_OPF_BB_END) { reset_all_temps(nb_temps); } else { - for (i = 0; i < def->nb_oargs; i++) { + do_reset_output: + for (i = 0; i < nb_oargs; i++) { reset_temp(args[i]); /* Save the corresponding known-zero bits mask for the first output argument (only one supported so far). */ @@ -1284,11 +1275,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, } } } - for (i = 0; i < def->nb_args; i++) { + for (i = 0; i < nb_args; i++) { gen_args[i] = args[i]; } - args += def->nb_args; - gen_args += def->nb_args; + args += nb_args; + gen_args += nb_args; break; } } diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 83d9340fca..436b65bffb 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -24,7 +24,7 @@ #include "tcg-be-ldst.h" -static uint8_t *tb_ret_addr; +static tcg_insn_unit *tb_ret_addr; #if defined _CALL_DARWIN || defined __APPLE__ #define TCG_TARGET_CALL_DARWIN @@ -171,50 +171,47 @@ static const int tcg_target_callee_save_regs[] = { TCG_REG_R31 }; -static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) +static inline bool in_range_b(tcg_target_long target) { - tcg_target_long disp; - - disp = target - (tcg_target_long) pc; - if ((disp << 6) >> 6 != disp) - tcg_abort (); + return target == sextract32(target, 0, 26); +} +static uint32_t reloc_pc24_val(tcg_insn_unit *pc, tcg_insn_unit *target) +{ + ptrdiff_t disp = tcg_ptr_byte_diff(target, pc); + assert(in_range_b(disp)); return disp & 0x3fffffc; } -static void reloc_pc24 (void *pc, tcg_target_long target) +static void reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target) { - *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc) - | reloc_pc24_val (pc, target); + *pc = (*pc & ~0x3fffffc) | reloc_pc24_val(pc, target); } -static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) +static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target) { - tcg_target_long disp; - - disp = target - (tcg_target_long) pc; - if (disp != (int16_t) disp) - tcg_abort (); - + ptrdiff_t disp = tcg_ptr_byte_diff(target, pc); + assert(disp == (int16_t) disp); return disp & 0xfffc; } -static void reloc_pc14 (void *pc, tcg_target_long target) +static void reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target) { - *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc) - | reloc_pc14_val (pc, target); + *pc = (*pc & ~0xfffc) | reloc_pc14_val(pc, target); } -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { - value += addend; + tcg_insn_unit *target = (tcg_insn_unit *)value; + + assert(addend == 0); switch (type) { case R_PPC_REL14: - reloc_pc14 (code_ptr, value); + reloc_pc14(code_ptr, target); break; case R_PPC_REL24: - reloc_pc24 (code_ptr, value); + reloc_pc24(code_ptr, target); break; default: tcg_abort(); @@ -480,47 +477,36 @@ static void tcg_out_ldst (TCGContext *s, int ret, int addr, } } -static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) +static void tcg_out_b(TCGContext *s, int mask, tcg_insn_unit *target) { - tcg_target_long disp; - - disp = target - (tcg_target_long) s->code_ptr; - if ((disp << 6) >> 6 == disp) - tcg_out32 (s, B | (disp & 0x3fffffc) | mask); - else { - tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target); - tcg_out32 (s, MTSPR | RS (0) | CTR); - tcg_out32 (s, BCCTR | BO_ALWAYS | mask); + ptrdiff_t disp = tcg_pcrel_diff(s, target); + if (in_range_b(disp)) { + tcg_out32(s, B | (disp & 0x3fffffc) | mask); + } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, (uintptr_t)target); + tcg_out32(s, MTSPR | RS(TCG_REG_R0) | CTR); + tcg_out32(s, BCCTR | BO_ALWAYS | mask); } } -static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg, - int lk) +static void tcg_out_call1(TCGContext *s, tcg_insn_unit *target, int lk) { #ifdef _CALL_AIX - int reg; - - if (const_arg) { - reg = 2; - tcg_out_movi (s, TCG_TYPE_I32, reg, arg); - } - else reg = arg; - - tcg_out32 (s, LWZ | RT (0) | RA (reg)); - tcg_out32 (s, MTSPR | RA (0) | CTR); - tcg_out32 (s, LWZ | RT (2) | RA (reg) | 4); - tcg_out32 (s, BCCTR | BO_ALWAYS | lk); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, (uintptr_t)target); + tcg_out32(s, LWZ | RT(TCG_REG_R0) | RA(reg)); + tcg_out32(s, MTSPR | RA(TCG_REG_R0) | CTR); + tcg_out32(s, LWZ | RT(TCG_REG_R2) | RA(reg) | 4); + tcg_out32(s, BCCTR | BO_ALWAYS | lk); #else - if (const_arg) { - tcg_out_b (s, lk, arg); - } - else { - tcg_out32 (s, MTSPR | RS (arg) | LR); - tcg_out32 (s, BCLR | BO_ALWAYS | lk); - } + tcg_out_b(s, lk, target); #endif } +static void tcg_out_call(TCGContext *s, tcg_insn_unit *target) +{ + tcg_out_call1(s, target, LK); +} + #if defined(CONFIG_SOFTMMU) static void add_qemu_ldst_label (TCGContext *s, @@ -531,8 +517,8 @@ static void add_qemu_ldst_label (TCGContext *s, int addrlo_reg, int addrhi_reg, int mem_index, - uint8_t *raddr, - uint8_t *label_ptr) + tcg_insn_unit *raddr, + tcg_insn_unit *label_ptr) { TCGLabelQemuLdst *label = new_ldst_label(s); @@ -550,7 +536,7 @@ static void add_qemu_ldst_label (TCGContext *s, /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, * int mmu_idx, uintptr_t ra) */ -static const void * const qemu_ld_helpers[16] = { +static void * const qemu_ld_helpers[16] = { [MO_UB] = helper_ret_ldub_mmu, [MO_LEUW] = helper_le_lduw_mmu, [MO_LEUL] = helper_le_ldul_mmu, @@ -563,7 +549,7 @@ static const void * const qemu_ld_helpers[16] = { /* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, * uintxx_t val, int mmu_idx, uintptr_t ra) */ -static const void * const qemu_st_helpers[16] = { +static void * const qemu_st_helpers[16] = { [MO_UB] = helper_ret_stb_mmu, [MO_LEUW] = helper_le_stw_mmu, [MO_LEUL] = helper_le_stl_mmu, @@ -573,8 +559,8 @@ static const void * const qemu_st_helpers[16] = { [MO_BEQ] = helper_be_stq_mmu, }; -static void *ld_trampolines[16]; -static void *st_trampolines[16]; +static tcg_insn_unit *ld_trampolines[16]; +static tcg_insn_unit *st_trampolines[16]; /* Perform the TLB load and compare. Branches to the slow path, placing the address of the branch in *LABEL_PTR. Loads the addend of the TLB into R0. @@ -582,14 +568,15 @@ static void *st_trampolines[16]; static void tcg_out_tlb_check(TCGContext *s, TCGReg r0, TCGReg r1, TCGReg r2, TCGReg addrlo, TCGReg addrhi, TCGMemOp s_bits, - int mem_index, int is_load, uint8_t **label_ptr) + int mem_index, int is_load, + tcg_insn_unit **label_ptr) { int cmp_off = (is_load ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read) : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write)); int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend); - uint16_t retranst; + tcg_insn_unit retranst; TCGReg base = TCG_AREG0; /* Extract the page index, shifted into place for tlb index. */ @@ -648,7 +635,7 @@ static void tcg_out_tlb_check(TCGContext *s, TCGReg r0, TCGReg r1, TCGReg r2, This address cannot be used for a tail call, but it's shorter than forming an address from scratch. */ *label_ptr = s->code_ptr; - retranst = ((uint16_t *) s->code_ptr)[1] & ~3; + retranst = *s->code_ptr & 0xfffc; tcg_out32(s, BC | BI(7, CR_EQ) | retranst | BO_COND_FALSE | LK); } #endif @@ -659,7 +646,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64) TCGMemOp opc, bswap; #ifdef CONFIG_SOFTMMU int mem_index; - uint8_t *label_ptr; + tcg_insn_unit *label_ptr; #endif datalo = *args++; @@ -731,7 +718,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) TCGMemOp opc, bswap, s_bits; #ifdef CONFIG_SOFTMMU int mem_index; - uint8_t *label_ptr; + tcg_insn_unit *label_ptr; #endif datalo = *args++; @@ -790,7 +777,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) TCGReg ir, datalo, datahi; TCGMemOp opc = l->opc; - reloc_pc14 (l->label_ptr[0], (uintptr_t)s->code_ptr); + reloc_pc14(l->label_ptr[0], s->code_ptr); ir = TCG_REG_R4; if (TARGET_LONG_BITS == 32) { @@ -804,7 +791,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) } tcg_out_movi(s, TCG_TYPE_I32, ir++, l->mem_index); tcg_out32(s, MFSPR | RT(ir++) | LR); - tcg_out_b(s, LK, (uintptr_t)ld_trampolines[opc & ~MO_SIGN]); + tcg_out_b(s, LK, ld_trampolines[opc & ~MO_SIGN]); datalo = l->datalo_reg; switch (opc & MO_SSIZE) { @@ -832,7 +819,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) } break; } - tcg_out_b (s, 0, (uintptr_t)l->raddr); + tcg_out_b(s, 0, l->raddr); } static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) @@ -840,7 +827,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) TCGReg ir, datalo; TCGMemOp opc = l->opc; - reloc_pc14 (l->label_ptr[0], (tcg_target_long) s->code_ptr); + reloc_pc14(l->label_ptr[0], s->code_ptr); ir = TCG_REG_R4; if (TARGET_LONG_BITS == 32) { @@ -878,16 +865,16 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) tcg_out_movi(s, TCG_TYPE_I32, ir++, l->mem_index); tcg_out32(s, MFSPR | RT(ir++) | LR); - tcg_out_b(s, LK, (uintptr_t)st_trampolines[opc]); - tcg_out_b(s, 0, (uintptr_t)l->raddr); + tcg_out_b(s, LK, st_trampolines[opc]); + tcg_out_b(s, 0, l->raddr); } #endif #ifdef CONFIG_SOFTMMU -static void emit_ldst_trampoline (TCGContext *s, const void *ptr) +static void emit_ldst_trampoline(TCGContext *s, tcg_insn_unit *ptr) { - tcg_out_mov (s, TCG_TYPE_I32, 3, TCG_AREG0); - tcg_out_call (s, (tcg_target_long) ptr, 1, 0); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R3, TCG_AREG0); + tcg_out_call1(s, ptr, 0); } #endif @@ -909,12 +896,13 @@ static void tcg_target_qemu_prologue (TCGContext *s) #ifdef _CALL_AIX { - uint32_t addr; + uintptr_t addr; /* First emit adhoc function descriptor */ - addr = (uint32_t) s->code_ptr + 12; - tcg_out32 (s, addr); /* entry point */ - s->code_ptr += 8; /* skip TOC and environment pointer */ + addr = (uintptr_t)s->code_ptr + 12; + tcg_out32(s, addr); /* entry point */ + tcg_out32(s, 0); /* toc */ + tcg_out32(s, 0); /* environment pointer */ } #endif tcg_out32 (s, MFSPR | RT (0) | LR); @@ -1065,18 +1053,17 @@ static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, } -static void tcg_out_bc (TCGContext *s, int bc, int label_index) +static void tcg_out_bc(TCGContext *s, int bc, int label_index) { TCGLabel *l = &s->labels[label_index]; - if (l->has_value) - tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value)); - else { - uint16_t val = *(uint16_t *) &s->code_ptr[2]; - + if (l->has_value) { + tcg_out32(s, bc | reloc_pc14_val(s->code_ptr, l->u.value_ptr)); + } else { /* Thanks to Andrzej Zaborowski */ - tcg_out32 (s, bc | (val & 0xfffc)); - tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); + tcg_insn_unit retrans = *s->code_ptr & 0xfffc; + tcg_out_reloc(s, s->code_ptr, R_PPC_REL14, label_index, 0); + tcg_out32(s, bc | retrans); } } @@ -1367,43 +1354,33 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, { switch (opc) { case INDEX_op_exit_tb: - tcg_out_movi (s, TCG_TYPE_I32, TCG_REG_R3, args[0]); - tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R3, args[0]); + tcg_out_b(s, 0, tb_ret_addr); break; case INDEX_op_goto_tb: if (s->tb_jmp_offset) { /* direct jump method */ - - s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; - s->code_ptr += 16; - } - else { + s->tb_jmp_offset[args[0]] = tcg_current_code_size(s); + s->code_ptr += 4; + } else { tcg_abort (); } - s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + s->tb_next_offset[args[0]] = tcg_current_code_size(s); break; case INDEX_op_br: { TCGLabel *l = &s->labels[args[0]]; if (l->has_value) { - tcg_out_b (s, 0, l->u.value); - } - else { - uint32_t val = *(uint32_t *) s->code_ptr; - + tcg_out_b(s, 0, l->u.value_ptr); + } else { /* Thanks to Andrzej Zaborowski */ - tcg_out32 (s, B | (val & 0x3fffffc)); - tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); + tcg_insn_unit retrans = *s->code_ptr & 0x3fffffc; + tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, args[0], 0); + tcg_out32(s, B | retrans); } } break; - case INDEX_op_call: - tcg_out_call (s, args[0], const_args[0], LK); - break; - case INDEX_op_movi_i32: - tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); - break; case INDEX_op_ld8u_i32: tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); break; @@ -1839,20 +1816,19 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const_args[2]); break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: - tcg_dump_ops (s); - tcg_abort (); + tcg_abort(); } } static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "ri" } }, { INDEX_op_br, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_movi_i32, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 0d4f5959a7..dd7e557948 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -25,6 +25,7 @@ #define TCG_TARGET_PPC 1 #define TCG_TARGET_NB_REGS 32 +#define TCG_TARGET_INSN_UNIT_SIZE 4 typedef enum { TCG_REG_R0 = 0, diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 45b1c06910..c90ddcd03a 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -31,7 +31,7 @@ #define TCG_CT_CONST_ZERO 0x1000 #define TCG_CT_CONST_MONE 0x2000 -static uint8_t *tb_ret_addr; +static tcg_insn_unit *tb_ret_addr; #if TARGET_LONG_BITS == 32 #define LD_ADDR LWZ @@ -168,61 +168,54 @@ static inline bool in_range_b(tcg_target_long target) return target == sextract64(target, 0, 26); } -static uint32_t reloc_pc24_val(void *pc, tcg_target_long target) +static uint32_t reloc_pc24_val(tcg_insn_unit *pc, tcg_insn_unit *target) { - tcg_target_long disp; - - disp = target - (tcg_target_long)pc; + ptrdiff_t disp = tcg_ptr_byte_diff(target, pc); assert(in_range_b(disp)); - return disp & 0x3fffffc; } -static void reloc_pc24(void *pc, tcg_target_long target) +static void reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target) { - *(uint32_t *)pc = (*(uint32_t *)pc & ~0x3fffffc) - | reloc_pc24_val(pc, target); + *pc = (*pc & ~0x3fffffc) | reloc_pc24_val(pc, target); } -static uint16_t reloc_pc14_val(void *pc, tcg_target_long target) +static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target) { - tcg_target_long disp; - - disp = target - (tcg_target_long)pc; - if (disp != (int16_t) disp) { - tcg_abort(); - } - + ptrdiff_t disp = tcg_ptr_byte_diff(target, pc); + assert(disp == (int16_t) disp); return disp & 0xfffc; } -static void reloc_pc14(void *pc, tcg_target_long target) +static void reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target) { - *(uint32_t *)pc = (*(uint32_t *)pc & ~0xfffc) | reloc_pc14_val(pc, target); + *pc = (*pc & ~0xfffc) | reloc_pc14_val(pc, target); } static inline void tcg_out_b_noaddr(TCGContext *s, int insn) { - unsigned retrans = *(uint32_t *)s->code_ptr & 0x3fffffc; + unsigned retrans = *s->code_ptr & 0x3fffffc; tcg_out32(s, insn | retrans); } static inline void tcg_out_bc_noaddr(TCGContext *s, int insn) { - unsigned retrans = *(uint32_t *)s->code_ptr & 0xfffc; + unsigned retrans = *s->code_ptr & 0xfffc; tcg_out32(s, insn | retrans); } -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { - value += addend; + tcg_insn_unit *target = (tcg_insn_unit *)value; + + assert(addend == 0); switch (type) { case R_PPC_REL14: - reloc_pc14(code_ptr, value); + reloc_pc14(code_ptr, target); break; case R_PPC_REL24: - reloc_pc24(code_ptr, value); + reloc_pc24(code_ptr, target); break; default: tcg_abort(); @@ -702,61 +695,48 @@ static void tcg_out_xori32(TCGContext *s, TCGReg dst, TCGReg src, uint32_t c) tcg_out_zori32(s, dst, src, c, XORI, XORIS); } -static void tcg_out_b(TCGContext *s, int mask, tcg_target_long target) +static void tcg_out_b(TCGContext *s, int mask, tcg_insn_unit *target) { - tcg_target_long disp; - - disp = target - (tcg_target_long)s->code_ptr; + ptrdiff_t disp = tcg_pcrel_diff(s, target); if (in_range_b(disp)) { tcg_out32(s, B | (disp & 0x3fffffc) | mask); } else { - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, (tcg_target_long)target); + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R0, (uintptr_t)target); tcg_out32(s, MTSPR | RS(TCG_REG_R0) | CTR); tcg_out32(s, BCCTR | BO_ALWAYS | mask); } } -static void tcg_out_call(TCGContext *s, tcg_target_long arg, int const_arg) +static void tcg_out_call(TCGContext *s, tcg_insn_unit *target) { #ifdef __APPLE__ - if (const_arg) { - tcg_out_b(s, LK, arg); - } else { - tcg_out32(s, MTSPR | RS(arg) | LR); - tcg_out32(s, BCLR | BO_ALWAYS | LK); - } + tcg_out_b(s, LK, target); #else - TCGReg reg = arg; - int ofs = 0; - - if (const_arg) { - /* Look through the descriptor. If the branch is in range, and we - don't have to spend too much effort on building the toc. */ - intptr_t tgt = ((intptr_t *)arg)[0]; - intptr_t toc = ((intptr_t *)arg)[1]; - intptr_t diff = tgt - (intptr_t)s->code_ptr; - - if (in_range_b(diff) && toc == (uint32_t)toc) { - tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R2, toc); - tcg_out_b(s, LK, tgt); - return; - } - + /* Look through the descriptor. If the branch is in range, and we + don't have to spend too much effort on building the toc. */ + void *tgt = ((void **)target)[0]; + uintptr_t toc = ((uintptr_t *)target)[1]; + intptr_t diff = tcg_pcrel_diff(s, tgt); + + if (in_range_b(diff) && toc == (uint32_t)toc) { + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R2, toc); + tcg_out_b(s, LK, tgt); + } else { /* Fold the low bits of the constant into the addresses below. */ - ofs = (int16_t)arg; + intptr_t arg = (intptr_t)target; + int ofs = (int16_t)arg; + if (ofs + 8 < 0x8000) { arg -= ofs; } else { ofs = 0; } - reg = TCG_REG_R2; - tcg_out_movi(s, TCG_TYPE_I64, reg, arg); + tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R2, arg); + tcg_out32(s, LD | TAI(TCG_REG_R0, TCG_REG_R2, ofs)); + tcg_out32(s, MTSPR | RA(TCG_REG_R0) | CTR); + tcg_out32(s, LD | TAI(TCG_REG_R2, TCG_REG_R2, ofs + 8)); + tcg_out32(s, BCCTR | BO_ALWAYS | LK); } - - tcg_out32(s, LD | TAI(TCG_REG_R0, reg, ofs)); - tcg_out32(s, MTSPR | RA(TCG_REG_R0) | CTR); - tcg_out32(s, LD | TAI(TCG_REG_R2, reg, ofs + 8)); - tcg_out32(s, BCCTR | BO_ALWAYS | LK); #endif } @@ -844,7 +824,7 @@ static const uint32_t qemu_exts_opc[4] = { /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, * int mmu_idx, uintptr_t ra) */ -static const void * const qemu_ld_helpers[16] = { +static void * const qemu_ld_helpers[16] = { [MO_UB] = helper_ret_ldub_mmu, [MO_LEUW] = helper_le_lduw_mmu, [MO_LEUL] = helper_le_ldul_mmu, @@ -857,7 +837,7 @@ static const void * const qemu_ld_helpers[16] = { /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, * uintxx_t val, int mmu_idx, uintptr_t ra) */ -static const void * const qemu_st_helpers[16] = { +static void * const qemu_st_helpers[16] = { [MO_UB] = helper_ret_stb_mmu, [MO_LEUW] = helper_le_stw_mmu, [MO_LEUL] = helper_le_stl_mmu, @@ -946,7 +926,7 @@ static TCGReg tcg_out_tlb_read(TCGContext *s, TCGMemOp s_bits, TCGReg addr_reg, helper code. */ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc, int data_reg, int addr_reg, int mem_index, - uint8_t *raddr, uint8_t *label_ptr) + tcg_insn_unit *raddr, tcg_insn_unit *label_ptr) { TCGLabelQemuLdst *label = new_ldst_label(s); @@ -963,7 +943,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { TCGMemOp opc = lb->opc; - reloc_pc14(lb->label_ptr[0], (uintptr_t)s->code_ptr); + reloc_pc14(lb->label_ptr[0], s->code_ptr); tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R3, TCG_AREG0); @@ -974,7 +954,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R5, lb->mem_index); tcg_out32(s, MFSPR | RT(TCG_REG_R6) | LR); - tcg_out_call(s, (tcg_target_long)qemu_ld_helpers[opc & ~MO_SIGN], 1); + tcg_out_call(s, qemu_ld_helpers[opc & ~MO_SIGN]); if (opc & MO_SIGN) { uint32_t insn = qemu_exts_opc[opc & MO_SIZE]; @@ -983,7 +963,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) tcg_out_mov(s, TCG_TYPE_I64, lb->datalo_reg, TCG_REG_R3); } - tcg_out_b(s, 0, (uintptr_t)lb->raddr); + tcg_out_b(s, 0, lb->raddr); } static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) @@ -991,7 +971,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) TCGMemOp opc = lb->opc; TCGMemOp s_bits = opc & MO_SIZE; - reloc_pc14(lb->label_ptr[0], (uintptr_t)s->code_ptr); + reloc_pc14(lb->label_ptr[0], s->code_ptr); tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R3, TCG_AREG0); @@ -1004,9 +984,9 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R6, lb->mem_index); tcg_out32(s, MFSPR | RT(TCG_REG_R7) | LR); - tcg_out_call(s, (tcg_target_long)qemu_st_helpers[opc], 1); + tcg_out_call(s, qemu_st_helpers[opc]); - tcg_out_b(s, 0, (uintptr_t)lb->raddr); + tcg_out_b(s, 0, lb->raddr); } #endif /* SOFTMMU */ @@ -1017,7 +997,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, uint32_t insn; TCGMemOp s_bits = opc & MO_SIZE; #ifdef CONFIG_SOFTMMU - void *label_ptr; + tcg_insn_unit *label_ptr; #endif #ifdef CONFIG_SOFTMMU @@ -1063,7 +1043,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, TCGReg rbase; uint32_t insn; #ifdef CONFIG_SOFTMMU - void *label_ptr; + tcg_insn_unit *label_ptr; #endif #ifdef CONFIG_SOFTMMU @@ -1123,7 +1103,8 @@ static void tcg_target_qemu_prologue(TCGContext *s) #ifndef __APPLE__ /* First emit adhoc function descriptor */ tcg_out64(s, (uint64_t)s->code_ptr + 24); /* entry point */ - s->code_ptr += 16; /* skip TOC and environment pointer */ + tcg_out64(s, 0); /* toc */ + tcg_out64(s, 0); /* environment pointer */ #endif /* Prologue */ @@ -1415,7 +1396,7 @@ static void tcg_out_bc(TCGContext *s, int bc, int label_index) TCGLabel *l = &s->labels[label_index]; if (l->has_value) { - tcg_out32(s, bc | reloc_pc14_val(s->code_ptr, l->u.value)); + tcg_out32(s, bc | reloc_pc14_val(s->code_ptr, l->u.value_ptr)); } else { tcg_out_reloc(s, s->code_ptr, R_PPC_REL14, label_index, 0); tcg_out_bc_noaddr(s, bc); @@ -1478,15 +1459,13 @@ static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond, } } -void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr) +void ppc_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr) { TCGContext s; - unsigned long patch_size; - s.code_ptr = (uint8_t *) jmp_addr; - tcg_out_b(&s, 0, addr); - patch_size = s.code_ptr - (uint8_t *) jmp_addr; - flush_icache_range(jmp_addr, jmp_addr + patch_size); + s.code_buf = s.code_ptr = (tcg_insn_unit *)jmp_addr; + tcg_out_b(&s, 0, (tcg_insn_unit *)addr); + flush_icache_range(jmp_addr, jmp_addr + tcg_current_code_size(&s)); } static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, @@ -1498,40 +1477,31 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, switch (opc) { case INDEX_op_exit_tb: tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_R3, args[0]); - tcg_out_b(s, 0, (tcg_target_long)tb_ret_addr); + tcg_out_b(s, 0, tb_ret_addr); break; case INDEX_op_goto_tb: if (s->tb_jmp_offset) { /* Direct jump method. */ - s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; - s->code_ptr += 28; + s->tb_jmp_offset[args[0]] = tcg_current_code_size(s); + s->code_ptr += 7; } else { /* Indirect jump method. */ tcg_abort(); } - s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + s->tb_next_offset[args[0]] = tcg_current_code_size(s); break; case INDEX_op_br: { TCGLabel *l = &s->labels[args[0]]; if (l->has_value) { - tcg_out_b(s, 0, l->u.value); + tcg_out_b(s, 0, l->u.value_ptr); } else { tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, args[0], 0); tcg_out_b_noaddr(s, B); } } break; - case INDEX_op_call: - tcg_out_call(s, args[0], const_args[0]); - break; - case INDEX_op_movi_i32: - tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); - break; - case INDEX_op_movi_i64: - tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); - break; case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]); @@ -2012,8 +1982,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out32(s, MULHD | TAB(args[0], args[1], args[2])); break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_mov_i64: + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ + case INDEX_op_movi_i64: + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: - tcg_dump_ops(s); tcg_abort(); } } @@ -2021,14 +1995,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "ri" } }, { INDEX_op_br, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_mov_i64, { "r", "r" } }, - { INDEX_op_movi_i32, { "r" } }, - { INDEX_op_movi_i64, { "r" } }, - { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h index 3815b840a6..29f479a3cf 100644 --- a/tcg/ppc64/tcg-target.h +++ b/tcg/ppc64/tcg-target.h @@ -25,6 +25,7 @@ #define TCG_TARGET_PPC64 1 #define TCG_TARGET_NB_REGS 32 +#define TCG_TARGET_INSN_UNIT_SIZE 4 typedef enum { TCG_REG_R0 = 0, diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 1d912a7937..ebdd0743cf 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -320,7 +320,7 @@ static const uint8_t tcg_cond_to_ltr_cond[] = { #ifdef CONFIG_SOFTMMU /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, int mmu_idx) */ -static const void * const qemu_ld_helpers[4] = { +static void * const qemu_ld_helpers[4] = { helper_ldb_mmu, helper_ldw_mmu, helper_ldl_mmu, @@ -329,7 +329,7 @@ static const void * const qemu_ld_helpers[4] = { /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, uintxx_t val, int mmu_idx) */ -static const void * const qemu_st_helpers[4] = { +static void * const qemu_st_helpers[4] = { helper_stb_mmu, helper_stw_mmu, helper_stl_mmu, @@ -337,7 +337,7 @@ static const void * const qemu_st_helpers[4] = { }; #endif -static uint8_t *tb_ret_addr; +static tcg_insn_unit *tb_ret_addr; /* A list of relevant facilities used by this translator. Some of these are required for proper operation, and these are checked at startup. */ @@ -350,23 +350,20 @@ static uint8_t *tb_ret_addr; static uint64_t facilities; -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { - intptr_t code_ptr_tl = (intptr_t)code_ptr; - intptr_t pcrel2; - - /* ??? Not the usual definition of "addend". */ - pcrel2 = (value - (code_ptr_tl + addend)) >> 1; + intptr_t pcrel2 = (tcg_insn_unit *)value - (code_ptr - 1); + assert(addend == -2); switch (type) { case R_390_PC16DBL: assert(pcrel2 == (int16_t)pcrel2); - *(int16_t *)code_ptr = pcrel2; + tcg_patch16(code_ptr, pcrel2); break; case R_390_PC32DBL: assert(pcrel2 == (int32_t)pcrel2); - *(int32_t *)code_ptr = pcrel2; + tcg_patch32(code_ptr, pcrel2); break; default: tcg_abort(); @@ -672,7 +669,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, /* Try for PC-relative address load. */ if ((sval & 1) == 0) { - intptr_t off = (sval - (intptr_t)s->code_ptr) >> 1; + ptrdiff_t off = tcg_pcrel_diff(s, (void *)sval) >> 1; if (off == (int32_t)off) { tcg_out_insn(s, RIL, LARL, ret, off); return; @@ -789,10 +786,10 @@ static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg data, /* load data from an absolute host address */ static void tcg_out_ld_abs(TCGContext *s, TCGType type, TCGReg dest, void *abs) { - tcg_target_long addr = (tcg_target_long)abs; + intptr_t addr = (intptr_t)abs; - if (facilities & FACILITY_GEN_INST_EXT) { - tcg_target_long disp = (addr - (tcg_target_long)s->code_ptr) >> 1; + if ((facilities & FACILITY_GEN_INST_EXT) && !(addr & 1)) { + ptrdiff_t disp = tcg_pcrel_diff(s, abs) >> 1; if (disp == (int32_t)disp) { if (type == TCG_TYPE_I32) { tcg_out_insn(s, RIL, LRL, dest, disp); @@ -1154,15 +1151,15 @@ static void tgen_deposit(TCGContext *s, TCGReg dest, TCGReg src, tcg_out_risbg(s, dest, src, msb, lsb, ofs, 0); } -static void tgen_gotoi(TCGContext *s, int cc, tcg_target_long dest) +static void tgen_gotoi(TCGContext *s, int cc, tcg_insn_unit *dest) { - tcg_target_long off = (dest - (tcg_target_long)s->code_ptr) >> 1; - if (off > -0x8000 && off < 0x7fff) { + ptrdiff_t off = dest - s->code_ptr; + if (off == (int16_t)off) { tcg_out_insn(s, RI, BRC, cc, off); } else if (off == (int32_t)off) { tcg_out_insn(s, RIL, BRCL, cc, off); } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, dest); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, (uintptr_t)dest); tcg_out_insn(s, RR, BCR, cc, TCG_TMP0); } } @@ -1171,15 +1168,15 @@ static void tgen_branch(TCGContext *s, int cc, int labelno) { TCGLabel* l = &s->labels[labelno]; if (l->has_value) { - tgen_gotoi(s, cc, l->u.value); + tgen_gotoi(s, cc, l->u.value_ptr); } else if (USE_LONG_BRANCHES) { tcg_out16(s, RIL_BRCL | (cc << 4)); tcg_out_reloc(s, s->code_ptr, R_390_PC32DBL, labelno, -2); - s->code_ptr += 4; + s->code_ptr += 2; } else { tcg_out16(s, RI_BRC | (cc << 4)); tcg_out_reloc(s, s->code_ptr, R_390_PC16DBL, labelno, -2); - s->code_ptr += 2; + s->code_ptr += 1; } } @@ -1187,14 +1184,14 @@ static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc, TCGReg r1, TCGReg r2, int labelno) { TCGLabel* l = &s->labels[labelno]; - tcg_target_long off; + intptr_t off; if (l->has_value) { - off = (l->u.value - (tcg_target_long)s->code_ptr) >> 1; + off = l->u.value_ptr - s->code_ptr; } else { /* We need to keep the offset unchanged for retranslation. */ - off = ((int16_t *)s->code_ptr)[1]; - tcg_out_reloc(s, s->code_ptr + 2, R_390_PC16DBL, labelno, -2); + off = s->code_ptr[1]; + tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, labelno, -2); } tcg_out16(s, (opc & 0xff00) | (r1 << 4) | r2); @@ -1209,11 +1206,11 @@ static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc, tcg_target_long off; if (l->has_value) { - off = (l->u.value - (tcg_target_long)s->code_ptr) >> 1; + off = l->u.value_ptr - s->code_ptr; } else { /* We need to keep the offset unchanged for retranslation. */ - off = ((int16_t *)s->code_ptr)[1]; - tcg_out_reloc(s, s->code_ptr + 2, R_390_PC16DBL, labelno, -2); + off = s->code_ptr[1]; + tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, labelno, -2); } tcg_out16(s, (opc & 0xff00) | (r1 << 4) | cc); @@ -1272,13 +1269,13 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c, tgen_branch(s, cc, labelno); } -static void tgen_calli(TCGContext *s, tcg_target_long dest) +static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest) { - tcg_target_long off = (dest - (tcg_target_long)s->code_ptr) >> 1; + ptrdiff_t off = dest - s->code_ptr; if (off == (int32_t)off) { tcg_out_insn(s, RIL, BRASL, TCG_REG_R14, off); } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, dest); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, (uintptr_t)dest); tcg_out_insn(s, RR, BASR, TCG_REG_R14, TCG_TMP0); } } @@ -1395,14 +1392,14 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int opc, TCGReg data, #if defined(CONFIG_SOFTMMU) static TCGReg tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, int mem_index, int opc, - uint16_t **label2_ptr_p, int is_store) + tcg_insn_unit **label2_ptr_p, int is_store) { const TCGReg arg0 = tcg_target_call_iarg_regs[0]; const TCGReg arg1 = tcg_target_call_iarg_regs[1]; const TCGReg arg2 = tcg_target_call_iarg_regs[2]; const TCGReg arg3 = tcg_target_call_iarg_regs[3]; int s_bits = opc & 3; - uint16_t *label1_ptr; + tcg_insn_unit *label1_ptr; tcg_target_long ofs; if (TARGET_LONG_BITS == 32) { @@ -1436,7 +1433,7 @@ static TCGReg tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, tcg_out_mov(s, TCG_TYPE_I64, arg1, addr_reg); } - label1_ptr = (uint16_t*)s->code_ptr; + label1_ptr = s->code_ptr; /* je label1 (offset will be patched in later) */ tcg_out_insn(s, RI, BRC, S390_CC_EQ, 0); @@ -1463,11 +1460,11 @@ static TCGReg tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, } tcg_out_movi(s, TCG_TYPE_I32, arg3, mem_index); tcg_out_mov(s, TCG_TYPE_I64, arg0, TCG_AREG0); - tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]); + tcg_out_call(s, qemu_st_helpers[s_bits]); } else { tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); tcg_out_mov(s, TCG_TYPE_I64, arg0, TCG_AREG0); - tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]); + tcg_out_call(s, qemu_ld_helpers[s_bits]); /* sign extension */ switch (opc) { @@ -1488,13 +1485,12 @@ static TCGReg tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, } /* jump to label2 (end) */ - *label2_ptr_p = (uint16_t*)s->code_ptr; + *label2_ptr_p = s->code_ptr; tcg_out_insn(s, RI, BRC, S390_CC_ALWAYS, 0); /* this is label1, patch branch */ - *(label1_ptr + 1) = ((unsigned long)s->code_ptr - - (unsigned long)label1_ptr) >> 1; + label1_ptr[1] = s->code_ptr - label1_ptr; ofs = offsetof(CPUArchState, tlb_table[mem_index][0].addend); assert(ofs < 0x80000); @@ -1504,11 +1500,10 @@ static TCGReg tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, return arg1; } -static void tcg_finish_qemu_ldst(TCGContext* s, uint16_t *label2_ptr) +static void tcg_finish_qemu_ldst(TCGContext* s, tcg_insn_unit *label2_ptr) { /* patch branch */ - *(label2_ptr + 1) = ((unsigned long)s->code_ptr - - (unsigned long)label2_ptr) >> 1; + label2_ptr[1] = s->code_ptr - label2_ptr; } #else static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg, @@ -1535,7 +1530,7 @@ static void tcg_out_qemu_ld(TCGContext* s, const TCGArg* args, int opc) TCGReg addr_reg, data_reg; #if defined(CONFIG_SOFTMMU) int mem_index; - uint16_t *label2_ptr; + tcg_insn_unit *label2_ptr; #else TCGReg index_reg; tcg_target_long disp; @@ -1564,7 +1559,7 @@ static void tcg_out_qemu_st(TCGContext* s, const TCGArg* args, int opc) TCGReg addr_reg, data_reg; #if defined(CONFIG_SOFTMMU) int mem_index; - uint16_t *label2_ptr; + tcg_insn_unit *label2_ptr; #else TCGReg index_reg; tcg_target_long disp; @@ -1602,7 +1597,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_exit_tb: /* return value */ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R2, args[0]); - tgen_gotoi(s, S390_CC_ALWAYS, (unsigned long)tb_ret_addr); + tgen_gotoi(s, S390_CC_ALWAYS, tb_ret_addr); break; case INDEX_op_goto_tb: @@ -1614,22 +1609,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, /* and go there */ tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_TMP0); } - s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; - break; - - case INDEX_op_call: - if (const_args[0]) { - tgen_calli(s, args[0]); - } else { - tcg_out_insn(s, RR, BASR, TCG_REG_R14, args[0]); - } - break; - - case INDEX_op_mov_i32: - tcg_out_mov(s, TCG_TYPE_I32, args[0], args[1]); - break; - case INDEX_op_movi_i32: - tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); + s->tb_next_offset[args[0]] = tcg_current_code_size(s); break; OP_32_64(ld8u): @@ -1864,13 +1844,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_qemu_st(s, args, LD_UINT64); break; - case INDEX_op_mov_i64: - tcg_out_mov(s, TCG_TYPE_I64, args[0], args[1]); - break; - case INDEX_op_movi_i64: - tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); - break; - case INDEX_op_ld16s_i64: tcg_out_mem(s, 0, RXY_LGH, args[0], args[1], TCG_REG_NONE, args[2]); break; @@ -2075,8 +2048,12 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tgen_deposit(s, args[0], args[2], args[3], args[4]); break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_mov_i64: + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ + case INDEX_op_movi_i64: + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: - fprintf(stderr,"unimplemented opc 0x%x\n",opc); tcg_abort(); } } @@ -2084,12 +2061,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "ri" } }, { INDEX_op_br, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_movi_i32, { "r" } }, - { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, @@ -2147,9 +2120,6 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_qemu_st32, { "L", "L" } }, { INDEX_op_qemu_st64, { "L", "L" } }, - { INDEX_op_mov_i64, { "r", "r" } }, - { INDEX_op_movi_i64, { "r" } }, - { INDEX_op_ld8u_i64, { "r", "r" } }, { INDEX_op_ld8s_i64, { "r", "r" } }, { INDEX_op_ld16u_i64, { "r", "r" } }, diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index 755c00237e..5bf733eb3d 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -24,6 +24,8 @@ #ifndef TCG_TARGET_S390 #define TCG_TARGET_S390 1 +#define TCG_TARGET_INSN_UNIT_SIZE 2 + typedef enum TCGReg { TCG_REG_R0 = 0, TCG_REG_R1, diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 5468ff5c16..17ff5773ad 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -279,37 +279,32 @@ static inline int check_fit_i32(int32_t val, unsigned int bits) # define check_fit_ptr check_fit_i32 #endif -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { uint32_t insn; - value += addend; + + assert(addend == 0); + value = tcg_ptr_byte_diff((tcg_insn_unit *)value, code_ptr); + switch (type) { - case R_SPARC_32: - if (value != (uint32_t)value) { - tcg_abort(); - } - *(uint32_t *)code_ptr = value; - break; case R_SPARC_WDISP16: - value -= (intptr_t)code_ptr; if (!check_fit_ptr(value >> 2, 16)) { tcg_abort(); } - insn = *(uint32_t *)code_ptr; + insn = *code_ptr; insn &= ~INSN_OFF16(-1); insn |= INSN_OFF16(value); - *(uint32_t *)code_ptr = insn; + *code_ptr = insn; break; case R_SPARC_WDISP19: - value -= (intptr_t)code_ptr; if (!check_fit_ptr(value >> 2, 19)) { tcg_abort(); } - insn = *(uint32_t *)code_ptr; + insn = *code_ptr; insn &= ~INSN_OFF19(-1); insn |= INSN_OFF19(value); - *(uint32_t *)code_ptr = insn; + *code_ptr = insn; break; default: tcg_abort(); @@ -573,10 +568,10 @@ static void tcg_out_bpcc(TCGContext *s, int scond, int flags, int label) int off19; if (l->has_value) { - off19 = INSN_OFF19(l->u.value - (unsigned long)s->code_ptr); + off19 = INSN_OFF19(tcg_pcrel_diff(s, l->u.value_ptr)); } else { /* Make sure to preserve destinations during retranslation. */ - off19 = *(uint32_t *)s->code_ptr & INSN_OFF19(-1); + off19 = *s->code_ptr & INSN_OFF19(-1); tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label, 0); } tcg_out_bpcc0(s, scond, flags, off19); @@ -620,10 +615,10 @@ static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, TCGReg arg1, int off16; if (l->has_value) { - off16 = INSN_OFF16(l->u.value - (unsigned long)s->code_ptr); + off16 = INSN_OFF16(tcg_pcrel_diff(s, l->u.value_ptr)); } else { /* Make sure to preserve destinations during retranslation. */ - off16 = *(uint32_t *)s->code_ptr & INSN_OFF16(-1); + off16 = *s->code_ptr & INSN_OFF16(-1); tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP16, label, 0); } tcg_out32(s, INSN_OP(0) | INSN_OP2(3) | BPR_PT | INSN_RS1(arg1) @@ -740,62 +735,66 @@ static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, tcg_out_mov(s, TCG_TYPE_I32, rl, tmp); } -static void tcg_out_calli(TCGContext *s, uintptr_t dest) +static void tcg_out_call_nodelay(TCGContext *s, tcg_insn_unit *dest) { - intptr_t disp = dest - (uintptr_t)s->code_ptr; + ptrdiff_t disp = tcg_pcrel_diff(s, dest); if (disp == (int32_t)disp) { tcg_out32(s, CALL | (uint32_t)disp >> 2); } else { - tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, dest & ~0xfff); - tcg_out_arithi(s, TCG_REG_O7, TCG_REG_T1, dest & 0xfff, JMPL); + uintptr_t desti = (uintptr_t)dest; + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, desti & ~0xfff); + tcg_out_arithi(s, TCG_REG_O7, TCG_REG_T1, desti & 0xfff, JMPL); } } +static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest) +{ + tcg_out_call_nodelay(s, dest); + tcg_out_nop(s); +} + #ifdef CONFIG_SOFTMMU -static uintptr_t qemu_ld_trampoline[16]; -static uintptr_t qemu_st_trampoline[16]; +static tcg_insn_unit *qemu_ld_trampoline[16]; +static tcg_insn_unit *qemu_st_trampoline[16]; static void build_trampolines(TCGContext *s) { - static uintptr_t const qemu_ld_helpers[16] = { - [MO_UB] = (uintptr_t)helper_ret_ldub_mmu, - [MO_SB] = (uintptr_t)helper_ret_ldsb_mmu, - [MO_LEUW] = (uintptr_t)helper_le_lduw_mmu, - [MO_LESW] = (uintptr_t)helper_le_ldsw_mmu, - [MO_LEUL] = (uintptr_t)helper_le_ldul_mmu, - [MO_LEQ] = (uintptr_t)helper_le_ldq_mmu, - [MO_BEUW] = (uintptr_t)helper_be_lduw_mmu, - [MO_BESW] = (uintptr_t)helper_be_ldsw_mmu, - [MO_BEUL] = (uintptr_t)helper_be_ldul_mmu, - [MO_BEQ] = (uintptr_t)helper_be_ldq_mmu, + static void * const qemu_ld_helpers[16] = { + [MO_UB] = helper_ret_ldub_mmu, + [MO_SB] = helper_ret_ldsb_mmu, + [MO_LEUW] = helper_le_lduw_mmu, + [MO_LESW] = helper_le_ldsw_mmu, + [MO_LEUL] = helper_le_ldul_mmu, + [MO_LEQ] = helper_le_ldq_mmu, + [MO_BEUW] = helper_be_lduw_mmu, + [MO_BESW] = helper_be_ldsw_mmu, + [MO_BEUL] = helper_be_ldul_mmu, + [MO_BEQ] = helper_be_ldq_mmu, }; - static uintptr_t const qemu_st_helpers[16] = { - [MO_UB] = (uintptr_t)helper_ret_stb_mmu, - [MO_LEUW] = (uintptr_t)helper_le_stw_mmu, - [MO_LEUL] = (uintptr_t)helper_le_stl_mmu, - [MO_LEQ] = (uintptr_t)helper_le_stq_mmu, - [MO_BEUW] = (uintptr_t)helper_be_stw_mmu, - [MO_BEUL] = (uintptr_t)helper_be_stl_mmu, - [MO_BEQ] = (uintptr_t)helper_be_stq_mmu, + static void * const qemu_st_helpers[16] = { + [MO_UB] = helper_ret_stb_mmu, + [MO_LEUW] = helper_le_stw_mmu, + [MO_LEUL] = helper_le_stl_mmu, + [MO_LEQ] = helper_le_stq_mmu, + [MO_BEUW] = helper_be_stw_mmu, + [MO_BEUL] = helper_be_stl_mmu, + [MO_BEQ] = helper_be_stq_mmu, }; int i; TCGReg ra; - uintptr_t tramp; for (i = 0; i < 16; ++i) { - if (qemu_ld_helpers[i] == 0) { + if (qemu_ld_helpers[i] == NULL) { continue; } /* May as well align the trampoline. */ - tramp = (uintptr_t)s->code_ptr; - while (tramp & 15) { + while ((uintptr_t)s->code_ptr & 15) { tcg_out_nop(s); - tramp += 4; } - qemu_ld_trampoline[i] = tramp; + qemu_ld_trampoline[i] = s->code_ptr; if (SPARC64 || TARGET_LONG_BITS == 32) { ra = TCG_REG_O3; @@ -810,22 +809,20 @@ static void build_trampolines(TCGContext *s) /* Set the env operand. */ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O0, TCG_AREG0); /* Tail call. */ - tcg_out_calli(s, qemu_ld_helpers[i]); + tcg_out_call_nodelay(s, qemu_ld_helpers[i]); tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O7, ra); } for (i = 0; i < 16; ++i) { - if (qemu_st_helpers[i] == 0) { + if (qemu_st_helpers[i] == NULL) { continue; } /* May as well align the trampoline. */ - tramp = (uintptr_t)s->code_ptr; - while (tramp & 15) { + while ((uintptr_t)s->code_ptr & 15) { tcg_out_nop(s); - tramp += 4; } - qemu_st_trampoline[i] = tramp; + qemu_st_trampoline[i] = s->code_ptr; if (SPARC64) { ra = TCG_REG_O4; @@ -859,7 +856,7 @@ static void build_trampolines(TCGContext *s) /* Set the env operand. */ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O0, TCG_AREG0); /* Tail call. */ - tcg_out_calli(s, qemu_st_helpers[i]); + tcg_out_call_nodelay(s, qemu_st_helpers[i]); tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O7, ra); } } @@ -1005,8 +1002,8 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, #ifdef CONFIG_SOFTMMU TCGMemOp s_bits = memop & MO_SIZE; TCGReg addrz, param; - uintptr_t func; - uint32_t *label_ptr; + tcg_insn_unit *func; + tcg_insn_unit *label_ptr; addrz = tcg_out_tlb_load(s, addr, memi, s_bits, offsetof(CPUTLBEntry, addr_read)); @@ -1016,7 +1013,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, over the TLB Miss case. */ /* beq,a,pt %[xi]cc, label0 */ - label_ptr = (uint32_t *)s->code_ptr; + label_ptr = s->code_ptr; tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0); /* delay slot */ @@ -1038,8 +1035,8 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, } else { func = qemu_ld_trampoline[memop]; } - assert(func != 0); - tcg_out_calli(s, func); + assert(func != NULL); + tcg_out_call_nodelay(s, func); /* delay slot */ tcg_out_movi(s, TCG_TYPE_I32, param, memi); @@ -1067,7 +1064,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, } } - *label_ptr |= INSN_OFF19((uintptr_t)s->code_ptr - (uintptr_t)label_ptr); + *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr)); #else if (SPARC64 && TARGET_LONG_BITS == 32) { tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL); @@ -1085,8 +1082,8 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, #ifdef CONFIG_SOFTMMU TCGMemOp s_bits = memop & MO_SIZE; TCGReg addrz, param; - uintptr_t func; - uint32_t *label_ptr; + tcg_insn_unit *func; + tcg_insn_unit *label_ptr; addrz = tcg_out_tlb_load(s, addr, memi, s_bits, offsetof(CPUTLBEntry, addr_write)); @@ -1094,7 +1091,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, /* The fast path is exactly one insn. Thus we can perform the entire TLB Hit in the (annulled) delay slot of the branch over TLB Miss. */ /* beq,a,pt %[xi]cc, label0 */ - label_ptr = (uint32_t *)s->code_ptr; + label_ptr = s->code_ptr; tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT | (TARGET_LONG_BITS == 64 ? BPCC_XCC : BPCC_ICC), 0); /* delay slot */ @@ -1115,12 +1112,12 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, tcg_out_mov(s, TCG_TYPE_REG, param++, data); func = qemu_st_trampoline[memop]; - assert(func != 0); - tcg_out_calli(s, func); + assert(func != NULL); + tcg_out_call_nodelay(s, func); /* delay slot */ tcg_out_movi(s, TCG_TYPE_REG, param, memi); - *label_ptr |= INSN_OFF19((uintptr_t)s->code_ptr - (uintptr_t)label_ptr); + *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr)); #else if (SPARC64 && TARGET_LONG_BITS == 32) { tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL); @@ -1159,26 +1156,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_goto_tb: if (s->tb_jmp_offset) { /* direct jump method */ - uint32_t old_insn = *(uint32_t *)s->code_ptr; - s->tb_jmp_offset[a0] = s->code_ptr - s->code_buf; + s->tb_jmp_offset[a0] = tcg_current_code_size(s); /* Make sure to preserve links during retranslation. */ - tcg_out32(s, CALL | (old_insn & ~INSN_OP(-1))); + tcg_out32(s, CALL | (*s->code_ptr & ~INSN_OP(-1))); } else { /* indirect jump method */ tcg_out_ld_ptr(s, TCG_REG_T1, (uintptr_t)(s->tb_next + a0)); tcg_out_arithi(s, TCG_REG_G0, TCG_REG_T1, 0, JMPL); } tcg_out_nop(s); - s->tb_next_offset[a0] = s->code_ptr - s->code_buf; - break; - case INDEX_op_call: - if (const_args[0]) { - tcg_out_calli(s, a0); - } else { - tcg_out_arithi(s, TCG_REG_O7, a0, 0, JMPL); - } - /* delay slot */ - tcg_out_nop(s); + s->tb_next_offset[a0] = tcg_current_code_size(s); break; case INDEX_op_br: tcg_out_bpcc(s, COND_A, BPCC_PT, a0); @@ -1373,13 +1360,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_arithc(s, a0, TCG_REG_G0, a1, const_args[1], c); break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_mov_i64: - case INDEX_op_mov_i32: + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ case INDEX_op_movi_i64: - case INDEX_op_movi_i32: - /* Always implemented with tcg_out_mov/i, never with tcg_out_op. */ + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: - /* Opcode not implemented. */ tcg_abort(); } } @@ -1387,11 +1373,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "ri" } }, { INDEX_op_br, { } }, - { INDEX_op_mov_i32, { "r", "r" } }, - { INDEX_op_movi_i32, { "r" } }, { INDEX_op_ld8u_i32, { "r", "r" } }, { INDEX_op_ld8s_i32, { "r", "r" } }, { INDEX_op_ld16u_i32, { "r", "r" } }, @@ -1428,8 +1411,6 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rJ" } }, { INDEX_op_muls2_i32, { "r", "r", "rZ", "rJ" } }, - { INDEX_op_mov_i64, { "R", "R" } }, - { INDEX_op_movi_i64, { "R" } }, { INDEX_op_ld8u_i64, { "R", "r" } }, { INDEX_op_ld8s_i64, { "R", "r" } }, { INDEX_op_ld16u_i64, { "R", "r" } }, diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index 3a903dbfd0..473bfc71fd 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -26,6 +26,7 @@ #define TCG_TARGET_REG_BITS 64 +#define TCG_TARGET_INSN_UNIT_SIZE 4 #define TCG_TARGET_NB_REGS 32 typedef enum { diff --git a/tcg/tcg-be-ldst.h b/tcg/tcg-be-ldst.h index ad94c0ca51..49b3de61ea 100644 --- a/tcg/tcg-be-ldst.h +++ b/tcg/tcg-be-ldst.h @@ -31,8 +31,8 @@ typedef struct TCGLabelQemuLdst { TCGReg datalo_reg; /* reg index for low word to be loaded or stored */ TCGReg datahi_reg; /* reg index for high word to be loaded or stored */ int mem_index; /* soft MMU memory index */ - uint8_t *raddr; /* gen code addr of the next IR of qemu_ld/st IR */ - uint8_t *label_ptr[2]; /* label pointers to be updated */ + tcg_insn_unit *raddr; /* gen code addr of the next IR of qemu_ld/st IR */ + tcg_insn_unit *label_ptr[2]; /* label pointers to be updated */ } TCGLabelQemuLdst; typedef struct TCGBackendData { diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 6dbbb38838..bdd0139482 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -390,11 +390,7 @@ static inline int tcg_gen_sizemask(int n, int is_64bit, int is_signed) static inline void tcg_gen_helperN(void *func, int flags, int sizemask, TCGArg ret, int nargs, TCGArg *args) { - TCGv_ptr fn; - fn = tcg_const_ptr(func); - tcg_gen_callN(&tcg_ctx, fn, flags, sizemask, ret, - nargs, args); - tcg_temp_free_ptr(fn); + tcg_gen_callN(&tcg_ctx, func, flags, sizemask, ret, nargs, args); } /* Note: Both tcg_gen_helper32() and tcg_gen_helper64() are currently @@ -405,29 +401,23 @@ static inline void tcg_gen_helperN(void *func, int flags, int sizemask, static inline void tcg_gen_helper32(void *func, int sizemask, TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) { - TCGv_ptr fn; TCGArg args[2]; - fn = tcg_const_ptr(func); args[0] = GET_TCGV_I32(a); args[1] = GET_TCGV_I32(b); - tcg_gen_callN(&tcg_ctx, fn, + tcg_gen_callN(&tcg_ctx, func, TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_SIDE_EFFECTS, sizemask, GET_TCGV_I32(ret), 2, args); - tcg_temp_free_ptr(fn); } static inline void tcg_gen_helper64(void *func, int sizemask, TCGv_i64 ret, TCGv_i64 a, TCGv_i64 b) { - TCGv_ptr fn; TCGArg args[2]; - fn = tcg_const_ptr(func); args[0] = GET_TCGV_I64(a); args[1] = GET_TCGV_I64(b); - tcg_gen_callN(&tcg_ctx, fn, + tcg_gen_callN(&tcg_ctx, func, TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_SIDE_EFFECTS, sizemask, GET_TCGV_I64(ret), 2, args); - tcg_temp_free_ptr(fn); } /* 32 bit ops */ diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index adb6ce1bb9..71ba64ac16 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -40,7 +40,7 @@ DEF(discard, 1, 0, 0, TCG_OPF_NOT_PRESENT) DEF(set_label, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_NOT_PRESENT) /* variable number of parameters */ -DEF(call, 0, 1, 2, TCG_OPF_CALL_CLOBBER) +DEF(call, 0, 0, 3, TCG_OPF_CALL_CLOBBER | TCG_OPF_NOT_PRESENT) DEF(br, 0, 0, 1, TCG_OPF_BB_END) @@ -51,8 +51,8 @@ DEF(br, 0, 0, 1, TCG_OPF_BB_END) # define IMPL64 TCG_OPF_64BIT #endif -DEF(mov_i32, 1, 1, 0, 0) -DEF(movi_i32, 1, 0, 1, 0) +DEF(mov_i32, 1, 1, 0, TCG_OPF_NOT_PRESENT) +DEF(movi_i32, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(setcond_i32, 1, 2, 1, 0) DEF(movcond_i32, 1, 4, 1, IMPL(TCG_TARGET_HAS_movcond_i32)) /* load/store */ @@ -110,8 +110,8 @@ DEF(eqv_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_eqv_i32)) DEF(nand_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_nand_i32)) DEF(nor_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_nor_i32)) -DEF(mov_i64, 1, 1, 0, IMPL64) -DEF(movi_i64, 1, 0, 1, IMPL64) +DEF(mov_i64, 1, 1, 0, TCG_OPF_64BIT | TCG_OPF_NOT_PRESENT) +DEF(movi_i64, 1, 0, 1, TCG_OPF_64BIT | TCG_OPF_NOT_PRESENT) DEF(setcond_i64, 1, 2, 1, IMPL64) DEF(movcond_i64, 1, 4, 1, IMPL64 | IMPL(TCG_TARGET_HAS_movcond_i64)) /* load/store */ @@ -65,7 +65,7 @@ /* Forward declarations for functions declared in tcg-target.c and used here. */ static void tcg_target_init(TCGContext *s); static void tcg_target_qemu_prologue(TCGContext *s); -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend); /* The CIE and FDE header definitions will be common to all hosts. */ @@ -101,6 +101,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args); static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1, intptr_t arg2); +static void tcg_out_call(TCGContext *s, tcg_insn_unit *target); static int tcg_target_const_match(tcg_target_long val, TCGType type, const TCGArgConstraint *arg_ct); static void tcg_out_tb_init(TCGContext *s); @@ -117,35 +118,87 @@ const size_t tcg_op_defs_max = ARRAY_SIZE(tcg_op_defs); static TCGRegSet tcg_target_available_regs[2]; static TCGRegSet tcg_target_call_clobber_regs; +#if TCG_TARGET_INSN_UNIT_SIZE == 1 static inline void tcg_out8(TCGContext *s, uint8_t v) { *s->code_ptr++ = v; } +static inline void tcg_patch8(tcg_insn_unit *p, uint8_t v) +{ + *p = v; +} +#endif + +#if TCG_TARGET_INSN_UNIT_SIZE <= 2 static inline void tcg_out16(TCGContext *s, uint16_t v) { - uint8_t *p = s->code_ptr; - *(uint16_t *)p = v; - s->code_ptr = p + 2; + if (TCG_TARGET_INSN_UNIT_SIZE == 2) { + *s->code_ptr++ = v; + } else { + tcg_insn_unit *p = s->code_ptr; + memcpy(p, &v, sizeof(v)); + s->code_ptr = p + (2 / TCG_TARGET_INSN_UNIT_SIZE); + } } +static inline void tcg_patch16(tcg_insn_unit *p, uint16_t v) +{ + if (TCG_TARGET_INSN_UNIT_SIZE == 2) { + *p = v; + } else { + memcpy(p, &v, sizeof(v)); + } +} +#endif + +#if TCG_TARGET_INSN_UNIT_SIZE <= 4 static inline void tcg_out32(TCGContext *s, uint32_t v) { - uint8_t *p = s->code_ptr; - *(uint32_t *)p = v; - s->code_ptr = p + 4; + if (TCG_TARGET_INSN_UNIT_SIZE == 4) { + *s->code_ptr++ = v; + } else { + tcg_insn_unit *p = s->code_ptr; + memcpy(p, &v, sizeof(v)); + s->code_ptr = p + (4 / TCG_TARGET_INSN_UNIT_SIZE); + } } +static inline void tcg_patch32(tcg_insn_unit *p, uint32_t v) +{ + if (TCG_TARGET_INSN_UNIT_SIZE == 4) { + *p = v; + } else { + memcpy(p, &v, sizeof(v)); + } +} +#endif + +#if TCG_TARGET_INSN_UNIT_SIZE <= 8 static inline void tcg_out64(TCGContext *s, uint64_t v) { - uint8_t *p = s->code_ptr; - *(uint64_t *)p = v; - s->code_ptr = p + 8; + if (TCG_TARGET_INSN_UNIT_SIZE == 8) { + *s->code_ptr++ = v; + } else { + tcg_insn_unit *p = s->code_ptr; + memcpy(p, &v, sizeof(v)); + s->code_ptr = p + (8 / TCG_TARGET_INSN_UNIT_SIZE); + } } +static inline void tcg_patch64(tcg_insn_unit *p, uint64_t v) +{ + if (TCG_TARGET_INSN_UNIT_SIZE == 8) { + *p = v; + } else { + memcpy(p, &v, sizeof(v)); + } +} +#endif + /* label relocation processing */ -static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, +static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type, int label_index, intptr_t addend) { TCGLabel *l; @@ -168,23 +221,20 @@ static void tcg_out_reloc(TCGContext *s, uint8_t *code_ptr, int type, } } -static void tcg_out_label(TCGContext *s, int label_index, void *ptr) +static void tcg_out_label(TCGContext *s, int label_index, tcg_insn_unit *ptr) { - TCGLabel *l; - TCGRelocation *r; + TCGLabel *l = &s->labels[label_index]; intptr_t value = (intptr_t)ptr; + TCGRelocation *r; - l = &s->labels[label_index]; - if (l->has_value) { - tcg_abort(); - } - r = l->u.first_reloc; - while (r != NULL) { + assert(!l->has_value); + + for (r = l->u.first_reloc; r != NULL; r = r->next) { patch_reloc(r->ptr, r->type, value, r->addend); - r = r->next; } + l->has_value = 1; - l->u.value = value; + l->u.value_ptr = ptr; } int gen_new_label(void) @@ -339,7 +389,7 @@ void tcg_prologue_init(TCGContext *s) #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { - size_t size = s->code_ptr - s->code_buf; + size_t size = tcg_current_code_size(s); qemu_log("PROLOGUE: [size=%zu]\n", size); log_disas(s->code_buf, size); qemu_log("\n"); @@ -656,7 +706,7 @@ int tcg_check_temp_count(void) /* Note: we convert the 64 bit args to 32 bit and do some alignment and endian swap. Maybe it would be better to do the alignment and endian swap in tcg_reg_alloc_call(). */ -void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, +void tcg_gen_callN(TCGContext *s, void *func, unsigned int flags, int sizemask, TCGArg ret, int nargs, TCGArg *args) { int i; @@ -783,11 +833,10 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, *s->gen_opparam_ptr++ = args[i]; real_args++; } - *s->gen_opparam_ptr++ = GET_TCGV_PTR(func); - + *s->gen_opparam_ptr++ = (uintptr_t)func; *s->gen_opparam_ptr++ = flags; - *nparam = (nb_rets << 16) | (real_args + 1); + *nparam = (nb_rets << 16) | real_args; /* total parameters, needed to go backward in the instruction stream */ *s->gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; @@ -1194,49 +1243,21 @@ void tcg_dump_ops(TCGContext *s) nb_iargs = arg & 0xffff; nb_cargs = def->nb_cargs; - qemu_log(" %s ", def->name); - - /* function name */ - qemu_log("%s", - tcg_get_arg_str_idx(s, buf, sizeof(buf), - args[nb_oargs + nb_iargs - 1])); - /* flags */ - qemu_log(",$0x%" TCG_PRIlx, args[nb_oargs + nb_iargs]); - /* nb out args */ - qemu_log(",$%d", nb_oargs); - for(i = 0; i < nb_oargs; i++) { - qemu_log(","); - qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), + /* function name, flags, out args */ + qemu_log(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name, + tcg_find_helper(s, args[nb_oargs + nb_iargs]), + args[nb_oargs + nb_iargs + 1], nb_oargs); + for (i = 0; i < nb_oargs; i++) { + qemu_log(",%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), args[i])); } - for(i = 0; i < (nb_iargs - 1); i++) { - qemu_log(","); - if (args[nb_oargs + i] == TCG_CALL_DUMMY_ARG) { - qemu_log("<dummy>"); - } else { - qemu_log("%s", tcg_get_arg_str_idx(s, buf, sizeof(buf), - args[nb_oargs + i])); - } - } - } else if (c == INDEX_op_movi_i32 || c == INDEX_op_movi_i64) { - tcg_target_ulong val; - const char *name; - - nb_oargs = def->nb_oargs; - nb_iargs = def->nb_iargs; - nb_cargs = def->nb_cargs; - qemu_log(" %s %s,$", def->name, - tcg_get_arg_str_idx(s, buf, sizeof(buf), args[0])); - val = args[1]; - name = tcg_find_helper(s, val); - if (name) { - qemu_log("%s", name); - } else { - if (c == INDEX_op_movi_i32) { - qemu_log("0x%x", (uint32_t)val); - } else { - qemu_log("0x%" PRIx64 , (uint64_t)val); + for (i = 0; i < nb_iargs; i++) { + TCGArg arg = args[nb_oargs + i]; + const char *t = "<dummy>"; + if (arg != TCG_CALL_DUMMY_ARG) { + t = tcg_get_arg_str_idx(s, buf, sizeof(buf), arg); } + qemu_log(",%s", t); } } else { qemu_log(" %s ", def->name); @@ -1499,9 +1520,9 @@ static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps, temporaries are removed. */ static void tcg_liveness_analysis(TCGContext *s) { - int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops; + int i, op_index, nb_args, nb_iargs, nb_oargs, nb_ops; TCGOpcode op, op_new, op_new2; - TCGArg *args; + TCGArg *args, arg; const TCGOpDef *def; uint8_t *dead_temps, *mem_temps; uint16_t dead_args; @@ -1531,15 +1552,15 @@ static void tcg_liveness_analysis(TCGContext *s) nb_args = args[-1]; args -= nb_args; - nb_iargs = args[0] & 0xffff; - nb_oargs = args[0] >> 16; - args++; - call_flags = args[nb_oargs + nb_iargs]; + arg = *args++; + nb_iargs = arg & 0xffff; + nb_oargs = arg >> 16; + call_flags = args[nb_oargs + nb_iargs + 1]; /* pure functions can be removed if their result is not used */ if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { - for(i = 0; i < nb_oargs; i++) { + for (i = 0; i < nb_oargs; i++) { arg = args[i]; if (!dead_temps[arg] || mem_temps[arg]) { goto do_not_remove_call; @@ -1553,7 +1574,7 @@ static void tcg_liveness_analysis(TCGContext *s) /* output args are dead */ dead_args = 0; sync_args = 0; - for(i = 0; i < nb_oargs; i++) { + for (i = 0; i < nb_oargs; i++) { arg = args[i]; if (dead_temps[arg]) { dead_args |= (1 << i); @@ -1576,7 +1597,7 @@ static void tcg_liveness_analysis(TCGContext *s) } /* input args are live */ - for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) { + for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { arg = args[i]; if (arg != TCG_CALL_DUMMY_ARG) { if (dead_temps[arg]) { @@ -2075,13 +2096,15 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, { TCGRegSet allocated_regs; TCGTemp *ts, *ots; - const TCGArgConstraint *arg_ct, *oarg_ct; + TCGType otype, itype; tcg_regset_set(allocated_regs, s->reserved_regs); ots = &s->temps[args[0]]; ts = &s->temps[args[1]]; - oarg_ct = &def->args_ct[0]; - arg_ct = &def->args_ct[1]; + + /* Note that otype != itype for no-op truncation. */ + otype = ots->type; + itype = ts->type; /* If the source value is not in a register, and we're going to be forced to have it in a register in order to perform the copy, @@ -2089,12 +2112,13 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, we don't have to reload SOURCE the next time it is used. */ if (((NEED_SYNC_ARG(0) || ots->fixed_reg) && ts->val_type != TEMP_VAL_REG) || ts->val_type == TEMP_VAL_MEM) { - ts->reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); + ts->reg = tcg_reg_alloc(s, tcg_target_available_regs[itype], + allocated_regs); if (ts->val_type == TEMP_VAL_MEM) { - tcg_out_ld(s, ts->type, ts->reg, ts->mem_reg, ts->mem_offset); + tcg_out_ld(s, itype, ts->reg, ts->mem_reg, ts->mem_offset); ts->mem_coherent = 1; } else if (ts->val_type == TEMP_VAL_CONST) { - tcg_out_movi(s, ts->type, ts->reg, ts->val); + tcg_out_movi(s, itype, ts->reg, ts->val); } s->reg_to_temp[ts->reg] = args[1]; ts->val_type = TEMP_VAL_REG; @@ -2109,7 +2133,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, if (!ots->mem_allocated) { temp_allocate_frame(s, args[0]); } - tcg_out_st(s, ots->type, ts->reg, ots->mem_reg, ots->mem_offset); + tcg_out_st(s, otype, ts->reg, ots->mem_reg, ots->mem_offset); if (IS_DEAD_ARG(1)) { temp_dead(s, args[1]); } @@ -2137,9 +2161,10 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def, /* When allocating a new register, make sure to not spill the input one. */ tcg_regset_set_reg(allocated_regs, ts->reg); - ots->reg = tcg_reg_alloc(s, oarg_ct->u.regs, allocated_regs); + ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype], + allocated_regs); } - tcg_out_mov(s, ots->type, ots->reg, ts->reg); + tcg_out_mov(s, otype, ots->reg, ts->reg); } ots->val_type = TEMP_VAL_REG; ots->mem_coherent = 0; @@ -2323,26 +2348,27 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, uint16_t dead_args, uint8_t sync_args) { int nb_iargs, nb_oargs, flags, nb_regs, i, reg, nb_params; - TCGArg arg, func_arg; + TCGArg arg; TCGTemp *ts; intptr_t stack_offset; size_t call_stack_size; - uintptr_t func_addr; - int const_func_arg, allocate_args; + tcg_insn_unit *func_addr; + int allocate_args; TCGRegSet allocated_regs; - const TCGArgConstraint *arg_ct; arg = *args++; nb_oargs = arg >> 16; nb_iargs = arg & 0xffff; - nb_params = nb_iargs - 1; + nb_params = nb_iargs; - flags = args[nb_oargs + nb_iargs]; + func_addr = (tcg_insn_unit *)(intptr_t)args[nb_oargs + nb_iargs]; + flags = args[nb_oargs + nb_iargs + 1]; nb_regs = ARRAY_SIZE(tcg_target_call_iarg_regs); - if (nb_regs > nb_params) + if (nb_regs > nb_params) { nb_regs = nb_params; + } /* assign stack slots first */ call_stack_size = (nb_params - nb_regs) * sizeof(tcg_target_long); @@ -2410,40 +2436,6 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, } } - /* assign function address */ - func_arg = args[nb_oargs + nb_iargs - 1]; - arg_ct = &def->args_ct[0]; - ts = &s->temps[func_arg]; - func_addr = ts->val; - const_func_arg = 0; - if (ts->val_type == TEMP_VAL_MEM) { - reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); - tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset); - func_arg = reg; - tcg_regset_set_reg(allocated_regs, reg); - } else if (ts->val_type == TEMP_VAL_REG) { - reg = ts->reg; - if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) { - reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); - tcg_out_mov(s, ts->type, reg, ts->reg); - } - func_arg = reg; - tcg_regset_set_reg(allocated_regs, reg); - } else if (ts->val_type == TEMP_VAL_CONST) { - if (tcg_target_const_match(func_addr, ts->type, arg_ct)) { - const_func_arg = 1; - func_arg = func_addr; - } else { - reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs); - tcg_out_movi(s, ts->type, reg, func_addr); - func_arg = reg; - tcg_regset_set_reg(allocated_regs, reg); - } - } else { - tcg_abort(); - } - - /* mark dead temporaries and free the associated registers */ for(i = nb_oargs; i < nb_iargs + nb_oargs; i++) { if (IS_DEAD_ARG(i)) { @@ -2468,7 +2460,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def, save_globals(s, allocated_regs); } - tcg_out_op(s, opc, &func_arg, &const_func_arg); + tcg_out_call(s, func_addr); /* assign output registers and emit moves if needed */ for(i = 0; i < nb_oargs; i++) { @@ -2518,7 +2510,8 @@ static void dump_op_count(void) #endif -static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, +static inline int tcg_gen_code_common(TCGContext *s, + tcg_insn_unit *gen_code_buf, long search_pc) { TCGOpcode opc; @@ -2633,7 +2626,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, } args += def->nb_args; next: - if (search_pc >= 0 && search_pc < s->code_ptr - gen_code_buf) { + if (search_pc >= 0 && search_pc < tcg_current_code_size(s)) { return op_index; } op_index++; @@ -2647,7 +2640,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, return -1; } -int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) +int tcg_gen_code(TCGContext *s, tcg_insn_unit *gen_code_buf) { #ifdef CONFIG_PROFILER { @@ -2666,16 +2659,17 @@ int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) tcg_gen_code_common(s, gen_code_buf, -1); /* flush instruction cache */ - flush_icache_range((uintptr_t)gen_code_buf, (uintptr_t)s->code_ptr); + flush_icache_range((uintptr_t)s->code_buf, (uintptr_t)s->code_ptr); - return s->code_ptr - gen_code_buf; + return tcg_current_code_size(s); } /* Return the index of the micro operation such as the pc after is < offset bytes from the start of the TB. The contents of gen_code_buf must not be changed, though writing the same values is ok. Return -1 if not found. */ -int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) +int tcg_gen_code_search_pc(TCGContext *s, tcg_insn_unit *gen_code_buf, + long offset) { return tcg_gen_code_common(s, gen_code_buf, offset); } @@ -146,10 +146,25 @@ typedef enum TCGOpcode { #define tcg_regset_andnot(d, a, b) (d) = (a) & ~(b) #define tcg_regset_not(d, a) (d) = ~(a) +#ifndef TCG_TARGET_INSN_UNIT_SIZE +# error "Missing TCG_TARGET_INSN_UNIT_SIZE" +#elif TCG_TARGET_INSN_UNIT_SIZE == 1 +typedef uint8_t tcg_insn_unit; +#elif TCG_TARGET_INSN_UNIT_SIZE == 2 +typedef uint16_t tcg_insn_unit; +#elif TCG_TARGET_INSN_UNIT_SIZE == 4 +typedef uint32_t tcg_insn_unit; +#elif TCG_TARGET_INSN_UNIT_SIZE == 8 +typedef uint64_t tcg_insn_unit; +#else +/* The port better have done this. */ +#endif + + typedef struct TCGRelocation { struct TCGRelocation *next; int type; - uint8_t *ptr; + tcg_insn_unit *ptr; intptr_t addend; } TCGRelocation; @@ -157,6 +172,7 @@ typedef struct TCGLabel { int has_value; union { uintptr_t value; + tcg_insn_unit *value_ptr; TCGRelocation *first_reloc; } u; } TCGLabel; @@ -464,7 +480,7 @@ struct TCGContext { int nb_temps; /* goto_tb support */ - uint8_t *code_buf; + tcg_insn_unit *code_buf; uintptr_t *tb_next; uint16_t *tb_next_offset; uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */ @@ -485,7 +501,7 @@ struct TCGContext { intptr_t frame_end; int frame_reg; - uint8_t *code_ptr; + tcg_insn_unit *code_ptr; TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */ TCGTempSet free_temps[TCG_TYPE_COUNT * 2]; @@ -524,14 +540,17 @@ struct TCGContext { uint16_t gen_opc_icount[OPC_BUF_SIZE]; uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; - /* Code generation */ + /* Code generation. Note that we specifically do not use tcg_insn_unit + here, because there's too much arithmetic throughout that relies + on addition and subtraction working on bytes. Rely on the GCC + extension that allows arithmetic on void*. */ int code_gen_max_blocks; - uint8_t *code_gen_prologue; - uint8_t *code_gen_buffer; + void *code_gen_prologue; + void *code_gen_buffer; size_t code_gen_buffer_size; /* threshold to flush the translated code buffer */ size_t code_gen_buffer_max_size; - uint8_t *code_gen_ptr; + void *code_gen_ptr; TBContext tb_ctx; @@ -566,8 +585,9 @@ void tcg_context_init(TCGContext *s); void tcg_prologue_init(TCGContext *s); void tcg_func_start(TCGContext *s); -int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf); -int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset); +int tcg_gen_code(TCGContext *s, tcg_insn_unit *gen_code_buf); +int tcg_gen_code_search_pc(TCGContext *s, tcg_insn_unit *gen_code_buf, + long offset); void tcg_set_frame(TCGContext *s, int reg, intptr_t start, intptr_t size); @@ -705,7 +725,7 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs); #define tcg_temp_free_ptr(T) tcg_temp_free_i64(TCGV_PTR_TO_NAT(T)) #endif -void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, +void tcg_gen_callN(TCGContext *s, void *func, unsigned int flags, int sizemask, TCGArg ret, int nargs, TCGArg *args); void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, @@ -724,6 +744,51 @@ TCGv_i32 tcg_const_local_i32(int32_t val); TCGv_i64 tcg_const_local_i64(int64_t val); /** + * tcg_ptr_byte_diff + * @a, @b: addresses to be differenced + * + * There are many places within the TCG backends where we need a byte + * difference between two pointers. While this can be accomplished + * with local casting, it's easy to get wrong -- especially if one is + * concerned with the signedness of the result. + * + * This version relies on GCC's void pointer arithmetic to get the + * correct result. + */ + +static inline ptrdiff_t tcg_ptr_byte_diff(void *a, void *b) +{ + return a - b; +} + +/** + * tcg_pcrel_diff + * @s: the tcg context + * @target: address of the target + * + * Produce a pc-relative difference, from the current code_ptr + * to the destination address. + */ + +static inline ptrdiff_t tcg_pcrel_diff(TCGContext *s, void *target) +{ + return tcg_ptr_byte_diff(target, s->code_ptr); +} + +/** + * tcg_current_code_size + * @s: the tcg context + * + * Compute the current code size within the translation block. + * This is used to fill in qemu's data structures for goto_tb. + */ + +static inline size_t tcg_current_code_size(TCGContext *s) +{ + return tcg_ptr_byte_diff(s->code_ptr, s->code_buf); +} + +/** * tcg_qemu_tb_exec: * @env: CPUArchState * for the CPU * @tb_ptr: address of generated code for the TB to execute diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c index 47c0b85d95..9b39231c15 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.c @@ -59,12 +59,8 @@ static const TCGTargetOpDef tcg_target_op_defs[] = { { INDEX_op_exit_tb, { NULL } }, { INDEX_op_goto_tb, { NULL } }, - { INDEX_op_call, { RI } }, { INDEX_op_br, { NULL } }, - { INDEX_op_mov_i32, { R, R } }, - { INDEX_op_movi_i32, { R } }, - { INDEX_op_ld8u_i32, { R, R } }, { INDEX_op_ld8s_i32, { R, R } }, { INDEX_op_ld16u_i32, { R, R } }, @@ -141,9 +137,6 @@ static const TCGTargetOpDef tcg_target_op_defs[] = { #endif #if TCG_TARGET_REG_BITS == 64 - { INDEX_op_mov_i64, { R, R } }, - { INDEX_op_movi_i64, { R } }, - { INDEX_op_ld8u_i64, { R, R } }, { INDEX_op_ld8s_i64, { R, R } }, { INDEX_op_ld16u_i64, { R, R } }, @@ -371,14 +364,18 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { }; #endif -static void patch_reloc(uint8_t *code_ptr, int type, +static void patch_reloc(tcg_insn_unit *code_ptr, int type, intptr_t value, intptr_t addend) { /* tcg_out_reloc always uses the same type, addend. */ assert(type == sizeof(tcg_target_long)); assert(addend == 0); assert(value != 0); - *(tcg_target_long *)code_ptr = value; + if (TCG_TARGET_REG_BITS == 32) { + tcg_patch32(code_ptr, value); + } else { + tcg_patch64(code_ptr, value); + } } /* Parse target specific constraints. */ @@ -413,8 +410,11 @@ void tci_disas(uint8_t opc) /* Write value (native size). */ static void tcg_out_i(TCGContext *s, tcg_target_ulong v) { - *(tcg_target_ulong *)s->code_ptr = v; - s->code_ptr += sizeof(tcg_target_ulong); + if (TCG_TARGET_REG_BITS == 32) { + tcg_out32(s, v); + } else { + tcg_out64(s, v); + } } /* Write opcode. */ @@ -542,6 +542,11 @@ static void tcg_out_movi(TCGContext *s, TCGType type, old_code_ptr[1] = s->code_ptr - old_code_ptr; } +static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *arg) +{ + tcg_out_ri(s, 1, (uintptr_t)arg); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args) { @@ -557,21 +562,18 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, if (s->tb_jmp_offset) { /* Direct jump method. */ assert(args[0] < ARRAY_SIZE(s->tb_jmp_offset)); - s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->tb_jmp_offset[args[0]] = tcg_current_code_size(s); tcg_out32(s, 0); } else { /* Indirect jump method. */ TODO(); } assert(args[0] < ARRAY_SIZE(s->tb_next_offset)); - s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + s->tb_next_offset[args[0]] = tcg_current_code_size(s); break; case INDEX_op_br: tci_out_label(s, args[0]); break; - case INDEX_op_call: - tcg_out_ri(s, const_args[0], args[0]); - break; case INDEX_op_setcond_i32: tcg_out_r(s, args[0]); tcg_out_r(s, args[1]); @@ -596,9 +598,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out8(s, args[3]); /* condition */ break; #endif - case INDEX_op_movi_i32: - TODO(); /* Handled by tcg_out_movi? */ - break; case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld16u_i32: @@ -654,10 +653,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, break; #if TCG_TARGET_REG_BITS == 64 - case INDEX_op_mov_i64: - case INDEX_op_movi_i64: - TODO(); - break; case INDEX_op_add_i64: case INDEX_op_sub_i64: case INDEX_op_mul_i64: @@ -825,11 +820,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out_i(s, *args); #endif break; - case INDEX_op_end: - TODO(); - break; + case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ + case INDEX_op_mov_i64: + case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ + case INDEX_op_movi_i64: + case INDEX_op_call: /* Always emitted via tcg_out_call. */ default: - fprintf(stderr, "Missing: %s\n", tcg_op_defs[opc].name); tcg_abort(); } old_code_ptr[1] = s->code_ptr - old_code_ptr; diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 37719e875c..0be5acdb81 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -43,6 +43,7 @@ #include "config-host.h" #define TCG_TARGET_INTERPRETER 1 +#define TCG_TARGET_INSN_UNIT_SIZE 1 #if UINTPTR_MAX == UINT32_MAX # define TCG_TARGET_REG_BITS 32 diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 073dc7a2d3..c4af131a66 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -233,6 +233,10 @@ echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG", $QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io +echo -e 'qemu-io ide0-hd0 "write -P 0x33 0 4k"\ncommit ide0-hd0' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io + +$QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 01b0384472..31e329e893 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -358,4 +358,14 @@ wrote 4096/4096 bytes at offset 0 read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index ca5aa16ff7..26a2fd3e0e 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -104,6 +104,13 @@ truncate -s 10M $TEST_IMG _img_info echo +echo "=== Converting to streamOptimized from image with small cluster size===" +TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 IMGOPTS="cluster_size=4096" _make_test_img 1G +$QEMU_IO -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io +$QEMU_IO -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io +$QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2" "$TEST_IMG" 2>&1 + +echo echo "=== Testing version 3 ===" _use_sample_img iotest-version3.vmdk.bz2 _img_info diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 3371c867bb..eba0dedda0 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -2046,10 +2046,18 @@ RW 12582912 VMFS "dummy.IMGFMT" 1 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes +=== Converting to streamOptimized from image with small cluster size=== +Formatting 'TEST_DIR/t.vmdk.IMGFMT', fmt=IMGFMT size=1073741824 +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 10240 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + === Testing version 3 === image: TEST_DIR/iotest-version3.IMGFMT file format: IMGFMT virtual size: 1.0G (1073741824 bytes) +cluster_size: 65536 === Testing 4TB monolithicFlat creation and IO === Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 index 33c8dc410a..56cd6f89b7 100755 --- a/tests/qemu-iotests/085 +++ b/tests/qemu-iotests/085 @@ -30,10 +30,6 @@ echo "QA output created by $seq" here=`pwd` status=1 # failure is the default! -qemu_pid= - -QMP_IN="${TEST_DIR}/qmp-in-$$" -QMP_OUT="${TEST_DIR}/qmp-out-$$" snapshot_virt0="snapshot-v0.qcow2" snapshot_virt1="snapshot-v1.qcow2" @@ -42,10 +38,7 @@ MAX_SNAPSHOTS=10 _cleanup() { - kill -KILL ${qemu_pid} - wait ${qemu_pid} 2>/dev/null # silent kill - - rm -f "${QMP_IN}" "${QMP_OUT}" + _cleanup_qemu for i in $(seq 1 ${MAX_SNAPSHOTS}) do rm -f "${TEST_DIR}/${i}-${snapshot_virt0}" @@ -59,43 +52,12 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks . ./common.rc . ./common.filter +. ./common.qemu _supported_fmt qcow2 _supported_proto file _supported_os Linux -# Wait for expected QMP response from QEMU. Will time out -# after 10 seconds, which counts as failure. -# -# $1 is the string to expect -# -# If $silent is set to anything but an empty string, then -# response is not echoed out. -function timed_wait_for() -{ - while read -t 10 resp <&5 - do - if [ "${silent}" == "" ]; then - echo "${resp}" | _filter_testdir | _filter_qemu - fi - grep -q "${1}" < <(echo ${resp}) - if [ $? -eq 0 ]; then - return - fi - done - echo "Timeout waiting for ${1}" - exit 1 # Timeout means the test failed -} - -# Sends QMP command to QEMU, and waits for the expected response -# -# ${1}: String of the QMP command to send -# ${2}: String that the QEMU response should contain -function send_qmp_cmd() -{ - echo "${1}" >&6 - timed_wait_for "${2}" -} # ${1}: unique identifier for the snapshot filename function create_single_snapshot() @@ -104,7 +66,7 @@ function create_single_snapshot() 'arguments': { 'device': 'virtio0', 'snapshot-file':'"${TEST_DIR}/${1}-${snapshot_virt0}"', 'format': 'qcow2' } }" - send_qmp_cmd "${cmd}" "return" + _send_qemu_cmd $h "${cmd}" "return" } # ${1}: unique identifier for the snapshot filename @@ -120,14 +82,11 @@ function create_group_snapshot() 'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt1}"' } } ] } }" - send_qmp_cmd "${cmd}" "return" + _send_qemu_cmd $h "${cmd}" "return" } size=128M -mkfifo "${QMP_IN}" -mkfifo "${QMP_OUT}" - _make_test_img $size mv "${TEST_IMG}" "${TEST_IMG}.orig" _make_test_img $size @@ -136,23 +95,15 @@ echo echo === Running QEMU === echo -"${QEMU}" -nographic -monitor none -serial none -qmp stdio\ - -drive file="${TEST_IMG}.orig",if=virtio\ - -drive file="${TEST_IMG}",if=virtio 2>&1 >"${QMP_OUT}" <"${QMP_IN}"& -qemu_pid=$! - -# redirect fifos to file descriptors, to keep from blocking -exec 5<"${QMP_OUT}" -exec 6>"${QMP_IN}" - -# Don't print response, since it has version information in it -silent=yes timed_wait_for "capabilities" +qemu_comm_method="qmp" +_launch_qemu -drive file="${TEST_IMG}.orig",if=virtio -drive file="${TEST_IMG}",if=virtio +h=$QEMU_HANDLE echo echo === Sending capabilities === echo -send_qmp_cmd "{ 'execute': 'qmp_capabilities' }" "return" +_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return" echo echo === Create a single snapshot on virtio0 === @@ -165,16 +116,16 @@ echo echo === Invalid command - missing device and nodename === echo -send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync', - 'arguments': { 'snapshot-file':'"${TEST_DIR}"/1-${snapshot_virt0}', +_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'snapshot-file':'"${TEST_DIR}/1-${snapshot_virt0}"', 'format': 'qcow2' } }" "error" echo echo === Invalid command - missing snapshot-file === echo -send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync', - 'arguments': { 'device': 'virtio0', +_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'device': 'virtio0', 'format': 'qcow2' } }" "error" echo echo diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 new file mode 100755 index 0000000000..384b3ace54 --- /dev/null +++ b/tests/qemu-iotests/091 @@ -0,0 +1,105 @@ +#!/bin/bash +# +# Live migration test +# +# Performs a migration from one VM to another via monitor commands +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=jcody@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +MIG_FIFO="${TEST_DIR}/migrate" + +_cleanup() +{ + rm -f "${MIG_FIFO}" + _cleanup_qemu + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +size=1G + +_make_test_img $size + +mkfifo "${MIG_FIFO}" + +echo +echo === Starting QEMU VM1 === +echo + +qemu_comm_method="monitor" +_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk +h1=$QEMU_HANDLE + +echo +echo === Starting QEMU VM2 === +echo +_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk \ + -incoming "exec: cat '${MIG_FIFO}'" +h2=$QEMU_HANDLE + +echo +echo === VM 1: Migrate from VM1 to VM2 === +echo + +silent=yes +_send_qemu_cmd $h1 'qemu-io disk "write -P 0x22 0 4M"' "(qemu)" +echo "vm1: qemu-io disk write complete" +_send_qemu_cmd $h1 "migrate \"exec: cat > '${MIG_FIFO}'\"" "(qemu)" +echo "vm1: live migration started" +qemu_cmd_repeat=20 _send_qemu_cmd $h1 "info migrate" "completed" +echo "vm1: live migration completed" + +echo +echo === VM 2: Post-migration, write to disk, verify running === +echo + +_send_qemu_cmd $h2 'qemu-io disk "write 4M 1M"' "(qemu)" +echo "vm2: qemu-io disk write complete" +qemu_cmd_repeat=20 _send_qemu_cmd $h2 "info status" "running" +echo "vm2: qemu process running successfully" + +echo "vm2: flush io, and quit" +_send_qemu_cmd $h2 'qemu-io disk flush' "(qemu)" +_send_qemu_cmd $h2 'quit' "" + +echo "Check image pattern" +${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io + +echo "Running 'qemu-img check -r all \$TEST_IMG'" +"${QEMU_IMG}" check -r all "${TEST_IMG}" 2>&1 | _filter_testdir | _filter_qemu + +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/091.out b/tests/qemu-iotests/091.out new file mode 100644 index 0000000000..a2e0122966 --- /dev/null +++ b/tests/qemu-iotests/091.out @@ -0,0 +1,28 @@ +QA output created by 091 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + +=== Starting QEMU VM1 === + + +=== Starting QEMU VM2 === + + +=== VM 1: Migrate from VM1 to VM2 === + +vm1: qemu-io disk write complete +vm1: live migration started +vm1: live migration completed + +=== VM 2: Post-migration, write to disk, verify running === + +vm2: qemu-io disk write complete +vm2: qemu process running successfully +vm2: flush io, and quit +Check image pattern +read 4194304/4194304 bytes at offset 0 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Running 'qemu-img check -r all $TEST_IMG' +No errors were found on the image. +80/16384 = 0.49% allocated, 0.00% fragmented, 0.00% compressed clusters +Image end offset: 5570560 +*** done diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu new file mode 100644 index 0000000000..918af3102c --- /dev/null +++ b/tests/qemu-iotests/common.qemu @@ -0,0 +1,200 @@ +#!/bin/bash +# +# This allows for launching of multiple QEMU instances, with independent +# communication possible to each instance. +# +# Each instance can choose, at launch, to use either the QMP or the +# HMP (monitor) interface. +# +# All instances are cleaned up via _cleanup_qemu, including killing the +# running qemu instance. +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +QEMU_COMM_TIMEOUT=10 + +QEMU_FIFO_IN="${TEST_DIR}/qmp-in-$$" +QEMU_FIFO_OUT="${TEST_DIR}/qmp-out-$$" + +QEMU_PID= +_QEMU_HANDLE=0 +QEMU_HANDLE=0 + +# If bash version is >= 4.1, these will be overwritten and dynamic +# file descriptor values assigned. +_out_fd=3 +_in_fd=4 + +# Wait for expected QMP response from QEMU. Will time out +# after 10 seconds, which counts as failure. +# +# Override QEMU_COMM_TIMEOUT for a timeout different than the +# default 10 seconds +# +# $1: The handle to use +# $2+ All remaining arguments comprise the string to search for +# in the response. +# +# If $silent is set to anything but an empty string, then +# response is not echoed out. +function _timed_wait_for() +{ + local h=${1} + shift + + QEMU_STATUS[$h]=0 + while read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]} + do + if [ -z "${silent}" ]; then + echo "${resp}" | _filter_testdir | _filter_qemu \ + | _filter_qemu_io | _filter_qmp + fi + grep -q "${*}" < <(echo ${resp}) + if [ $? -eq 0 ]; then + return + fi + done + QEMU_STATUS[$h]=-1 + if [ -z "${qemu_error_no_exit}" ]; then + echo "Timeout waiting for ${*} on handle ${h}" + exit 1 # Timeout means the test failed + fi +} + + +# Sends QMP or HMP command to QEMU, and waits for the expected response +# +# $1: QEMU handle to use +# $2: String of the QMP command to send +# ${@: -1} (Last string passed) +# String that the QEMU response should contain. If it is a null +# string, do not wait for a response +# +# Set qemu_cmd_repeat to the number of times to repeat the cmd +# until either timeout, or a response. If it is not set, or <=0, +# then the command is only sent once. +# +# If $qemu_error_no_exit is set, then even if the expected response +# is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in +# that case. +function _send_qemu_cmd() +{ + local h=${1} + local count=1 + local cmd= + local use_error=${qemu_error_no_exit} + shift + + if [ ${qemu_cmd_repeat} -gt 0 ] 2>/dev/null; then + count=${qemu_cmd_repeat} + use_error="no" + fi + # This array element extraction is done to accomodate pathnames with spaces + cmd=${@: 1:${#@}-1} + shift $(($# - 1)) + + while [ ${count} -gt 0 ] + do + echo "${cmd}" >&${QEMU_IN[${h}]} + if [ -n "${1}" ]; then + qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" + if [ ${QEMU_STATUS[$h]} -eq 0 ]; then + return + fi + fi + let count--; + done + if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then + echo "Timeout waiting for ${1} on handle ${h}" + exit 1 #Timeout means the test failed + fi +} + + +# Launch a QEMU process. +# +# Input parameters: +# $qemu_comm_method: set this variable to 'monitor' (case insensitive) +# to use the QEMU HMP monitor for communication. +# Otherwise, the default of QMP is used. +# Returns: +# $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. +# +function _launch_qemu() +{ + local comm= + local fifo_out= + local fifo_in= + + if (shopt -s nocasematch; [[ "${qemu_comm_method}" == "monitor" ]]) + then + comm="-monitor stdio" + else + local qemu_comm_method="qmp" + comm="-monitor none -qmp stdio" + fi + + fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE} + fifo_in=${QEMU_FIFO_IN}_${_QEMU_HANDLE} + mkfifo "${fifo_out}" + mkfifo "${fifo_in}" + + "${QEMU}" -nographic -serial none ${comm} -machine accel=qtest "${@}" 2>&1 \ + >"${fifo_out}" \ + <"${fifo_in}" & + QEMU_PID[${_QEMU_HANDLE}]=$! + + if [[ "${BASH_VERSINFO[0]}" -ge "5" || + ("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]] + then + # bash >= 4.1 required for automatic fd + exec {_out_fd}<"${fifo_out}" + exec {_in_fd}>"${fifo_in}" + else + let _out_fd++ + let _in_fd++ + eval "exec ${_out_fd}<'${fifo_out}'" + eval "exec ${_in_fd}>'${fifo_in}'" + fi + + QEMU_OUT[${_QEMU_HANDLE}]=${_out_fd} + QEMU_IN[${_QEMU_HANDLE}]=${_in_fd} + QEMU_STATUS[${_QEMU_HANDLE}]=0 + + if [ "${qemu_comm_method}" == "qmp" ] + then + # Don't print response, since it has version information in it + silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities" + fi + QEMU_HANDLE=${_QEMU_HANDLE} + let _QEMU_HANDLE++ +} + + +# Silenty kills the QEMU process +function _cleanup_qemu() +{ + # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices + for i in "${!QEMU_OUT[@]}" + do + kill -KILL ${QEMU_PID[$i]} 2>/dev/null + wait ${QEMU_PID[$i]} 2>/dev/null # silent kill + rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" + eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors + eval "exec ${QEMU_OUT[$i]}<&-" + done +} diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index ae096638b8..cd3e4d2c27 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -96,3 +96,4 @@ 087 rw auto 088 rw auto 090 rw auto quick +091 rw auto diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c index 75cd1a1fd4..30cc721e55 100644 --- a/tests/test-vmstate.c +++ b/tests/test-vmstate.c @@ -65,8 +65,7 @@ static const VMStateDescription vmstate_simple = { .name = "test", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_UINT32(a, TestStruct), VMSTATE_UINT32(b, TestStruct), VMSTATE_UINT32(c, TestStruct), @@ -131,8 +130,7 @@ static const VMStateDescription vmstate_versioned = { .name = "test", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(a, TestStruct), VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so * we catch bugs more easily. @@ -207,8 +205,7 @@ static const VMStateDescription vmstate_skipping = { .name = "test", .version_id = 2, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT32(a, TestStruct), VMSTATE_UINT32(b, TestStruct), VMSTATE_UINT32_TEST(c, TestStruct, test_skip), diff --git a/trace-events b/trace-events index af4449d2ba..2c5b30763e 100644 --- a/trace-events +++ b/trace-events @@ -1230,6 +1230,8 @@ kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d" kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p" kvm_failed_spr_set(int str, const char *msg) "Warning: Unable to set SPR %d to KVM: %s" kvm_failed_spr_get(int str, const char *msg) "Warning: Unable to retrieve SPR %d from KVM: %s" +kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s" +kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s" # memory.c memory_region_ops_read(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u" @@ -1246,7 +1248,3 @@ xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (ad # hw/pci/pci_host.c pci_cfg_read(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x -> 0x%x" pci_cfg_write(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x <- 0x%x" - -# target-s390/kvm.c -kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s" -kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s" diff --git a/translate-all.c b/translate-all.c index 5759974d42..5549a85ed5 100644 --- a/translate-all.c +++ b/translate-all.c @@ -143,7 +143,7 @@ void cpu_gen_init(void) int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr) { TCGContext *s = &tcg_ctx; - uint8_t *gen_code_buf; + tcg_insn_unit *gen_code_buf; int gen_code_size; #ifdef CONFIG_PROFILER int64_t ti; @@ -186,8 +186,8 @@ int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { - qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr); - log_disas(tb->tc_ptr, *gen_code_size_ptr); + qemu_log("OUT: [size=%d]\n", gen_code_size); + log_disas(tb->tc_ptr, gen_code_size); qemu_log("\n"); qemu_log_flush(); } @@ -235,7 +235,8 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, s->tb_jmp_offset = NULL; s->tb_next = tb->tb_next; #endif - j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr); + j = tcg_gen_code_search_pc(s, (tcg_insn_unit *)tc_ptr, + searched_pc - tc_ptr); if (j < 0) return -1; /* now find start of instruction before */ @@ -944,7 +945,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, { CPUArchState *env = cpu->env_ptr; TranslationBlock *tb; - uint8_t *tc_ptr; tb_page_addr_t phys_pc, phys_page2; target_ulong virt_page2; int code_gen_size; @@ -959,8 +959,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, /* Don't forget to invalidate previous TB info. */ tcg_ctx.tb_ctx.tb_invalidated_flag = 1; } - tc_ptr = tcg_ctx.code_gen_ptr; - tb->tc_ptr = tc_ptr; + tb->tc_ptr = tcg_ctx.code_gen_ptr; tb->cs_base = cs_base; tb->flags = flags; tb->cflags = cflags; diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 6f2294efda..4af420bfa8 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -17,4 +17,4 @@ common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o $(obj)/sdl.o $(obj)/sdl_zoom.o $(obj)/sdl2.o: QEMU_CFLAGS += $(SDL_CFLAGS) -$(obj)/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS) +gtk.o-cflags := $(GTK_CFLAGS) $(VTE_CFLAGS) diff --git a/util/fifo8.c b/util/fifo8.c index 6a43482c9e..0ea5ad98e3 100644 --- a/util/fifo8.c +++ b/util/fifo8.c @@ -116,8 +116,7 @@ const VMStateDescription vmstate_fifo8 = { .name = "Fifo8", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, 0, capacity), VMSTATE_UINT32(head, Fifo8), VMSTATE_UINT32(num, Fifo8), diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 93f7d351d3..69552f7ec3 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -238,3 +238,115 @@ char *qemu_get_exec_dir(void) { return g_strdup(exec_dir); } + +/* + * g_poll has a problem on Windows when using + * timeouts < 10ms, in glib/gpoll.c: + * + * // If not, and we have a significant timeout, poll again with + * // timeout then. Note that this will return indication for only + * // one event, or only for messages. We ignore timeouts less than + * // ten milliseconds as they are mostly pointless on Windows, the + * // MsgWaitForMultipleObjectsEx() call will timeout right away + * // anyway. + * + * if (retval == 0 && (timeout == INFINITE || timeout >= 10)) + * retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout); + * + * So whenever g_poll is called with timeout < 10ms it does + * a quick poll instead of wait, this causes significant performance + * degradation of QEMU, thus we should use WaitForMultipleObjectsEx + * directly + */ +gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout) +{ + guint i; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + gint nhandles = 0; + int num_completed = 0; + + for (i = 0; i < nfds; i++) { + gint j; + + if (fds[i].fd <= 0) { + continue; + } + + /* don't add same handle several times + */ + for (j = 0; j < nhandles; j++) { + if (handles[j] == (HANDLE)fds[i].fd) { + break; + } + } + + if (j == nhandles) { + if (nhandles == MAXIMUM_WAIT_OBJECTS) { + fprintf(stderr, "Too many handles to wait for!\n"); + break; + } else { + handles[nhandles++] = (HANDLE)fds[i].fd; + } + } + } + + for (i = 0; i < nfds; ++i) { + fds[i].revents = 0; + } + + if (timeout == -1) { + timeout = INFINITE; + } + + if (nhandles == 0) { + if (timeout == INFINITE) { + return -1; + } else { + SleepEx(timeout, TRUE); + return 0; + } + } + + while (1) { + DWORD res; + gint j; + + res = WaitForMultipleObjectsEx(nhandles, handles, FALSE, + timeout, TRUE); + + if (res == WAIT_FAILED) { + for (i = 0; i < nfds; ++i) { + fds[i].revents = 0; + } + + return -1; + } else if ((res == WAIT_TIMEOUT) || (res == WAIT_IO_COMPLETION) || + ((int)res < (int)WAIT_OBJECT_0) || + (res >= (WAIT_OBJECT_0 + nhandles))) { + break; + } + + for (i = 0; i < nfds; ++i) { + if (handles[res - WAIT_OBJECT_0] == (HANDLE)fds[i].fd) { + fds[i].revents = fds[i].events; + } + } + + ++num_completed; + + if (nhandles <= 1) { + break; + } + + /* poll the rest of the handles + */ + for (j = res - WAIT_OBJECT_0 + 1; j < nhandles; j++) { + handles[j - 1] = handles[j]; + } + --nhandles; + + timeout = 0; + } + + return num_completed; +} @@ -3024,7 +3024,6 @@ int main(int argc, char **argv, char **envp) runstate_init(); - init_clocks(); rtc_clock = QEMU_CLOCK_HOST; qemu_init_auxval(envp); |