diff options
138 files changed, 5495 insertions, 3539 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 8f5681fd64..2ede20d60b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -553,6 +553,7 @@ T: git git://github.com/kvaneesh/QEMU.git virtio-blk M: Kevin Wolf <kwolf@redhat.com> +M: Stefan Hajnoczi <stefanha@redhat.com> S: Supported F: hw/virtio-blk* @@ -583,6 +584,7 @@ F: audio/ Block M: Kevin Wolf <kwolf@redhat.com> +M: Stefan Hajnoczi <stefanha@redhat.com> S: Supported F: block* F: block/ @@ -127,6 +127,8 @@ pixman/Makefile: $(SRC_PATH)/pixman/configure $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) +$(SUBDIR_RULES): libqemustub.a + $(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) subdir-libdis $(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) subdir-libdis-user subdir-libuser @@ -157,6 +159,12 @@ version.o: $(SRC_PATH)/version.rc config-host.h $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") version-obj-$(CONFIG_WIN32) += version.o + +###################################################################### +# Build library with stubs + +libqemustub.a: $(stub-obj-y) + ###################################################################### # Support building shared library libcacard @@ -183,13 +191,13 @@ tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ main-loop.o iohandler.o error.o tools-obj-$(CONFIG_POSIX) += compatfd.o -qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) -qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) -qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) +qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemustub.a +qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemustub.a +qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemustub.a qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o -vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o +vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o libqemustub.a $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@") fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y) @@ -232,7 +240,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) +qemu-ga$(EXESUF): qemu-ga.o $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemustub.a QEMULIBS=libuser libdis libdis-user diff --git a/Makefile.objs b/Makefile.objs index 37be7e26f7..3c7abca433 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -1,4 +1,8 @@ ####################################################################### +# Stub library, linked in tools +stub-obj-y = stubs/ + +####################################################################### # Target-independent parts used in system and user emulation universal-obj-y = universal-obj-y += qemu-log.o @@ -100,6 +104,8 @@ common-obj-y += vl.o common-obj-$(CONFIG_SLIRP) += slirp/ +common-obj-y += backends/ + ###################################################################### # libseccomp ifeq ($(CONFIG_SECCOMP),y) @@ -237,6 +243,7 @@ vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) QEMU_CFLAGS+=$(GLIB_CFLAGS) nested-vars += \ + stub-obj-y \ qga-obj-y \ qom-obj-y \ qapi-obj-y \ diff --git a/Makefile.target b/Makefile.target index 3822bc5ac3..8b658c0d13 100644 --- a/Makefile.target +++ b/Makefile.target @@ -162,12 +162,12 @@ endif #CONFIG_LINUX_USER ifdef QEMU_PROGW # The linker builds a windows executable. Make also a console executable. -$(QEMU_PROGW): $(all-obj-y) +$(QEMU_PROGW): $(all-obj-y) ../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) +$(QEMU_PROG): $(all-obj-y) ../libqemustub.a $(call LINK,$^) endif diff --git a/backends/Makefile.objs b/backends/Makefile.objs new file mode 100644 index 0000000000..883676106b --- /dev/null +++ b/backends/Makefile.objs @@ -0,0 +1,2 @@ +common-obj-y += rng.o rng-egd.o +common-obj-$(CONFIG_POSIX) += rng-random.o diff --git a/backends/rng-egd.c b/backends/rng-egd.c new file mode 100644 index 0000000000..ad8473777c --- /dev/null +++ b/backends/rng-egd.c @@ -0,0 +1,224 @@ +/* + * QEMU Random Number Generator Backend + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/rng.h" +#include "qemu-char.h" +#include "qerror.h" +#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */ + +#define TYPE_RNG_EGD "rng-egd" +#define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD) + +typedef struct RngEgd +{ + RngBackend parent; + + CharDriverState *chr; + char *chr_name; + + GSList *requests; +} RngEgd; + +typedef struct RngRequest +{ + EntropyReceiveFunc *receive_entropy; + uint8_t *data; + void *opaque; + size_t offset; + size_t size; +} RngRequest; + +static void rng_egd_request_entropy(RngBackend *b, size_t size, + EntropyReceiveFunc *receive_entropy, + void *opaque) +{ + RngEgd *s = RNG_EGD(b); + RngRequest *req; + + req = g_malloc(sizeof(*req)); + + req->offset = 0; + req->size = size; + req->receive_entropy = receive_entropy; + req->opaque = opaque; + req->data = g_malloc(req->size); + + while (size > 0) { + uint8_t header[2]; + uint8_t len = MIN(size, 255); + + /* synchronous entropy request */ + header[0] = 0x02; + header[1] = len; + + qemu_chr_fe_write(s->chr, header, sizeof(header)); + + size -= len; + } + + s->requests = g_slist_append(s->requests, req); +} + +static void rng_egd_free_request(RngRequest *req) +{ + g_free(req->data); + g_free(req); +} + +static int rng_egd_chr_can_read(void *opaque) +{ + RngEgd *s = RNG_EGD(opaque); + GSList *i; + int size = 0; + + for (i = s->requests; i; i = i->next) { + RngRequest *req = i->data; + size += req->size - req->offset; + } + + return size; +} + +static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size) +{ + RngEgd *s = RNG_EGD(opaque); + + while (size > 0 && s->requests) { + RngRequest *req = s->requests->data; + int len = MIN(size, req->size - req->offset); + + memcpy(req->data + req->offset, buf, len); + req->offset += len; + size -= len; + + if (req->offset == req->size) { + s->requests = g_slist_remove_link(s->requests, s->requests); + + req->receive_entropy(req->opaque, req->data, req->size); + + rng_egd_free_request(req); + } + } +} + +static void rng_egd_free_requests(RngEgd *s) +{ + GSList *i; + + for (i = s->requests; i; i = i->next) { + rng_egd_free_request(i->data); + } + + g_slist_free(s->requests); + s->requests = NULL; +} + +static void rng_egd_cancel_requests(RngBackend *b) +{ + RngEgd *s = RNG_EGD(b); + + /* We simply delete the list of pending requests. If there is data in the + * queue waiting to be read, this is okay, because there will always be + * more data than we requested originally + */ + rng_egd_free_requests(s); +} + +static void rng_egd_opened(RngBackend *b, Error **errp) +{ + RngEgd *s = RNG_EGD(b); + + if (s->chr_name == NULL) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, + "chardev", "a valid character device"); + return; + } + + s->chr = qemu_chr_find(s->chr_name); + if (s->chr == NULL) { + error_set(errp, QERR_DEVICE_NOT_FOUND, s->chr_name); + return; + } + + /* FIXME we should resubmit pending requests when the CDS reconnects. */ + qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read, + NULL, s); +} + +static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp) +{ + RngBackend *b = RNG_BACKEND(obj); + RngEgd *s = RNG_EGD(b); + + if (b->opened) { + error_set(errp, QERR_PERMISSION_DENIED); + } else { + g_free(s->chr_name); + s->chr_name = g_strdup(value); + } +} + +static char *rng_egd_get_chardev(Object *obj, Error **errp) +{ + RngEgd *s = RNG_EGD(obj); + + if (s->chr && s->chr->label) { + return g_strdup(s->chr->label); + } + + return NULL; +} + +static void rng_egd_init(Object *obj) +{ + object_property_add_str(obj, "chardev", + rng_egd_get_chardev, rng_egd_set_chardev, + NULL); +} + +static void rng_egd_finalize(Object *obj) +{ + RngEgd *s = RNG_EGD(obj); + + if (s->chr) { + qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); + } + + g_free(s->chr_name); + + rng_egd_free_requests(s); +} + +static void rng_egd_class_init(ObjectClass *klass, void *data) +{ + RngBackendClass *rbc = RNG_BACKEND_CLASS(klass); + + rbc->request_entropy = rng_egd_request_entropy; + rbc->cancel_requests = rng_egd_cancel_requests; + rbc->opened = rng_egd_opened; +} + +static TypeInfo rng_egd_info = { + .name = TYPE_RNG_EGD, + .parent = TYPE_RNG_BACKEND, + .instance_size = sizeof(RngEgd), + .class_init = rng_egd_class_init, + .instance_init = rng_egd_init, + .instance_finalize = rng_egd_finalize, +}; + +static void register_types(void) +{ + type_register_static(&rng_egd_info); +} + +type_init(register_types); diff --git a/backends/rng-random.c b/backends/rng-random.c new file mode 100644 index 0000000000..9c9923b2ac --- /dev/null +++ b/backends/rng-random.c @@ -0,0 +1,161 @@ +/* + * QEMU Random Number Generator Backend + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/rng-random.h" +#include "qemu/rng.h" +#include "qerror.h" +#include "main-loop.h" + +struct RndRandom +{ + RngBackend parent; + + int fd; + char *filename; + + EntropyReceiveFunc *receive_func; + void *opaque; + size_t size; +}; + +/** + * A simple and incomplete backend to request entropy from /dev/random. + * + * This backend exposes an additional "filename" property that can be used to + * set the filename to use to open the backend. + */ + +static void entropy_available(void *opaque) +{ + RndRandom *s = RNG_RANDOM(opaque); + uint8_t buffer[s->size]; + ssize_t len; + + len = read(s->fd, buffer, s->size); + g_assert(len != -1); + + s->receive_func(s->opaque, buffer, len); + s->receive_func = NULL; + + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); +} + +static void rng_random_request_entropy(RngBackend *b, size_t size, + EntropyReceiveFunc *receive_entropy, + void *opaque) +{ + RndRandom *s = RNG_RANDOM(b); + + if (s->receive_func) { + s->receive_func(s->opaque, NULL, 0); + } + + s->receive_func = receive_entropy; + s->opaque = opaque; + s->size = size; + + qemu_set_fd_handler(s->fd, entropy_available, NULL, s); +} + +static void rng_random_opened(RngBackend *b, Error **errp) +{ + RndRandom *s = RNG_RANDOM(b); + + if (s->filename == NULL) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, + "filename", "a valid filename"); + } else { + s->fd = open(s->filename, O_RDONLY | O_NONBLOCK); + + if (s->fd == -1) { + error_set(errp, QERR_OPEN_FILE_FAILED, s->filename); + } + } +} + +static char *rng_random_get_filename(Object *obj, Error **errp) +{ + RndRandom *s = RNG_RANDOM(obj); + + if (s->filename) { + return g_strdup(s->filename); + } + + return NULL; +} + +static void rng_random_set_filename(Object *obj, const char *filename, + Error **errp) +{ + RngBackend *b = RNG_BACKEND(obj); + RndRandom *s = RNG_RANDOM(obj); + + if (b->opened) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + if (s->filename) { + g_free(s->filename); + } + + s->filename = g_strdup(filename); +} + +static void rng_random_init(Object *obj) +{ + RndRandom *s = RNG_RANDOM(obj); + + object_property_add_str(obj, "filename", + rng_random_get_filename, + rng_random_set_filename, + NULL); + + s->filename = g_strdup("/dev/random"); +} + +static void rng_random_finalize(Object *obj) +{ + RndRandom *s = RNG_RANDOM(obj); + + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + + if (s->fd != -1) { + close(s->fd); + } + + g_free(s->filename); +} + +static void rng_random_class_init(ObjectClass *klass, void *data) +{ + RngBackendClass *rbc = RNG_BACKEND_CLASS(klass); + + rbc->request_entropy = rng_random_request_entropy; + rbc->opened = rng_random_opened; +} + +static TypeInfo rng_random_info = { + .name = TYPE_RNG_RANDOM, + .parent = TYPE_RNG_BACKEND, + .instance_size = sizeof(RndRandom), + .class_init = rng_random_class_init, + .instance_init = rng_random_init, + .instance_finalize = rng_random_finalize, +}; + +static void register_types(void) +{ + type_register_static(&rng_random_info); +} + +type_init(register_types); diff --git a/backends/rng.c b/backends/rng.c new file mode 100644 index 0000000000..06f261180c --- /dev/null +++ b/backends/rng.c @@ -0,0 +1,93 @@ +/* + * QEMU Random Number Generator Backend + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/rng.h" +#include "qerror.h" + +void rng_backend_request_entropy(RngBackend *s, size_t size, + EntropyReceiveFunc *receive_entropy, + void *opaque) +{ + RngBackendClass *k = RNG_BACKEND_GET_CLASS(s); + + if (k->request_entropy) { + k->request_entropy(s, size, receive_entropy, opaque); + } +} + +void rng_backend_cancel_requests(RngBackend *s) +{ + RngBackendClass *k = RNG_BACKEND_GET_CLASS(s); + + if (k->cancel_requests) { + k->cancel_requests(s); + } +} + +static bool rng_backend_prop_get_opened(Object *obj, Error **errp) +{ + RngBackend *s = RNG_BACKEND(obj); + + return s->opened; +} + +void rng_backend_open(RngBackend *s, Error **errp) +{ + object_property_set_bool(OBJECT(s), true, "opened", errp); +} + +static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp) +{ + RngBackend *s = RNG_BACKEND(obj); + RngBackendClass *k = RNG_BACKEND_GET_CLASS(s); + + if (value == s->opened) { + return; + } + + if (!value && s->opened) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + if (k->opened) { + k->opened(s, errp); + } + + if (!error_is_set(errp)) { + s->opened = value; + } +} + +static void rng_backend_init(Object *obj) +{ + object_property_add_bool(obj, "opened", + rng_backend_prop_get_opened, + rng_backend_prop_set_opened, + NULL); +} + +static TypeInfo rng_backend_info = { + .name = TYPE_RNG_BACKEND, + .parent = TYPE_OBJECT, + .instance_size = sizeof(RngBackend), + .instance_init = rng_backend_init, + .class_size = sizeof(RngBackendClass), + .abstract = true, +}; + +static void register_types(void) +{ + type_register_static(&rng_backend_info); +} + +type_init(register_types); @@ -3521,7 +3521,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs) void bdrv_aio_cancel(BlockDriverAIOCB *acb) { - acb->pool->cancel(acb); + acb->aiocb_info->cancel(acb); } /* block I/O throttling */ @@ -3711,7 +3711,7 @@ static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb) qemu_aio_release(acb); } -static AIOPool bdrv_em_aio_pool = { +static const AIOCBInfo bdrv_em_aiocb_info = { .aiocb_size = sizeof(BlockDriverAIOCBSync), .cancel = bdrv_aio_cancel_em, }; @@ -3740,7 +3740,7 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs, { BlockDriverAIOCBSync *acb; - acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&bdrv_em_aiocb_info, bs, cb, opaque); acb->is_write = is_write; acb->qiov = qiov; acb->bounce = qemu_blockalign(bs, qiov->size); @@ -3785,7 +3785,7 @@ static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb) qemu_aio_flush(); } -static AIOPool bdrv_em_co_aio_pool = { +static const AIOCBInfo bdrv_em_co_aiocb_info = { .aiocb_size = sizeof(BlockDriverAIOCBCoroutine), .cancel = bdrv_aio_co_cancel_em, }; @@ -3828,7 +3828,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, Coroutine *co; BlockDriverAIOCBCoroutine *acb; - acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque); acb->req.sector = sector_num; acb->req.nb_sectors = nb_sectors; acb->req.qiov = qiov; @@ -3858,7 +3858,7 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, Coroutine *co; BlockDriverAIOCBCoroutine *acb; - acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque); co = qemu_coroutine_create(bdrv_aio_flush_co_entry); qemu_coroutine_enter(co, acb); @@ -3884,7 +3884,7 @@ BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs, trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque); - acb = qemu_aio_get(&bdrv_em_co_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque); acb->req.sector = sector_num; acb->req.nb_sectors = nb_sectors; co = qemu_coroutine_create(bdrv_aio_discard_co_entry); @@ -3904,18 +3904,13 @@ void bdrv_init_with_whitelist(void) bdrv_init(); } -void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs, +void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { BlockDriverAIOCB *acb; - if (pool->free_aiocb) { - acb = pool->free_aiocb; - pool->free_aiocb = acb->next; - } else { - acb = g_malloc0(pool->aiocb_size); - acb->pool = pool; - } + acb = g_slice_alloc(aiocb_info->aiocb_size); + acb->aiocb_info = aiocb_info; acb->bs = bs; acb->cb = cb; acb->opaque = opaque; @@ -3924,10 +3919,8 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs, void qemu_aio_release(void *p) { - BlockDriverAIOCB *acb = (BlockDriverAIOCB *)p; - AIOPool *pool = acb->pool; - acb->next = pool->free_aiocb; - pool->free_aiocb = acb; + BlockDriverAIOCB *acb = p; + g_slice_free1(acb->aiocb_info->aiocb_size, acb); } /**************************************************************/ diff --git a/block/blkdebug.c b/block/blkdebug.c index 1206d5256b..d61ece86a9 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -41,7 +41,7 @@ typedef struct BlkdebugAIOCB { static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb); -static AIOPool blkdebug_aio_pool = { +static const AIOCBInfo blkdebug_aiocb_info = { .aiocb_size = sizeof(BlkdebugAIOCB), .cancel = blkdebug_aio_cancel, }; @@ -335,7 +335,7 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs, return NULL; } - acb = qemu_aio_get(&blkdebug_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque); acb->ret = -error; bh = qemu_bh_new(error_callback_bh, acb); diff --git a/block/blkverify.c b/block/blkverify.c index 9d5f1ec5b9..4beede77ab 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -48,7 +48,7 @@ static void blkverify_aio_cancel(BlockDriverAIOCB *blockacb) } } -static AIOPool blkverify_aio_pool = { +static const AIOCBInfo blkverify_aiocb_info = { .aiocb_size = sizeof(BlkverifyAIOCB), .cancel = blkverify_aio_cancel, }; @@ -233,7 +233,7 @@ static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write, BlockDriverCompletionFunc *cb, void *opaque) { - BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aio_pool, bs, cb, opaque); + BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque); acb->bh = NULL; acb->is_write = is_write; diff --git a/block/curl.c b/block/curl.c index c1074cd2e3..1179484de0 100644 --- a/block/curl.c +++ b/block/curl.c @@ -438,7 +438,7 @@ static void curl_aio_cancel(BlockDriverAIOCB *blockacb) // Do we have to implement canceling? Seems to work without... } -static AIOPool curl_aio_pool = { +static const AIOCBInfo curl_aiocb_info = { .aiocb_size = sizeof(CURLAIOCB), .cancel = curl_aio_cancel, }; @@ -505,7 +505,7 @@ static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs, { CURLAIOCB *acb; - acb = qemu_aio_get(&curl_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&curl_aiocb_info, bs, cb, opaque); acb->qiov = qiov; acb->sector_num = sector_num; diff --git a/block/gluster.c b/block/gluster.c index 3588d7377f..1c90174b13 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -388,7 +388,7 @@ static void qemu_gluster_aio_cancel(BlockDriverAIOCB *blockacb) } } -static AIOPool gluster_aio_pool = { +static const AIOCBInfo gluster_aiocb_info = { .aiocb_size = sizeof(GlusterAIOCB), .cancel = qemu_gluster_aio_cancel, }; @@ -439,7 +439,7 @@ static BlockDriverAIOCB *qemu_gluster_aio_rw(BlockDriverState *bs, size = nb_sectors * BDRV_SECTOR_SIZE; s->qemu_aio_count++; - acb = qemu_aio_get(&gluster_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque); acb->size = size; acb->ret = 0; acb->finished = NULL; @@ -484,7 +484,7 @@ static BlockDriverAIOCB *qemu_gluster_aio_flush(BlockDriverState *bs, GlusterAIOCB *acb; BDRVGlusterState *s = bs->opaque; - acb = qemu_aio_get(&gluster_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&gluster_aiocb_info, bs, cb, opaque); acb->size = 0; acb->ret = 0; acb->finished = NULL; diff --git a/block/iscsi.c b/block/iscsi.c index d0b1a10ee4..a6a819d68f 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -133,7 +133,7 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb) } } -static AIOPool iscsi_aio_pool = { +static const AIOCBInfo iscsi_aiocb_info = { .aiocb_size = sizeof(IscsiAIOCB), .cancel = iscsi_aio_cancel, }; @@ -234,7 +234,7 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, uint64_t lba; struct iscsi_data data; - acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb); acb->iscsilun = iscsilun; @@ -325,7 +325,7 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors; - acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb); acb->iscsilun = iscsilun; @@ -430,7 +430,7 @@ iscsi_aio_flush(BlockDriverState *bs, struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; - acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); acb->iscsilun = iscsilun; acb->canceled = 0; @@ -483,7 +483,7 @@ iscsi_aio_discard(BlockDriverState *bs, IscsiAIOCB *acb; struct unmap_list list[1]; - acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); acb->iscsilun = iscsilun; acb->canceled = 0; @@ -558,7 +558,7 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs, assert(req == SG_IO); - acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); acb->iscsilun = iscsilun; acb->canceled = 0; diff --git a/block/linux-aio.c b/block/linux-aio.c index 6ca984dbe8..91ef863241 100644 --- a/block/linux-aio.c +++ b/block/linux-aio.c @@ -140,7 +140,7 @@ static void laio_cancel(BlockDriverAIOCB *blockacb) } } -static AIOPool laio_pool = { +static const AIOCBInfo laio_aiocb_info = { .aiocb_size = sizeof(struct qemu_laiocb), .cancel = laio_cancel, }; @@ -154,7 +154,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, struct iocb *iocbs; off_t offset = sector_num * 512; - laiocb = qemu_aio_get(&laio_pool, bs, cb, opaque); + laiocb = qemu_aio_get(&laio_aiocb_info, bs, cb, opaque); laiocb->nbytes = nb_sectors * 512; laiocb->ctx = s; laiocb->ret = -EINPROGRESS; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 5e3f9153fb..96224d1af2 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -301,7 +301,8 @@ static int alloc_refcount_block(BlockDriverState *bs, uint64_t last_table_size; uint64_t blocks_clusters; do { - uint64_t table_clusters = size_to_clusters(s, table_size); + uint64_t table_clusters = + size_to_clusters(s, table_size * sizeof(uint64_t)); blocks_clusters = 1 + ((table_clusters + refcount_block_clusters - 1) / refcount_block_clusters); diff --git a/block/qed.c b/block/qed.c index 6c182ca917..0b5374a202 100644 --- a/block/qed.c +++ b/block/qed.c @@ -30,7 +30,7 @@ static void qed_aio_cancel(BlockDriverAIOCB *blockacb) } } -static AIOPool qed_aio_pool = { +static const AIOCBInfo qed_aiocb_info = { .aiocb_size = sizeof(QEDAIOCB), .cancel = qed_aio_cancel, }; @@ -1311,7 +1311,7 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque, int flags) { - QEDAIOCB *acb = qemu_aio_get(&qed_aio_pool, bs, cb, opaque); + QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, cb, opaque); trace_qed_aio_setup(bs->opaque, acb, sector_num, nb_sectors, opaque, flags); diff --git a/block/rbd.c b/block/rbd.c index 015a9db0ad..0aaacaf859 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -570,7 +570,7 @@ static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb) acb->cancelled = 1; } -static AIOPool rbd_aio_pool = { +static const AIOCBInfo rbd_aiocb_info = { .aiocb_size = sizeof(RBDAIOCB), .cancel = qemu_rbd_aio_cancel, }; @@ -672,7 +672,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs, BDRVRBDState *s = bs->opaque; - acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&rbd_aiocb_info, bs, cb, opaque); acb->cmd = cmd; acb->qiov = qiov; if (cmd == RBD_AIO_DISCARD) { diff --git a/block/sheepdog.c b/block/sheepdog.c index 93061744d6..a48f58cfe8 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -420,7 +420,7 @@ static void sd_aio_cancel(BlockDriverAIOCB *blockacb) acb->canceled = true; } -static AIOPool sd_aio_pool = { +static const AIOCBInfo sd_aiocb_info = { .aiocb_size = sizeof(SheepdogAIOCB), .cancel = sd_aio_cancel, }; @@ -431,7 +431,7 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, { SheepdogAIOCB *acb; - acb = qemu_aio_get(&sd_aio_pool, bs, cb, opaque); + acb = qemu_aio_get(&sd_aiocb_info, bs, cb, opaque); acb->qiov = qiov; diff --git a/block/vmdk.c b/block/vmdk.c index 1a80e5a247..51398c0c08 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1092,6 +1092,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, BDRVVmdkState *s = bs->opaque; int ret; uint64_t n, index_in_cluster; + uint64_t extent_begin_sector, extent_relative_sector_num; VmdkExtent *extent = NULL; uint64_t cluster_offset; @@ -1103,7 +1104,9 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, ret = get_cluster_offset( bs, extent, NULL, sector_num << 9, 0, &cluster_offset); - index_in_cluster = sector_num % extent->cluster_sectors; + extent_begin_sector = extent->end_sector - extent->sectors; + extent_relative_sector_num = sector_num - extent_begin_sector; + index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; n = extent->cluster_sectors - index_in_cluster; if (n > nb_sectors) { n = nb_sectors; @@ -1154,6 +1157,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, VmdkExtent *extent = NULL; int n, ret; int64_t index_in_cluster; + uint64_t extent_begin_sector, extent_relative_sector_num; uint64_t cluster_offset; VmdkMetaData m_data; @@ -1196,7 +1200,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, if (ret) { return -EINVAL; } - index_in_cluster = sector_num % extent->cluster_sectors; + extent_begin_sector = extent->end_sector - extent->sectors; + extent_relative_sector_num = sector_num - extent_begin_sector; + index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; n = extent->cluster_sectors - index_in_cluster; if (n > nb_sectors) { n = nb_sectors; diff --git a/block/win32-aio.c b/block/win32-aio.c index c34dc73b6c..4704ee06c2 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -131,7 +131,7 @@ static void win32_aio_cancel(BlockDriverAIOCB *blockacb) } } -static AIOPool win32_aio_pool = { +static const AIOCBInfo win32_aiocb_info = { .aiocb_size = sizeof(QEMUWin32AIOCB), .cancel = win32_aio_cancel, }; @@ -145,7 +145,7 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs, uint64_t offset = sector_num * 512; DWORD rc; - waiocb = qemu_aio_get(&win32_aio_pool, bs, cb, opaque); + waiocb = qemu_aio_get(&win32_aiocb_info, bs, cb, opaque); waiocb->nbytes = nb_sectors * 512; waiocb->qiov = qiov; waiocb->is_read = (type == QEMU_AIO_READ); @@ -167,11 +167,11 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs, waiocb->is_linear = true; } - waiocb->ov = (OVERLAPPED) { - .Offset = (DWORD) offset, - .OffsetHigh = (DWORD) (offset >> 32), - .hEvent = event_notifier_get_handle(&aio->e) - }; + memset(&waiocb->ov, 0, sizeof(waiocb->ov)); + waiocb->ov.Offset = (DWORD)offset; + waiocb->ov.OffsetHigh = (DWORD)(offset >> 32); + waiocb->ov.hEvent = event_notifier_get_handle(&aio->e); + aio->count++; if (type & QEMU_AIO_READ) { diff --git a/compiler.h b/compiler.h index 55d7d74775..2f7998b6c1 100644 --- a/compiler.h +++ b/compiler.h @@ -50,20 +50,9 @@ # define __printf__ __gnu_printf__ # endif # endif -# if defined(__APPLE__) -# define QEMU_WEAK_ALIAS(newname, oldname) \ - static typeof(oldname) weak_##newname __attribute__((unused, weakref(#oldname))) -# define QEMU_WEAK_REF(newname, oldname) (weak_##newname ? weak_##newname : oldname) -# else -# define QEMU_WEAK_ALIAS(newname, oldname) \ - typeof(oldname) newname __attribute__((weak, alias (#oldname))) -# define QEMU_WEAK_REF(newname, oldname) newname -# endif #else #define GCC_ATTR /**/ #define GCC_FMT_ATTR(n, m) -#define QEMU_WEAK_ALIAS(newname, oldname) \ - _Pragma("weak " #newname "=" #oldname) #endif #endif /* COMPILER_H */ @@ -1383,7 +1383,7 @@ fi # libseccomp check if test "$seccomp" != "no" ; then - if $pkg_config libseccomp --modversion >/dev/null 2>&1; then + if $pkg_config --atleast-version=1.0.0 libseccomp --modversion >/dev/null 2>&1; then LIBS=`$pkg_config --libs libseccomp` seccomp="yes" else @@ -3891,7 +3891,10 @@ upper() { case "$cpu" in i386|x86_64|ppc) - echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_target_mak + # The TCG interpreter currently does not support ld/st optimization. + if test "$tcg_interpreter" = "no" ; then + echo "CONFIG_QEMU_LDST_OPTIMIZATION=y" >> $config_target_mak + fi ;; esac diff --git a/dma-helpers.c b/dma-helpers.c index 0c18e9e4d8..4f5fb649e7 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -195,7 +195,7 @@ static void dma_aio_cancel(BlockDriverAIOCB *acb) dma_complete(dbs, 0); } -static AIOPool dma_aio_pool = { +static const AIOCBInfo dma_aiocb_info = { .aiocb_size = sizeof(DMAAIOCB), .cancel = dma_aio_cancel, }; @@ -205,7 +205,7 @@ BlockDriverAIOCB *dma_bdrv_io( DMAIOFunc *io_func, BlockDriverCompletionFunc *cb, void *opaque, DMADirection dir) { - DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque); + DMAAIOCB *dbs = qemu_aio_get(&dma_aiocb_info, bs, cb, opaque); trace_dma_bdrv_io(dbs, bs, sector_num, (dir == DMA_DIRECTION_TO_DEVICE)); diff --git a/docs/specs/standard-vga.txt b/docs/specs/standard-vga.txt index 1cecccd469..8a4c1e93cd 100644 --- a/docs/specs/standard-vga.txt +++ b/docs/specs/standard-vga.txt @@ -36,7 +36,8 @@ IO ports used 03c0 - 03df : standard vga ports 01ce : bochs vbe interface index port -01cf : bochs vbe interface data port +01cf : bochs vbe interface data port (x86 only) +01d0 : bochs vbe interface data port Memory regions used diff --git a/docs/tracing.txt b/docs/tracing.txt index c541133368..453cc4a63d 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -139,6 +139,10 @@ having a common prefix in a batch. For example, virtio-blk trace events could be enabled using: trace-event virtio_blk_* on +If a line in the "-trace events=<file>" file begins with a '-', the trace event +will be disabled instead of enabled. This is useful when a wildcard was used +to enable an entire family of events but one noisy event needs to be disabled. + == Trace backends == The "tracetool" script automates tedious trace event code generation and also @@ -185,15 +189,6 @@ records the char* pointer value instead of the string that is pointed to. ==== Monitor commands ==== -* info trace - Display the contents of trace buffer. This command dumps the trace buffer - with simple formatting. For full pretty-printing, use the simpletrace.py - script on a binary trace file. - - The trace buffer is written into until full. The full trace buffer is - flushed and emptied. This means the 'info trace' will display few or no - entries if the buffer has just been flushed. - * trace-file on|off|flush|set <path> Enable/disable/flush the trace file or set the trace file name. diff --git a/exec-all.h b/exec-all.h index 6b3272ab9e..21aacdab50 100644 --- a/exec-all.h +++ b/exec-all.h @@ -290,10 +290,11 @@ extern int tb_invalidated_flag; /* The return address may point to the start of the next instruction. Subtracting one gets us the call instruction itself. */ #if defined(CONFIG_TCG_INTERPRETER) -/* Alpha and SH4 user mode emulations and Softmmu call GETPC(). +/* Softmmu, Alpha, MIPS, SH4 and SPARC user mode emulations call GETPC(). For all others, GETPC remains undefined (which makes TCI a little faster. */ -# if defined(CONFIG_SOFTMMU) || defined(TARGET_ALPHA) || defined(TARGET_SH4) \ - || defined(TARGET_SPARC) +# if defined(CONFIG_SOFTMMU) || \ + defined(TARGET_ALPHA) || defined(TARGET_MIPS) || \ + defined(TARGET_SH4) || defined(TARGET_SPARC) extern uintptr_t tci_tb_ptr; # define GETPC() tci_tb_ptr # endif diff --git a/fsdev/qemu-fsdev-dummy.c b/fsdev/qemu-fsdev-dummy.c index 4e700dd4e4..300f2758be 100644 --- a/fsdev/qemu-fsdev-dummy.c +++ b/fsdev/qemu-fsdev-dummy.c @@ -14,6 +14,7 @@ #include <string.h> #include "qemu-fsdev.h" #include "qemu-config.h" +#include "module.h" int qemu_fsdev_add(QemuOpts *opts) { diff --git a/gen-icount.h b/gen-icount.h index 430cb446d0..248cf5b16d 100644 --- a/gen-icount.h +++ b/gen-icount.h @@ -16,7 +16,7 @@ static inline void gen_icount_start(void) count = tcg_temp_local_new_i32(); tcg_gen_ld_i32(count, cpu_env, offsetof(CPUArchState, icount_decr.u32)); /* This is a horrid hack to allow fixing up the value later. */ - icount_arg = gen_opparam_ptr + 1; + icount_arg = tcg_ctx.gen_opparam_ptr + 1; tcg_gen_subi_i32(count, count, 0xdeadbeef); tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, icount_label); diff --git a/hmp-commands.hx b/hmp-commands.hx index b74ef75c39..010b8c9ba5 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1573,13 +1573,6 @@ show roms @end table ETEXI -#ifdef CONFIG_TRACE_SIMPLE -STEXI -@item info trace -show contents of trace buffer -ETEXI -#endif - STEXI @item info trace-events show available trace events and their state diff --git a/hw/Makefile.objs b/hw/Makefile.objs index af4ab0c735..ea46f8128e 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,6 +1,7 @@ common-obj-y = usb/ ide/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o +common-obj-$(CONFIG_VIRTIO) += virtio-rng.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o common-obj-y += fw_cfg.o common-obj-$(CONFIG_PCI) += pci.o pci_bridge.o pci_bridge_dev.o diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 15275cf3e5..519269a013 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -235,10 +235,9 @@ static int vmstate_acpi_post_load(void *opaque, int version_id) { \ .name = (stringify(_field)), \ .version_id = 0, \ - .num = GPE_LEN, \ .info = &vmstate_info_uint16, \ .size = sizeof(uint16_t), \ - .flags = VMS_ARRAY | VMS_POINTER, \ + .flags = VMS_SINGLE | VMS_POINTER, \ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ } @@ -267,11 +266,54 @@ static const VMStateDescription vmstate_pci_status = { } }; +static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) +{ + PIIX4PMState *s = opaque; + int ret, i; + uint16_t temp; + + ret = pci_device_load(&s->dev, f); + if (ret < 0) { + return ret; + } + qemu_get_be16s(f, &s->ar.pm1.evt.sts); + qemu_get_be16s(f, &s->ar.pm1.evt.en); + qemu_get_be16s(f, &s->ar.pm1.cnt.cnt); + + ret = vmstate_load_state(f, &vmstate_apm, opaque, 1); + if (ret) { + return ret; + } + + qemu_get_timer(f, s->ar.tmr.timer); + qemu_get_sbe64s(f, &s->ar.tmr.overflow_time); + + qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts); + for (i = 0; i < 3; i++) { + qemu_get_be16s(f, &temp); + } + + qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en); + for (i = 0; i < 3; i++) { + qemu_get_be16s(f, &temp); + } + + ret = vmstate_load_state(f, &vmstate_pci_status, opaque, 1); + return ret; +} + +/* qemu-kvm 1.2 uses version 3 but advertised as 2 + * To support incoming qemu-kvm 1.2 migration, change version_id + * and minimum_version_id to 2 below (which breaks migration from + * qemu 1.2). + * + */ static const VMStateDescription vmstate_acpi = { .name = "piix4_pm", - .version_id = 2, - .minimum_version_id = 1, + .version_id = 3, + .minimum_version_id = 3, .minimum_version_id_old = 1, + .load_state_old = acpi_load_old, .post_load = vmstate_acpi_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, PIIX4PMState), diff --git a/hw/arm-misc.h b/hw/arm-misc.h index adb166586b..d129678b26 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -12,6 +12,7 @@ #define ARM_MISC_H 1 #include "memory.h" +#include "hw/irq.h" /* The CPU is also modeled as an interrupt controller. */ #define ARM_PIC_CPU_IRQ 0 @@ -23,6 +23,8 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "hw/irq.h" + /* BD Address */ typedef struct { uint8_t b[6]; diff --git a/hw/devices.h b/hw/devices.h index 1a55c1e905..c60bcabae3 100644 --- a/hw/devices.h +++ b/hw/devices.h @@ -1,6 +1,8 @@ #ifndef QEMU_DEVICES_H #define QEMU_DEVICES_H +#include "hw/irq.h" + /* ??? Not all users of this file can include cpu-common.h. */ struct MemoryRegion; @@ -327,7 +327,7 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq); static void fdctrl_reset_fifo(FDCtrl *fdctrl); static int fdctrl_transfer_handler (void *opaque, int nchan, int dma_pos, int dma_len); -static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0); +static void fdctrl_raise_irq(FDCtrl *fdctrl); static FDrive *get_cur_drv(FDCtrl *fdctrl); static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl); @@ -349,12 +349,12 @@ enum { FD_DIR_SCANE = 2, FD_DIR_SCANL = 3, FD_DIR_SCANH = 4, + FD_DIR_VERIFY = 5, }; enum { FD_STATE_MULTI = 0x01, /* multi track flag */ FD_STATE_FORMAT = 0x02, /* format flag */ - FD_STATE_SEEK = 0x04, /* seek flag */ }; enum { @@ -496,7 +496,6 @@ enum { }; #define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI) -#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK) #define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT) struct FDCtrl { @@ -799,6 +798,7 @@ static void fdctrl_handle_tc(void *opaque, int irq, int level) /* Change IRQ state */ static void fdctrl_reset_irq(FDCtrl *fdctrl) { + fdctrl->status0 = 0; if (!(fdctrl->sra & FD_SRA_INTPEND)) return; FLOPPY_DPRINTF("Reset interrupt\n"); @@ -806,14 +806,13 @@ static void fdctrl_reset_irq(FDCtrl *fdctrl) fdctrl->sra &= ~FD_SRA_INTPEND; } -static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0) +static void fdctrl_raise_irq(FDCtrl *fdctrl) { /* Sparc mutation */ if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) { /* XXX: not sure */ fdctrl->msr &= ~FD_MSR_CMDBUSY; fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO; - fdctrl->status0 = status0; return; } if (!(fdctrl->sra & FD_SRA_INTPEND)) { @@ -822,7 +821,6 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0) } fdctrl->reset_sensei = 0; - fdctrl->status0 = status0; FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0); } @@ -851,7 +849,8 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq) fd_recalibrate(&fdctrl->drives[i]); fdctrl_reset_fifo(fdctrl); if (do_irq) { - fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG); + fdctrl->status0 |= FD_SR0_RDYCHG; + fdctrl_raise_irq(fdctrl); fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT; } } @@ -1079,15 +1078,12 @@ static void fdctrl_reset_fifo(FDCtrl *fdctrl) } /* Set FIFO status for the host to read */ -static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, uint8_t status0) +static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len) { fdctrl->data_dir = FD_DIR_READ; fdctrl->data_len = fifo_len; fdctrl->data_pos = 0; fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO; - if (status0) { - fdctrl_raise_irq(fdctrl, status0); - } } /* Set an error: unimplemented/unknown command */ @@ -1096,7 +1092,7 @@ static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction) qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n", fdctrl->fifo[0]); fdctrl->fifo[0] = FD_SR0_INVCMD; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } /* Seek to next sector @@ -1126,11 +1122,13 @@ static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv) } else { new_head = 0; new_track++; + fdctrl->status0 |= FD_SR0_SEEK; if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) { ret = 0; } } } else { + fdctrl->status0 |= FD_SR0_SEEK; new_track++; ret = 0; } @@ -1150,10 +1148,14 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0, uint8_t status1, uint8_t status2) { FDrive *cur_drv; - cur_drv = get_cur_drv(fdctrl); - fdctrl->status0 = status0 | FD_SR0_SEEK | (cur_drv->head << 2) | - GET_CUR_DRV(fdctrl); + + fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD); + fdctrl->status0 |= GET_CUR_DRV(fdctrl); + if (cur_drv->head) { + fdctrl->status0 |= FD_SR0_HEAD; + } + fdctrl->status0 |= status0; FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", status0, status1, status2, fdctrl->status0); @@ -1170,7 +1172,9 @@ static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0, } fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO; fdctrl->msr &= ~FD_MSR_NONDMA; - fdctrl_set_fifo(fdctrl, 7, fdctrl->status0); + + fdctrl_set_fifo(fdctrl, 7); + fdctrl_raise_irq(fdctrl); } /* Prepare a data transfer (either DMA or FIFO) */ @@ -1178,7 +1182,6 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) { FDrive *cur_drv; uint8_t kh, kt, ks; - int did_seek = 0; SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK); cur_drv = get_cur_drv(fdctrl); @@ -1212,7 +1215,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) fdctrl->fifo[5] = ks; return; case 1: - did_seek = 1; + fdctrl->status0 |= FD_SR0_SEEK; break; default: break; @@ -1234,16 +1237,12 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) /* Set the FIFO state */ fdctrl->data_dir = direction; fdctrl->data_pos = 0; - fdctrl->msr |= FD_MSR_CMDBUSY; + assert(fdctrl->msr & FD_MSR_CMDBUSY); if (fdctrl->fifo[0] & 0x80) fdctrl->data_state |= FD_STATE_MULTI; else fdctrl->data_state &= ~FD_STATE_MULTI; - if (did_seek) - fdctrl->data_state |= FD_STATE_SEEK; - else - fdctrl->data_state &= ~FD_STATE_SEEK; - if (fdctrl->fifo[5] == 00) { + if (fdctrl->fifo[5] == 0) { fdctrl->data_len = fdctrl->fifo[8]; } else { int tmp; @@ -1266,14 +1265,21 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL || direction == FD_DIR_SCANH) && dma_mode == 0) || (direction == FD_DIR_WRITE && dma_mode == 2) || - (direction == FD_DIR_READ && dma_mode == 1)) { + (direction == FD_DIR_READ && dma_mode == 1) || + (direction == FD_DIR_VERIFY)) { /* No access is allowed until DMA transfer has completed */ fdctrl->msr &= ~FD_MSR_RQM; - /* Now, we just have to wait for the DMA controller to - * recall us... - */ - DMA_hold_DREQ(fdctrl->dma_chann); - DMA_schedule(fdctrl->dma_chann); + if (direction != FD_DIR_VERIFY) { + /* Now, we just have to wait for the DMA controller to + * recall us... + */ + DMA_hold_DREQ(fdctrl->dma_chann); + DMA_schedule(fdctrl->dma_chann); + } else { + /* Start transfer */ + fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0, + fdctrl->data_len); + } return; } else { FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode, @@ -1285,7 +1291,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) if (direction != FD_DIR_WRITE) fdctrl->msr |= FD_MSR_DIO; /* IO based transfer: calculate len */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl_raise_irq(fdctrl); } /* Prepare a transfer of deleted data */ @@ -1376,6 +1382,9 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, goto transfer_error; } break; + case FD_DIR_VERIFY: + /* VERIFY commands */ + break; default: /* SCAN commands */ { @@ -1411,8 +1420,6 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, fdctrl->data_dir == FD_DIR_SCANL || fdctrl->data_dir == FD_DIR_SCANH) status2 = FD_SR2_SEH; - if (FD_DID_SEEK(fdctrl->data_state)) - status0 |= FD_SR0_SEEK; fdctrl->data_len -= len; fdctrl_stop_transfer(fdctrl, status0, status1, status2); transfer_error: @@ -1458,7 +1465,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl) * then from status mode to command mode */ if (fdctrl->msr & FD_MSR_NONDMA) { - fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } else { fdctrl_reset_fifo(fdctrl); fdctrl_reset_irq(fdctrl); @@ -1506,7 +1513,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl) fdctrl->fifo[5] = ks; return; case 1: - fdctrl->data_state |= FD_STATE_SEEK; + fdctrl->status0 |= FD_SR0_SEEK; break; default: break; @@ -1520,10 +1527,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl) if (cur_drv->sect == cur_drv->last_sect) { fdctrl->data_state &= ~FD_STATE_FORMAT; /* Last sector done */ - if (FD_DID_SEEK(fdctrl->data_state)) - fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); - else - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } else { /* More to do */ fdctrl->data_pos = 0; @@ -1536,7 +1540,7 @@ static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction) { fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0; fdctrl->fifo[0] = fdctrl->lock << 4; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction) @@ -1561,20 +1565,20 @@ static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction) (cur_drv->perpendicular << 2); fdctrl->fifo[8] = fdctrl->config; fdctrl->fifo[9] = fdctrl->precomp_trk; - fdctrl_set_fifo(fdctrl, 10, 0); + fdctrl_set_fifo(fdctrl, 10); } static void fdctrl_handle_version(FDCtrl *fdctrl, int direction) { /* Controller's version */ fdctrl->fifo[0] = fdctrl->version; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction) { fdctrl->fifo[0] = 0x41; /* Stepping 1 */ - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction) @@ -1627,7 +1631,7 @@ static void fdctrl_handle_save(FDCtrl *fdctrl, int direction) fdctrl->fifo[12] = fdctrl->pwrd; fdctrl->fifo[13] = 0; fdctrl->fifo[14] = 0; - fdctrl_set_fifo(fdctrl, 15, 0); + fdctrl_set_fifo(fdctrl, 15); } static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction) @@ -1650,7 +1654,6 @@ static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction) fdctrl->data_state |= FD_STATE_MULTI; else fdctrl->data_state &= ~FD_STATE_MULTI; - fdctrl->data_state &= ~FD_STATE_SEEK; cur_drv->bps = fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2]; #if 0 @@ -1693,7 +1696,7 @@ static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction) (cur_drv->head << 2) | GET_CUR_DRV(fdctrl) | 0x28; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction) @@ -1705,7 +1708,8 @@ static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction) fd_recalibrate(cur_drv); fdctrl_reset_fifo(fdctrl); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl->status0 |= FD_SR0_SEEK; + fdctrl_raise_irq(fdctrl); } static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction) @@ -1718,7 +1722,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction) fdctrl->reset_sensei--; } else if (!(fdctrl->sra & FD_SRA_INTPEND)) { fdctrl->fifo[0] = FD_SR0_INVCMD; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); return; } else { fdctrl->fifo[0] = @@ -1727,7 +1731,7 @@ static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction) } fdctrl->fifo[1] = cur_drv->track; - fdctrl_set_fifo(fdctrl, 2, 0); + fdctrl_set_fifo(fdctrl, 2); fdctrl_reset_irq(fdctrl); fdctrl->status0 = FD_SR0_RDYCHG; } @@ -1744,7 +1748,8 @@ static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction) */ fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl->status0 |= FD_SR0_SEEK; + fdctrl_raise_irq(fdctrl); } static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction) @@ -1769,7 +1774,7 @@ static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction) { fdctrl->pwrd = fdctrl->fifo[1]; fdctrl->fifo[0] = fdctrl->fifo[1]; - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } static void fdctrl_handle_option(FDCtrl *fdctrl, int direction) @@ -1788,7 +1793,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct fdctrl->fifo[0] = fdctrl->fifo[1]; fdctrl->fifo[2] = 0; fdctrl->fifo[3] = 0; - fdctrl_set_fifo(fdctrl, 4, 0); + fdctrl_set_fifo(fdctrl, 4); } else { fdctrl_reset_fifo(fdctrl); } @@ -1796,7 +1801,7 @@ static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direct /* ERROR */ fdctrl->fifo[0] = 0x80 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl); - fdctrl_set_fifo(fdctrl, 1, 0); + fdctrl_set_fifo(fdctrl, 1); } } @@ -1815,7 +1820,8 @@ static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction) } fdctrl_reset_fifo(fdctrl); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl->status0 |= FD_SR0_SEEK; + fdctrl_raise_irq(fdctrl); } static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction) @@ -1832,7 +1838,8 @@ static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction) } fdctrl_reset_fifo(fdctrl); /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); + fdctrl->status0 |= FD_SR0_SEEK; + fdctrl_raise_irq(fdctrl); } static const struct { @@ -1854,7 +1861,7 @@ static const struct { { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */ { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ }, { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE }, - { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_unimplemented }, + { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY }, { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL }, { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH }, { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE }, @@ -1918,7 +1925,7 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value) * then from status mode to command mode */ if (fdctrl->data_pos == fdctrl->data_len) - fdctrl_stop_transfer(fdctrl, FD_SR0_SEEK, 0x00, 0x00); + fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); return; } if (fdctrl->data_pos == 0) { diff --git a/hw/ide/core.c b/hw/ide/core.c index d683a8cc84..7d6b0fa7b4 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -336,7 +336,7 @@ static void trim_aio_cancel(BlockDriverAIOCB *acb) qemu_aio_release(iocb); } -static AIOPool trim_aio_pool = { +static const AIOCBInfo trim_aiocb_info = { .aiocb_size = sizeof(TrimAIOCB), .cancel = trim_aio_cancel, }; @@ -360,7 +360,7 @@ BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, TrimAIOCB *iocb; int i, j, ret; - iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque); + iocb = qemu_aio_get(&trim_aiocb_info, bs, cb, opaque); iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); iocb->ret = 0; @@ -3,6 +3,8 @@ /* Generic IRQ/GPIO pin infrastructure. */ +typedef struct IRQState *qemu_irq; + typedef void (*qemu_irq_handler)(void *opaque, int n, int level); void qemu_set_irq(qemu_irq irq, int level); diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 98839f278d..7d84ce3d74 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -25,6 +25,7 @@ #include "qemu-timer.h" #include "sysemu.h" #include "mc146818rtc.h" +#include "qapi/qapi-visit-core.h" #ifdef TARGET_I386 #include "apic.h" diff --git a/hw/megasas.c b/hw/megasas.c index 291ff40403..61b6527928 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -1296,7 +1296,7 @@ static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd) static int megasas_cache_flush(MegasasState *s, MegasasCmd *cmd) { - qemu_aio_flush(); + bdrv_drain_all(); return MFI_STAT_OK; } diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 0571d58908..4d2464a02c 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -861,7 +861,8 @@ void mips_malta_init(QEMUMachineInitArgs *args) be = 0; #endif /* FPGA */ - malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[2], serial_hds[2]); + /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */ + malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[4], serial_hds[2]); /* Load firmware in flash / BIOS. */ dinfo = drive_get(IF_PFLASH, 0, fl_idx); @@ -19,6 +19,7 @@ #ifndef hw_omap_h #include "memory.h" # define hw_omap_h "omap.h" +#include "hw/irq.h" # define OMAP_EMIFS_BASE 0x00000000 # define OMAP2_Q0_BASE 0x00000000 @@ -367,6 +367,10 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) pci_update_mappings(s); + memory_region_set_enabled(&s->bus_master_enable_region, + pci_get_word(s->config + PCI_COMMAND) + & PCI_COMMAND_MASTER); + g_free(config); return 0; } @@ -76,6 +76,7 @@ #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 #define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define FMT_PCIBUS PRIx64 diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index de0ba8726e..ea32c31ab6 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -1,6 +1,7 @@ #include "qdev.h" #include "qdev-addr.h" #include "hwaddr.h" +#include "qapi/qapi-visit-core.h" /* --- target physical address --- */ diff --git a/hw/qdev-core.h b/hw/qdev-core.h new file mode 100644 index 0000000000..fce9e2249c --- /dev/null +++ b/hw/qdev-core.h @@ -0,0 +1,238 @@ +#ifndef QDEV_CORE_H +#define QDEV_CORE_H + +#include "qemu-queue.h" +#include "qemu-option.h" +#include "qemu/object.h" +#include "hw/irq.h" +#include "error.h" + +typedef struct Property Property; + +typedef struct PropertyInfo PropertyInfo; + +typedef struct CompatProperty CompatProperty; + +typedef struct BusState BusState; + +typedef struct BusClass BusClass; + +enum DevState { + DEV_STATE_CREATED = 1, + DEV_STATE_INITIALIZED, +}; + +enum { + DEV_NVECTORS_UNSPECIFIED = -1, +}; + +#define TYPE_DEVICE "device" +#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE) +#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE) +#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE) + +typedef int (*qdev_initfn)(DeviceState *dev); +typedef int (*qdev_event)(DeviceState *dev); +typedef void (*qdev_resetfn)(DeviceState *dev); + +struct VMStateDescription; + +typedef struct DeviceClass { + ObjectClass parent_class; + + const char *fw_name; + const char *desc; + Property *props; + int no_user; + + /* callbacks */ + void (*reset)(DeviceState *dev); + + /* device state */ + const struct VMStateDescription *vmsd; + + /* Private to qdev / bus. */ + qdev_initfn init; + qdev_event unplug; + qdev_event exit; + const char *bus_type; +} DeviceClass; + +/* This structure should not be accessed directly. We declare it here + so that it can be embedded in individual device state structures. */ +struct DeviceState { + Object parent_obj; + + const char *id; + enum DevState state; + QemuOpts *opts; + int hotplugged; + BusState *parent_bus; + int num_gpio_out; + qemu_irq *gpio_out; + int num_gpio_in; + qemu_irq *gpio_in; + QLIST_HEAD(, BusState) child_bus; + int num_child_bus; + int instance_id_alias; + int alias_required_for_version; +}; + +#define TYPE_BUS "bus" +#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS) +#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS) +#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS) + +struct BusClass { + ObjectClass parent_class; + + /* FIXME first arg should be BusState */ + void (*print_dev)(Monitor *mon, DeviceState *dev, int indent); + char *(*get_dev_path)(DeviceState *dev); + /* + * This callback is used to create Open Firmware device path in accordance + * with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus + * bindings can be found at http://playground.sun.com/1275/bindings/. + */ + char *(*get_fw_dev_path)(DeviceState *dev); + int (*reset)(BusState *bus); +}; + +typedef struct BusChild { + DeviceState *child; + int index; + QTAILQ_ENTRY(BusChild) sibling; +} BusChild; + +/** + * BusState: + * @qom_allocated: Indicates whether the object was allocated by QOM. + * @glib_allocated: Indicates whether the object was initialized in-place + * yet is expected to be freed with g_free(). + */ +struct BusState { + Object obj; + DeviceState *parent; + const char *name; + int allow_hotplug; + bool qom_allocated; + bool glib_allocated; + int max_index; + QTAILQ_HEAD(ChildrenHead, BusChild) children; + QLIST_ENTRY(BusState) sibling; +}; + +struct Property { + const char *name; + PropertyInfo *info; + int offset; + uint8_t bitnr; + uint8_t qtype; + int64_t defval; +}; + +struct PropertyInfo { + const char *name; + const char *legacy_name; + const char **enum_table; + int (*parse)(DeviceState *dev, Property *prop, const char *str); + int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); + ObjectPropertyAccessor *get; + ObjectPropertyAccessor *set; + ObjectPropertyRelease *release; +}; + +typedef struct GlobalProperty { + const char *driver; + const char *property; + const char *value; + QTAILQ_ENTRY(GlobalProperty) next; +} GlobalProperty; + +/*** Board API. This should go away once we have a machine config file. ***/ + +DeviceState *qdev_create(BusState *bus, const char *name); +DeviceState *qdev_try_create(BusState *bus, const char *name); +int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; +void qdev_init_nofail(DeviceState *dev); +void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, + int required_for_version); +void qdev_unplug(DeviceState *dev, Error **errp); +void qdev_free(DeviceState *dev); +int qdev_simple_unplug_cb(DeviceState *dev); +void qdev_machine_creation_done(void); +bool qdev_machine_modified(void); + +qemu_irq qdev_get_gpio_in(DeviceState *dev, int n); +void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); + +BusState *qdev_get_child_bus(DeviceState *dev, const char *name); + +/*** Device API. ***/ + +/* Register device properties. */ +/* GPIO inputs also double as IRQ sinks. */ +void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); +void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); + +BusState *qdev_get_parent_bus(DeviceState *dev); + +/*** BUS API. ***/ + +DeviceState *qdev_find_recursive(BusState *bus, const char *id); + +/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */ +typedef int (qbus_walkerfn)(BusState *bus, void *opaque); +typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque); + +void qbus_create_inplace(BusState *bus, const char *typename, + DeviceState *parent, const char *name); +BusState *qbus_create(const char *typename, DeviceState *parent, const char *name); +/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion, + * < 0 if either devfn or busfn terminate walk somewhere in cursion, + * 0 otherwise. */ +int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque); +int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque); +void qdev_reset_all(DeviceState *dev); +void qbus_reset_all_fn(void *opaque); + +void qbus_free(BusState *bus); + +#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev) + +/* This should go away once we get rid of the NULL bus hack */ +BusState *sysbus_get_default(void); + +char *qdev_get_fw_dev_path(DeviceState *dev); + +/** + * @qdev_machine_init + * + * Initialize platform devices before machine init. This is a hack until full + * support for composition is added. + */ +void qdev_machine_init(void); + +/** + * @device_reset + * + * Reset a single device (by calling the reset method). + */ +void device_reset(DeviceState *dev); + +const struct VMStateDescription *qdev_get_vmsd(DeviceState *dev); + +const char *qdev_fw_name(DeviceState *dev); + +Object *qdev_get_machine(void); + +/* FIXME: make this a link<> */ +void qdev_set_parent_bus(DeviceState *dev, BusState *bus); + +extern int qdev_hotplug; + +char *qdev_get_dev_path(DeviceState *dev); + +#endif diff --git a/hw/qdev-monitor.h b/hw/qdev-monitor.h new file mode 100644 index 0000000000..220ceba4c5 --- /dev/null +++ b/hw/qdev-monitor.h @@ -0,0 +1,16 @@ +#ifndef QEMU_QDEV_MONITOR_H +#define QEMU_QDEV_MONITOR_H + +#include "qdev-core.h" +#include "monitor.h" + +/*** monitor commands ***/ + +void do_info_qtree(Monitor *mon); +void do_info_qdm(Monitor *mon); +int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); +int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data); +int qdev_device_help(QemuOpts *opts); +DeviceState *qdev_device_add(QemuOpts *opts); + +#endif diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 8aca0d43fe..81d901c6c4 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -4,6 +4,7 @@ #include "blockdev.h" #include "hw/block-common.h" #include "net/hub.h" +#include "qapi/qapi-visit-core.h" void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) { diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h new file mode 100644 index 0000000000..5b046abb28 --- /dev/null +++ b/hw/qdev-properties.h @@ -0,0 +1,130 @@ +#ifndef QEMU_QDEV_PROPERTIES_H +#define QEMU_QDEV_PROPERTIES_H + +#include "qdev-core.h" + +/*** qdev-properties.c ***/ + +extern PropertyInfo qdev_prop_bit; +extern PropertyInfo qdev_prop_uint8; +extern PropertyInfo qdev_prop_uint16; +extern PropertyInfo qdev_prop_uint32; +extern PropertyInfo qdev_prop_int32; +extern PropertyInfo qdev_prop_uint64; +extern PropertyInfo qdev_prop_hex8; +extern PropertyInfo qdev_prop_hex32; +extern PropertyInfo qdev_prop_hex64; +extern PropertyInfo qdev_prop_string; +extern PropertyInfo qdev_prop_chr; +extern PropertyInfo qdev_prop_ptr; +extern PropertyInfo qdev_prop_macaddr; +extern PropertyInfo qdev_prop_losttickpolicy; +extern PropertyInfo qdev_prop_bios_chs_trans; +extern PropertyInfo qdev_prop_drive; +extern PropertyInfo qdev_prop_netdev; +extern PropertyInfo qdev_prop_vlan; +extern PropertyInfo qdev_prop_pci_devfn; +extern PropertyInfo qdev_prop_blocksize; +extern PropertyInfo qdev_prop_pci_host_devaddr; + +#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ + .name = (_name), \ + .info = &(_prop), \ + .offset = offsetof(_state, _field) \ + + type_check(_type,typeof_field(_state, _field)), \ + } +#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \ + .name = (_name), \ + .info = &(_prop), \ + .offset = offsetof(_state, _field) \ + + type_check(_type,typeof_field(_state, _field)), \ + .qtype = QTYPE_QINT, \ + .defval = (_type)_defval, \ + } +#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \ + .name = (_name), \ + .info = &(qdev_prop_bit), \ + .bitnr = (_bit), \ + .offset = offsetof(_state, _field) \ + + type_check(uint32_t,typeof_field(_state, _field)), \ + .qtype = QTYPE_QBOOL, \ + .defval = (bool)_defval, \ + } + +#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) +#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t) +#define DEFINE_PROP_UINT32(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t) +#define DEFINE_PROP_INT32(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t) +#define DEFINE_PROP_UINT64(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t) +#define DEFINE_PROP_HEX8(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t) +#define DEFINE_PROP_HEX32(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t) +#define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) +#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) + +#define DEFINE_PROP_PTR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*) +#define DEFINE_PROP_CHR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*) +#define DEFINE_PROP_STRING(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) +#define DEFINE_PROP_NETDEV(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*) +#define DEFINE_PROP_VLAN(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*) +#define DEFINE_PROP_DRIVE(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *) +#define DEFINE_PROP_MACADDR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) +#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \ + LostTickPolicy) +#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int) +#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t) +#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress) + +#define DEFINE_PROP_END_OF_LIST() \ + {} + +/* Set properties between creation and init. */ +void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); +int qdev_prop_parse(DeviceState *dev, const char *name, const char *value); +void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value); +void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value); +void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value); +void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value); +void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value); +void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value); +void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value); +void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value); +void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value); +int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT; +void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value); +void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); +void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); +/* FIXME: Remove opaque pointer properties. */ +void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); + +void qdev_prop_register_global_list(GlobalProperty *props); +void qdev_prop_set_globals(DeviceState *dev); +void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, + Property *prop, const char *value); + +/** + * @qdev_property_add_static - add a @Property to a device referencing a + * field in a struct. + */ +void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp); + +#endif @@ -29,6 +29,7 @@ #include "qdev.h" #include "sysemu.h" #include "error.h" +#include "qapi/qapi-visit-core.h" int qdev_hotplug = 0; static bool qdev_hot_added = false; @@ -1,371 +1,9 @@ #ifndef QDEV_H #define QDEV_H -#include "hw.h" -#include "qemu-queue.h" -#include "qemu-char.h" -#include "qemu-option.h" -#include "qapi/qapi-visit-core.h" -#include "qemu/object.h" -#include "error.h" - -typedef struct Property Property; - -typedef struct PropertyInfo PropertyInfo; - -typedef struct CompatProperty CompatProperty; - -typedef struct BusState BusState; - -typedef struct BusClass BusClass; - -enum DevState { - DEV_STATE_CREATED = 1, - DEV_STATE_INITIALIZED, -}; - -enum { - DEV_NVECTORS_UNSPECIFIED = -1, -}; - -#define TYPE_DEVICE "device" -#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE) -#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE) -#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE) - -typedef int (*qdev_initfn)(DeviceState *dev); -typedef int (*qdev_event)(DeviceState *dev); -typedef void (*qdev_resetfn)(DeviceState *dev); - -typedef struct DeviceClass { - ObjectClass parent_class; - - const char *fw_name; - const char *desc; - Property *props; - int no_user; - - /* callbacks */ - void (*reset)(DeviceState *dev); - - /* device state */ - const VMStateDescription *vmsd; - - /* Private to qdev / bus. */ - qdev_initfn init; - qdev_event unplug; - qdev_event exit; - const char *bus_type; -} DeviceClass; - -/* This structure should not be accessed directly. We declare it here - so that it can be embedded in individual device state structures. */ -struct DeviceState { - Object parent_obj; - - const char *id; - enum DevState state; - QemuOpts *opts; - int hotplugged; - BusState *parent_bus; - int num_gpio_out; - qemu_irq *gpio_out; - int num_gpio_in; - qemu_irq *gpio_in; - QLIST_HEAD(, BusState) child_bus; - int num_child_bus; - int instance_id_alias; - int alias_required_for_version; -}; - -#define TYPE_BUS "bus" -#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS) -#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS) -#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS) - -struct BusClass { - ObjectClass parent_class; - - /* FIXME first arg should be BusState */ - void (*print_dev)(Monitor *mon, DeviceState *dev, int indent); - char *(*get_dev_path)(DeviceState *dev); - /* - * This callback is used to create Open Firmware device path in accordance - * with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus - * bindings can be found at http://playground.sun.com/1275/bindings/. - */ - char *(*get_fw_dev_path)(DeviceState *dev); - int (*reset)(BusState *bus); -}; - -typedef struct BusChild { - DeviceState *child; - int index; - QTAILQ_ENTRY(BusChild) sibling; -} BusChild; - -/** - * BusState: - * @qom_allocated: Indicates whether the object was allocated by QOM. - * @glib_allocated: Indicates whether the object was initialized in-place - * yet is expected to be freed with g_free(). - */ -struct BusState { - Object obj; - DeviceState *parent; - const char *name; - int allow_hotplug; - bool qom_allocated; - bool glib_allocated; - int max_index; - QTAILQ_HEAD(ChildrenHead, BusChild) children; - QLIST_ENTRY(BusState) sibling; -}; - -struct Property { - const char *name; - PropertyInfo *info; - int offset; - uint8_t bitnr; - uint8_t qtype; - int64_t defval; -}; - -struct PropertyInfo { - const char *name; - const char *legacy_name; - const char **enum_table; - int (*parse)(DeviceState *dev, Property *prop, const char *str); - int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); - ObjectPropertyAccessor *get; - ObjectPropertyAccessor *set; - ObjectPropertyRelease *release; -}; - -typedef struct GlobalProperty { - const char *driver; - const char *property; - const char *value; - QTAILQ_ENTRY(GlobalProperty) next; -} GlobalProperty; - -/*** Board API. This should go away once we have a machine config file. ***/ - -DeviceState *qdev_create(BusState *bus, const char *name); -DeviceState *qdev_try_create(BusState *bus, const char *name); -int qdev_device_help(QemuOpts *opts); -DeviceState *qdev_device_add(QemuOpts *opts); -int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; -void qdev_init_nofail(DeviceState *dev); -void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, - int required_for_version); -void qdev_unplug(DeviceState *dev, Error **errp); -void qdev_free(DeviceState *dev); -int qdev_simple_unplug_cb(DeviceState *dev); -void qdev_machine_creation_done(void); -bool qdev_machine_modified(void); - -qemu_irq qdev_get_gpio_in(DeviceState *dev, int n); -void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin); - -BusState *qdev_get_child_bus(DeviceState *dev, const char *name); - -/*** Device API. ***/ - -/* Register device properties. */ -/* GPIO inputs also double as IRQ sinks. */ -void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); -void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); - -BusState *qdev_get_parent_bus(DeviceState *dev); - -/*** BUS API. ***/ - -DeviceState *qdev_find_recursive(BusState *bus, const char *id); - -/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */ -typedef int (qbus_walkerfn)(BusState *bus, void *opaque); -typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque); - -void qbus_create_inplace(BusState *bus, const char *typename, - DeviceState *parent, const char *name); -BusState *qbus_create(const char *typename, DeviceState *parent, const char *name); -/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion, - * < 0 if either devfn or busfn terminate walk somewhere in cursion, - * 0 otherwise. */ -int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, - qbus_walkerfn *busfn, void *opaque); -int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, - qbus_walkerfn *busfn, void *opaque); -void qdev_reset_all(DeviceState *dev); -void qbus_reset_all_fn(void *opaque); - -void qbus_free(BusState *bus); - -#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev) - -/* This should go away once we get rid of the NULL bus hack */ -BusState *sysbus_get_default(void); - -/*** monitor commands ***/ - -void do_info_qtree(Monitor *mon); -void do_info_qdm(Monitor *mon); -int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); -int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data); - -/*** qdev-properties.c ***/ - -extern PropertyInfo qdev_prop_bit; -extern PropertyInfo qdev_prop_uint8; -extern PropertyInfo qdev_prop_uint16; -extern PropertyInfo qdev_prop_uint32; -extern PropertyInfo qdev_prop_int32; -extern PropertyInfo qdev_prop_uint64; -extern PropertyInfo qdev_prop_hex8; -extern PropertyInfo qdev_prop_hex32; -extern PropertyInfo qdev_prop_hex64; -extern PropertyInfo qdev_prop_string; -extern PropertyInfo qdev_prop_chr; -extern PropertyInfo qdev_prop_ptr; -extern PropertyInfo qdev_prop_macaddr; -extern PropertyInfo qdev_prop_losttickpolicy; -extern PropertyInfo qdev_prop_bios_chs_trans; -extern PropertyInfo qdev_prop_drive; -extern PropertyInfo qdev_prop_netdev; -extern PropertyInfo qdev_prop_vlan; -extern PropertyInfo qdev_prop_pci_devfn; -extern PropertyInfo qdev_prop_blocksize; -extern PropertyInfo qdev_prop_pci_host_devaddr; - -#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ - .name = (_name), \ - .info = &(_prop), \ - .offset = offsetof(_state, _field) \ - + type_check(_type,typeof_field(_state, _field)), \ - } -#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \ - .name = (_name), \ - .info = &(_prop), \ - .offset = offsetof(_state, _field) \ - + type_check(_type,typeof_field(_state, _field)), \ - .qtype = QTYPE_QINT, \ - .defval = (_type)_defval, \ - } -#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) { \ - .name = (_name), \ - .info = &(qdev_prop_bit), \ - .bitnr = (_bit), \ - .offset = offsetof(_state, _field) \ - + type_check(uint32_t,typeof_field(_state, _field)), \ - .qtype = QTYPE_QBOOL, \ - .defval = (bool)_defval, \ - } - -#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) -#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t) -#define DEFINE_PROP_UINT32(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t) -#define DEFINE_PROP_INT32(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t) -#define DEFINE_PROP_UINT64(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t) -#define DEFINE_PROP_HEX8(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t) -#define DEFINE_PROP_HEX32(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t) -#define DEFINE_PROP_HEX64(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) -#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t) - -#define DEFINE_PROP_PTR(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*) -#define DEFINE_PROP_CHR(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*) -#define DEFINE_PROP_STRING(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) -#define DEFINE_PROP_NETDEV(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*) -#define DEFINE_PROP_VLAN(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*) -#define DEFINE_PROP_DRIVE(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *) -#define DEFINE_PROP_MACADDR(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) -#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \ - LostTickPolicy) -#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int) -#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \ - DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t) -#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress) - -#define DEFINE_PROP_END_OF_LIST() \ - {} - -/* Set properties between creation and init. */ -void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); -int qdev_prop_parse(DeviceState *dev, const char *name, const char *value); -void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value); -void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value); -void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value); -void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value); -void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value); -void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value); -void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value); -void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value); -void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value); -int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT; -void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value); -void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); -void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); -/* FIXME: Remove opaque pointer properties. */ -void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); - -void qdev_prop_register_global_list(GlobalProperty *props); -void qdev_prop_set_globals(DeviceState *dev); -void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, - Property *prop, const char *value); - -char *qdev_get_fw_dev_path(DeviceState *dev); - -/** - * @qdev_property_add_static - add a @Property to a device referencing a - * field in a struct. - */ -void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp); - -/** - * @qdev_machine_init - * - * Initialize platform devices before machine init. This is a hack until full - * support for composition is added. - */ -void qdev_machine_init(void); - -/** - * @device_reset - * - * Reset a single device (by calling the reset method). - */ -void device_reset(DeviceState *dev); - -const VMStateDescription *qdev_get_vmsd(DeviceState *dev); - -const char *qdev_fw_name(DeviceState *dev); - -Object *qdev_get_machine(void); - -/* FIXME: make this a link<> */ -void qdev_set_parent_bus(DeviceState *dev, BusState *bus); - -extern int qdev_hotplug; - -char *qdev_get_dev_path(DeviceState *dev); +#include "hw/hw.h" +#include "qdev-core.h" +#include "qdev-properties.h" +#include "qdev-monitor.h" #endif diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 5849a964a4..e0ac2d1ec2 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -26,6 +26,7 @@ #include "loader.h" #include "elf.h" #include "hw/virtio.h" +#include "hw/virtio-rng.h" #include "hw/virtio-serial.h" #include "hw/virtio-net.h" #include "hw/sysbus.h" @@ -206,6 +207,18 @@ static int s390_virtio_scsi_init(VirtIOS390Device *dev) return s390_virtio_device_init(dev, vdev); } +static int s390_virtio_rng_init(VirtIOS390Device *dev) +{ + VirtIODevice *vdev; + + vdev = virtio_rng_init((DeviceState *)dev, &dev->rng); + if (!vdev) { + return -1; + } + + return s390_virtio_device_init(dev, vdev); +} + static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq) { ram_addr_t token_off; @@ -448,6 +461,29 @@ static TypeInfo s390_virtio_serial = { .class_init = s390_virtio_serial_class_init, }; +static void s390_virtio_rng_initfn(Object *obj) +{ + VirtIOS390Device *dev = VIRTIO_S390_DEVICE(obj); + + object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, + (Object **)&dev->rng.rng, NULL); +} + +static void s390_virtio_rng_class_init(ObjectClass *klass, void *data) +{ + VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass); + + k->init = s390_virtio_rng_init; +} + +static TypeInfo s390_virtio_rng = { + .name = "virtio-rng-s390", + .parent = TYPE_VIRTIO_S390_DEVICE, + .instance_size = sizeof(VirtIOS390Device), + .instance_init = s390_virtio_rng_initfn, + .class_init = s390_virtio_rng_class_init, +}; + static int s390_virtio_busdev_init(DeviceState *dev) { VirtIOS390Device *_dev = (VirtIOS390Device *)dev; @@ -528,6 +564,7 @@ static void s390_virtio_register_types(void) type_register_static(&s390_virtio_blk); type_register_static(&s390_virtio_net); type_register_static(&s390_virtio_scsi); + type_register_static(&s390_virtio_rng); type_register_static(&s390_virtio_bridge_info); } diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 4873134ae9..a83afe785f 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -19,6 +19,7 @@ #include "virtio-blk.h" #include "virtio-net.h" +#include "virtio-rng.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -75,6 +76,7 @@ struct VirtIOS390Device { virtio_serial_conf serial; virtio_net_conf net; VirtIOSCSIConf scsi; + VirtIORNGConf rng; }; typedef struct VirtIOS390Bus { diff --git a/hw/soc_dma.h b/hw/soc_dma.h index 9340b8f38e..5948489eae 100644 --- a/hw/soc_dma.h +++ b/hw/soc_dma.h @@ -19,6 +19,7 @@ */ #include "memory.h" +#include "hw/irq.h" struct soc_dma_s; struct soc_dma_ch_s; diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index fe45a1fbba..5887eab197 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -17,6 +17,7 @@ #include "hw/usb/hcd-ehci.h" #include "hw/pci.h" +#include "range.h" typedef struct EHCIPCIState { PCIDevice pcidev; @@ -79,6 +80,21 @@ static int usb_ehci_pci_initfn(PCIDevice *dev) return 0; } +static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, + uint32_t val, int l) +{ + EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev); + bool busmaster; + + pci_default_write_config(dev, addr, val, l); + + if (!range_covers_byte(addr, l, PCI_COMMAND)) { + return; + } + busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER; + i->ehci.dma = busmaster ? pci_dma_context(dev) : NULL; +} + static Property ehci_pci_properties[] = { DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128), DEFINE_PROP_END_OF_LIST(), @@ -106,6 +122,7 @@ static void ehci_class_init(ObjectClass *klass, void *data) k->device_id = i->device_id; k->revision = i->revision; k->class_id = PCI_CLASS_SERIAL_USB; + k->config_write = usb_ehci_pci_write_config; dc->vmsd = &vmstate_ehci_pci; dc->props = ehci_pci_properties; } diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index ee6c9ae302..7df8e21ecb 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -189,6 +189,7 @@ static const char *ehci_mmio_names[] = { static int ehci_state_executing(EHCIQueue *q); static int ehci_state_writeback(EHCIQueue *q); +static int ehci_state_advqueue(EHCIQueue *q); static int ehci_fill_queue(EHCIPacket *p); static const char *nr2str(const char **n, size_t len, uint32_t nr) @@ -453,12 +454,16 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) static void ehci_free_packet(EHCIPacket *p) { if (p->async == EHCI_ASYNC_FINISHED) { - int state = ehci_get_state(p->queue->ehci, p->queue->async); + EHCIQueue *q = p->queue; + int state = ehci_get_state(q->ehci, q->async); /* This is a normal, but rare condition (cancel racing completion) */ fprintf(stderr, "EHCI: Warning packet completed but not processed\n"); - ehci_state_executing(p->queue); - ehci_state_writeback(p->queue); - ehci_set_state(p->queue->ehci, p->queue->async, state); + ehci_state_executing(q); + ehci_state_writeback(q); + if (!(q->qh.token & QTD_TOKEN_HALT)) { + ehci_state_advqueue(q); + } + ehci_set_state(q->ehci, q->async, state); /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */ return; } @@ -959,6 +964,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, case USBINTR: val &= USBINTR_MASK; + if (ehci_enabled(s) && (USBSTS_FLR & val)) { + qemu_bh_schedule(s->async_bh); + } break; case FRINDEX: @@ -995,21 +1003,25 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, *mmio, old); } - -// TODO : Put in common header file, duplication from usb-ohci.c - /* Get an array of dwords from main memory */ static inline int get_dwords(EHCIState *ehci, uint32_t addr, uint32_t *buf, int num) { int i; + if (!ehci->dma) { + ehci_raise_irq(ehci, USBSTS_HSE); + ehci->usbcmd &= ~USBCMD_RUNSTOP; + trace_usb_ehci_dma_error(); + return -1; + } + for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { dma_memory_read(ehci->dma, addr, buf, sizeof(*buf)); *buf = le32_to_cpu(*buf); } - return 1; + return num; } /* Put an array of dwords in to main memory */ @@ -1018,12 +1030,19 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr, { int i; + if (!ehci->dma) { + ehci_raise_irq(ehci, USBSTS_HSE); + ehci->usbcmd &= ~USBCMD_RUNSTOP; + trace_usb_ehci_dma_error(); + return -1; + } + for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint32_t tmp = cpu_to_le32(*buf); dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp)); } - return 1; + return num; } /* @@ -1435,8 +1454,10 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) /* Find the head of the list (4.9.1.1) */ for(i = 0; i < MAX_QH; i++) { - get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh, - sizeof(EHCIqh) >> 2); + if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &qh, + sizeof(EHCIqh) >> 2) < 0) { + return 0; + } ehci_trace_qh(NULL, NLPTR_GET(entry), &qh); if (qh.epchar & QH_EPCHAR_H) { @@ -1533,8 +1554,11 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) goto out; } - get_dwords(ehci, NLPTR_GET(q->qhaddr), - (uint32_t *) &qh, sizeof(EHCIqh) >> 2); + if (get_dwords(ehci, NLPTR_GET(q->qhaddr), + (uint32_t *) &qh, sizeof(EHCIqh) >> 2) < 0) { + q = NULL; + goto out; + } ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh); /* @@ -1545,8 +1569,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) endp = get_field(qh.epchar, QH_EPCHAR_EP); if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || - (memcmp(&qh.current_qtd, &q->qh.current_qtd, - 9 * sizeof(uint32_t)) != 0) || + (qh.current_qtd != q->qh.current_qtd) || + (q->async && qh.next_qtd != q->qh.next_qtd) || + (memcmp(&qh.altnext_qtd, &q->qh.altnext_qtd, + 7 * sizeof(uint32_t)) != 0) || (q->dev != NULL && q->dev->addr != devaddr)) { if (ehci_reset_queue(q) > 0) { ehci_trace_guest_bug(ehci, "guest updated active QH"); @@ -1621,8 +1647,10 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async) assert(!async); entry = ehci_get_fetch_addr(ehci, async); - get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd, - sizeof(EHCIitd) >> 2); + if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *) &itd, + sizeof(EHCIitd) >> 2) < 0) { + return -1; + } ehci_trace_itd(ehci, entry, &itd); if (ehci_process_itd(ehci, &itd, entry) != 0) { @@ -1645,8 +1673,10 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async) assert(!async); entry = ehci_get_fetch_addr(ehci, async); - get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd, - sizeof(EHCIsitd) >> 2); + if (get_dwords(ehci, NLPTR_GET(entry), (uint32_t *)&sitd, + sizeof(EHCIsitd) >> 2) < 0) { + return 0; + } ehci_trace_sitd(ehci, entry, &sitd); if (!(sitd.results & SITD_RESULTS_ACTIVE)) { @@ -1707,14 +1737,17 @@ static int ehci_state_fetchqtd(EHCIQueue *q) EHCIPacket *p; int again = 1; - get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, - sizeof(EHCIqtd) >> 2); + if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, + sizeof(EHCIqtd) >> 2) < 0) { + return 0; + } ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd); p = QTAILQ_FIRST(&q->packets); if (p != NULL) { if (p->qtdaddr != q->qtdaddr || - (!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) || + (q->async && !NLPTR_TBIT(p->qtd.next) && + (p->qtd.next != qtd.next)) || (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) || p->qtd.bufptr[0] != qtd.bufptr[0]) { ehci_cancel_queue(q); @@ -1785,7 +1818,7 @@ static int ehci_fill_queue(EHCIPacket *p) USBEndpoint *ep = p->packet.ep; EHCIQueue *q = p->queue; EHCIqtd qtd = p->qtd; - uint32_t qtdaddr, start_addr = p->qtdaddr; + uint32_t qtdaddr; for (;;) { if (NLPTR_TBIT(qtd.next) != 0) { @@ -1796,11 +1829,15 @@ static int ehci_fill_queue(EHCIPacket *p) * Detect circular td lists, Windows creates these, counting on the * active bit going low after execution to make the queue stop. */ - if (qtdaddr == start_addr) { - break; + QTAILQ_FOREACH(p, &q->packets, next) { + if (p->qtdaddr == qtdaddr) { + goto leave; + } + } + if (get_dwords(q->ehci, NLPTR_GET(qtdaddr), + (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2) < 0) { + return -1; } - get_dwords(q->ehci, NLPTR_GET(qtdaddr), - (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); ehci_trace_qtd(q, NLPTR_GET(qtdaddr), &qtd); if (!(qtd.token & QTD_TOKEN_ACTIVE)) { break; @@ -1814,6 +1851,7 @@ static int ehci_fill_queue(EHCIPacket *p) assert(p->packet.status == USB_RET_ASYNC); p->async = EHCI_ASYNC_INFLIGHT; } +leave: usb_device_flush_ep_queue(ep->dev, ep); return 1; } @@ -2098,8 +2136,9 @@ static void ehci_advance_periodic_state(EHCIState *ehci) } list |= ((ehci->frindex & 0x1ff8) >> 1); - dma_memory_read(ehci->dma, list, &entry, sizeof entry); - entry = le32_to_cpu(entry); + if (get_dwords(ehci, list, &entry, 1) < 0) { + break; + } DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n", ehci->frindex / 8, list, entry); @@ -2209,6 +2248,10 @@ static void ehci_frame_timer(void *opaque) ehci->async_stepdown = 0; } + if (ehci_enabled(ehci) && (ehci->usbintr & USBSTS_FLR)) { + need_timer++; + } + if (need_timer) { /* If we've raised int, we speed up the timer, so that we quickly * notice any new packets queued up in response */ diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index ca3e24a850..aa77b7704d 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -135,7 +135,7 @@ static int parse_filter(const char *spec, struct USBAutoFilter *f); static void usb_host_auto_check(void *unused); static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name); -static int usb_linux_update_endp_table(USBHostDevice *s); +static void usb_linux_update_endp_table(USBHostDevice *s); static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p) { @@ -366,8 +366,11 @@ static void async_complete(void *opaque) if (p) { switch (aurb->urb.status) { case 0: - p->actual_length = aurb->urb.actual_length; - p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ + p->actual_length += aurb->urb.actual_length; + if (!aurb->more) { + /* Clear previous ASYNC status */ + p->status = USB_RET_SUCCESS; + } break; case -EPIPE: @@ -385,10 +388,12 @@ static void async_complete(void *opaque) } if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status); + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, aurb->urb.actual_length); usb_generic_async_ctrl_complete(&s->dev, p); } else if (!aurb->more) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status); + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, aurb->urb.actual_length); usb_packet_complete(&s->dev, p); } } @@ -863,8 +868,9 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p) p->ep->nr, p->iov.size); if (!is_valid(s, p->pid, p->ep->nr)) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); p->status = USB_RET_NAK; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); return; } @@ -879,8 +885,9 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p) ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg); if (ret < 0) { perror("USBDEVFS_CLEAR_HALT"); - trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); p->status = USB_RET_NAK; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); return; } clear_halt(s, p->pid, p->ep->nr); @@ -936,15 +943,15 @@ static void usb_host_handle_data(USBDevice *dev, USBPacket *p) switch(errno) { case ETIMEDOUT: - trace_usb_host_req_complete(s->bus_num, s->addr, p, - USB_RET_NAK); p->status = USB_RET_NAK; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); break; case EPIPE: default: - trace_usb_host_req_complete(s->bus_num, s->addr, p, - USB_RET_STALL); p->status = USB_RET_STALL; + trace_usb_host_req_complete(s->bus_num, s->addr, p, + p->status, p->actual_length); } return; } @@ -1132,8 +1139,7 @@ static void usb_host_handle_control(USBDevice *dev, USBPacket *p, p->status = USB_RET_ASYNC; } -/* returns 1 on problem encountered or 0 for success */ -static int usb_linux_update_endp_table(USBHostDevice *s) +static void usb_linux_update_endp_table(USBHostDevice *s) { static const char *tname[] = { [USB_ENDPOINT_XFER_CONTROL] = "control", @@ -1159,23 +1165,23 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 2) { trace_usb_host_parse_error(s->bus_num, s->addr, "descriptor too short"); - goto error; + return; } if (i + d->bLength > s->descr_len) { trace_usb_host_parse_error(s->bus_num, s->addr, "descriptor too long"); - goto error; + return; } switch (d->bDescriptorType) { case 0: trace_usb_host_parse_error(s->bus_num, s->addr, "invalid descriptor type"); - goto error; + return; case USB_DT_DEVICE: if (d->bLength < 0x12) { trace_usb_host_parse_error(s->bus_num, s->addr, "device descriptor too short"); - goto error; + return; } v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo; p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo; @@ -1185,7 +1191,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x09) { trace_usb_host_parse_error(s->bus_num, s->addr, "config descriptor too short"); - goto error; + return; } configuration = d->u.config.bConfigurationValue; active = (configuration == s->dev.configuration); @@ -1196,7 +1202,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x09) { trace_usb_host_parse_error(s->bus_num, s->addr, "interface descriptor too short"); - goto error; + return; } interface = d->u.interface.bInterfaceNumber; altsetting = d->u.interface.bAlternateSetting; @@ -1209,7 +1215,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (d->bLength < 0x07) { trace_usb_host_parse_error(s->bus_num, s->addr, "endpoint descriptor too short"); - goto error; + return; } devep = d->u.endpoint.bEndpointAddress; pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; @@ -1217,7 +1223,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s) if (ep == 0) { trace_usb_host_parse_error(s->bus_num, s->addr, "invalid endpoint address"); - goto error; + return; } type = d->u.endpoint.bmAttributes & 0x3; @@ -1250,11 +1256,6 @@ static int usb_linux_update_endp_table(USBHostDevice *s) break; } } - return 0; - -error: - usb_ep_reset(&s->dev); - return 1; } /* @@ -1341,10 +1342,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num, } usb_ep_init(&dev->dev); - ret = usb_linux_update_endp_table(dev); - if (ret) { - goto fail; - } + usb_linux_update_endp_table(dev); if (speed == -1) { struct usbdevfs_connectinfo ci; @@ -1738,6 +1736,7 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) } static QEMUTimer *usb_auto_timer; +static VMChangeStateEntry *usb_vmstate; static int usb_host_auto_scan(void *opaque, int bus_num, int addr, const char *port, @@ -1792,6 +1791,13 @@ static int usb_host_auto_scan(void *opaque, int bus_num, return 0; } +static void usb_host_vm_state(void *unused, int running, RunState state) +{ + if (running) { + usb_host_auto_check(unused); + } +} + static void usb_host_auto_check(void *unused) { struct USBHostDevice *s; @@ -1820,6 +1826,9 @@ static void usb_host_auto_check(void *unused) } } + if (!usb_vmstate) { + usb_vmstate = qemu_add_vm_change_state_handler(usb_host_vm_state, NULL); + } if (!usb_auto_timer) { usb_auto_timer = qemu_new_timer_ms(rt_clock, usb_host_auto_check, NULL); if (!usb_auto_timer) { diff --git a/hw/usb/libhw.c b/hw/usb/libhw.c index 703e2d213b..24d3cad3a2 100644 --- a/hw/usb/libhw.c +++ b/hw/usb/libhw.c @@ -37,7 +37,7 @@ int usb_packet_map(USBPacket *p, QEMUSGList *sgl) while (len) { dma_addr_t xlen = len; - mem = dma_memory_map(sgl->dma, sgl->sg[i].base, &xlen, dir); + mem = dma_memory_map(sgl->dma, base, &xlen, dir); if (!mem) { goto err; } diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index be9a232059..0c95e6b05e 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -342,7 +342,9 @@ static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, if (p->combined && p != p->combined->first) { continue; } - packet_id_queue_add(&dev->already_in_flight, p->id); + if (p->state == USB_PACKET_ASYNC) { + packet_id_queue_add(&dev->already_in_flight, p->id); + } } } @@ -1960,7 +1962,7 @@ static const VMStateDescription usbredir_vmstate = { static Property usbredir_properties[] = { DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), - DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), + DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning), DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str), DEFINE_PROP_INT32("bootindex", USBRedirDevice, bootindex, -1), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/vga-pci.c b/hw/vga-pci.c index ec29cac7f4..947e35c76f 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -84,9 +84,10 @@ static void pci_vga_ioport_write(void *ptr, hwaddr addr, uint64_t val, unsigned size) { PCIVGAState *d = ptr; + switch (size) { case 1: - vga_ioport_write(&d->vga, addr, val); + vga_ioport_write(&d->vga, addr + 0x3c0, val); break; case 2: /* @@ -94,8 +95,8 @@ static void pci_vga_ioport_write(void *ptr, hwaddr addr, * indexed registers with a single word write because the * index byte is updated first. */ - vga_ioport_write(&d->vga, addr, val & 0xff); - vga_ioport_write(&d->vga, addr+1, (val >> 8) & 0xff); + vga_ioport_write(&d->vga, addr + 0x3c0, val & 0xff); + vga_ioport_write(&d->vga, addr + 0x3c1, (val >> 8) & 0xff); break; } } @@ -2321,9 +2321,8 @@ static const MemoryRegionPortio vbe_portio_list[] = { { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index }, # ifdef TARGET_I386 { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data }, -# else - { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data }, # endif + { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data }, PORTIO_END_OF_LIST(), }; diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 96031500ee..71f4fb5dc6 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -852,6 +852,41 @@ static void virtio_balloon_exit_pci(PCIDevice *pci_dev) virtio_exit_pci(pci_dev); } +static int virtio_rng_init_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + VirtIODevice *vdev; + + if (proxy->rng.rng == NULL) { + proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM)); + + object_property_add_child(OBJECT(pci_dev), + "default-backend", + OBJECT(proxy->rng.default_backend), + NULL); + + object_property_set_link(OBJECT(pci_dev), + OBJECT(proxy->rng.default_backend), + "rng", NULL); + } + + vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng); + if (!vdev) { + return -1; + } + virtio_init_pci(proxy, vdev); + return 0; +} + +static void virtio_rng_exit_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + + virtio_pci_stop_ioeventfd(proxy); + virtio_rng_exit(proxy->vdev); + virtio_exit_pci(pci_dev); +} + static Property virtio_blk_properties[] = { DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf), @@ -982,6 +1017,50 @@ static TypeInfo virtio_balloon_info = { .class_init = virtio_balloon_class_init, }; +static void virtio_rng_initfn(Object *obj) +{ + PCIDevice *pci_dev = PCI_DEVICE(obj); + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + + object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, + (Object **)&proxy->rng.rng, NULL); +} + +static Property virtio_rng_properties[] = { + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), + /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If + you have an entropy source capable of generating more entropy than this + and you can pass it through via virtio-rng, then hats off to you. Until + then, this is unlimited for all practical purposes. + */ + DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX), + DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_rng_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_rng_init_pci; + k->exit = virtio_rng_exit_pci; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_RNG; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_OTHERS; + dc->reset = virtio_pci_reset; + dc->props = virtio_rng_properties; +} + +static TypeInfo virtio_rng_info = { + .name = "virtio-rng-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .instance_init = virtio_rng_initfn, + .class_init = virtio_rng_class_init, +}; + static int virtio_scsi_init_pci(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); @@ -1046,6 +1125,7 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_serial_info); type_register_static(&virtio_balloon_info); type_register_static(&virtio_scsi_info); + type_register_static(&virtio_rng_info); } type_init(virtio_pci_register_types) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index ac9d522f37..b58d9a2d19 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -17,6 +17,7 @@ #include "virtio-blk.h" #include "virtio-net.h" +#include "virtio-rng.h" #include "virtio-serial.h" #include "virtio-scsi.h" @@ -46,6 +47,7 @@ typedef struct { virtio_serial_conf serial; virtio_net_conf net; VirtIOSCSIConf scsi; + VirtIORNGConf rng; bool ioeventfd_disabled; bool ioeventfd_started; VirtIOIRQFD *vector_irqfd; diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c new file mode 100644 index 0000000000..3ca96c855f --- /dev/null +++ b/hw/virtio-rng.c @@ -0,0 +1,258 @@ +/* + * A virtio device implementing a hardware random number generator. + * + * Copyright 2012 Red Hat, Inc. + * Copyright 2012 Amit Shah <amit.shah@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "iov.h" +#include "qdev.h" +#include "virtio.h" +#include "virtio-rng.h" +#include "qemu/rng.h" + +typedef struct VirtIORNG { + VirtIODevice vdev; + + DeviceState *qdev; + + /* Only one vq - guest puts buffer(s) on it when it needs entropy */ + VirtQueue *vq; + VirtQueueElement elem; + + /* Config data for the device -- currently only chardev */ + VirtIORNGConf *conf; + + /* Whether we've popped a vq element into 'elem' above */ + bool popped; + + RngBackend *rng; + + /* We purposefully don't migrate this state. The quota will reset on the + * destination as a result. Rate limiting is host state, not guest state. + */ + QEMUTimer *rate_limit_timer; + int64_t quota_remaining; +} VirtIORNG; + +static bool is_guest_ready(VirtIORNG *vrng) +{ + if (virtio_queue_ready(vrng->vq) + && (vrng->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { + return true; + } + return false; +} + +static size_t pop_an_elem(VirtIORNG *vrng) +{ + size_t size; + + if (!vrng->popped && !virtqueue_pop(vrng->vq, &vrng->elem)) { + return 0; + } + vrng->popped = true; + + size = iov_size(vrng->elem.in_sg, vrng->elem.in_num); + return size; +} + +static void virtio_rng_process(VirtIORNG *vrng); + +/* Send data from a char device over to the guest */ +static void chr_read(void *opaque, const void *buf, size_t size) +{ + VirtIORNG *vrng = opaque; + size_t len; + int offset; + + if (!is_guest_ready(vrng)) { + return; + } + + vrng->quota_remaining -= size; + + offset = 0; + while (offset < size) { + if (!pop_an_elem(vrng)) { + break; + } + len = iov_from_buf(vrng->elem.in_sg, vrng->elem.in_num, + 0, buf + offset, size - offset); + offset += len; + + virtqueue_push(vrng->vq, &vrng->elem, len); + vrng->popped = false; + } + virtio_notify(&vrng->vdev, vrng->vq); + + /* + * Lastly, if we had multiple elems queued by the guest, and we + * didn't have enough data to fill them all, indicate we want more + * data. + */ + virtio_rng_process(vrng); +} + +static void virtio_rng_process(VirtIORNG *vrng) +{ + ssize_t size; + + if (!is_guest_ready(vrng)) { + return; + } + + size = pop_an_elem(vrng); + size = MIN(vrng->quota_remaining, size); + + if (size > 0) { + rng_backend_request_entropy(vrng->rng, size, chr_read, vrng); + } +} + + +static void handle_input(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); + virtio_rng_process(vrng); +} + +static uint32_t get_features(VirtIODevice *vdev, uint32_t f) +{ + return f; +} + +static void virtio_rng_save(QEMUFile *f, void *opaque) +{ + VirtIORNG *vrng = opaque; + + virtio_save(&vrng->vdev, f); + + qemu_put_byte(f, vrng->popped); + if (vrng->popped) { + int i; + + qemu_put_be32(f, vrng->elem.index); + + qemu_put_be32(f, vrng->elem.in_num); + for (i = 0; i < vrng->elem.in_num; i++) { + qemu_put_be64(f, vrng->elem.in_addr[i]); + } + + qemu_put_be32(f, vrng->elem.out_num); + for (i = 0; i < vrng->elem.out_num; i++) { + qemu_put_be64(f, vrng->elem.out_addr[i]); + } + } +} + +static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) +{ + VirtIORNG *vrng = opaque; + + if (version_id != 1) { + return -EINVAL; + } + virtio_load(&vrng->vdev, f); + + vrng->popped = qemu_get_byte(f); + if (vrng->popped) { + int i; + + vrng->elem.index = qemu_get_be32(f); + + vrng->elem.in_num = qemu_get_be32(f); + g_assert(vrng->elem.in_num < VIRTQUEUE_MAX_SIZE); + for (i = 0; i < vrng->elem.in_num; i++) { + vrng->elem.in_addr[i] = qemu_get_be64(f); + } + + vrng->elem.out_num = qemu_get_be32(f); + g_assert(vrng->elem.out_num < VIRTQUEUE_MAX_SIZE); + for (i = 0; i < vrng->elem.out_num; i++) { + vrng->elem.out_addr[i] = qemu_get_be64(f); + } + + virtqueue_map_sg(vrng->elem.in_sg, vrng->elem.in_addr, + vrng->elem.in_num, 1); + virtqueue_map_sg(vrng->elem.out_sg, vrng->elem.out_addr, + vrng->elem.out_num, 0); + } + + /* We may have an element ready but couldn't process it due to a quota + limit. Make sure to try again after live migration when the quota may + have been reset. + */ + virtio_rng_process(vrng); + + return 0; +} + +static void check_rate_limit(void *opaque) +{ + VirtIORNG *s = opaque; + + s->quota_remaining = s->conf->max_bytes; + virtio_rng_process(s); + qemu_mod_timer(s->rate_limit_timer, + qemu_get_clock_ms(vm_clock) + s->conf->period_ms); +} + + +VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf) +{ + VirtIORNG *vrng; + VirtIODevice *vdev; + Error *local_err = NULL; + + vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0, + sizeof(VirtIORNG)); + + vrng = DO_UPCAST(VirtIORNG, vdev, vdev); + + vrng->rng = conf->rng; + if (vrng->rng == NULL) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object"); + return NULL; + } + + rng_backend_open(vrng->rng, &local_err); + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return NULL; + } + + vrng->vq = virtio_add_queue(vdev, 8, handle_input); + vrng->vdev.get_features = get_features; + + vrng->qdev = dev; + vrng->conf = conf; + vrng->popped = false; + vrng->quota_remaining = vrng->conf->max_bytes; + + g_assert_cmpint(vrng->conf->max_bytes, <=, INT64_MAX); + + vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock, + check_rate_limit, vrng); + + qemu_mod_timer(vrng->rate_limit_timer, + qemu_get_clock_ms(vm_clock) + vrng->conf->period_ms); + + register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save, + virtio_rng_load, vrng); + + return vdev; +} + +void virtio_rng_exit(VirtIODevice *vdev) +{ + VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); + + unregister_savevm(vrng->qdev, "virtio-rng", vrng); + virtio_cleanup(vdev); +} diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h new file mode 100644 index 0000000000..f42d748eba --- /dev/null +++ b/hw/virtio-rng.h @@ -0,0 +1,28 @@ +/* + * Virtio RNG Support + * + * Copyright Red Hat, Inc. 2012 + * Copyright Amit Shah <amit.shah@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef _QEMU_VIRTIO_RNG_H +#define _QEMU_VIRTIO_RNG_H + +#include "qemu/rng.h" +#include "qemu/rng-random.h" + +/* The Virtio ID for the virtio rng device */ +#define VIRTIO_ID_RNG 4 + +struct VirtIORNGConf { + RngBackend *rng; + uint64_t max_bytes; + uint32_t period_ms; + RndRandom *default_backend; +}; + +#endif diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index d20bd8bf75..efa8a81db6 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -53,6 +53,15 @@ struct VirtIOSerial { uint32_t *ports_map; struct virtio_console_config config; + + struct { + QEMUTimer *timer; + int nr_active_ports; + struct { + VirtIOSerialPort *port; + uint8_t host_connected; + } *connected; + } post_load; }; static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id) @@ -626,6 +635,29 @@ static void virtio_serial_save(QEMUFile *f, void *opaque) } } +static void virtio_serial_post_load_timer_cb(void *opaque) +{ + int i; + VirtIOSerial *s = opaque; + VirtIOSerialPort *port; + uint8_t host_connected; + + for (i = 0 ; i < s->post_load.nr_active_ports; ++i) { + port = s->post_load.connected[i].port; + host_connected = s->post_load.connected[i].host_connected; + if (host_connected != port->host_connected) { + /* + * We have to let the guest know of the host connection + * status change + */ + send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, + port->host_connected); + } + } + g_free(s->post_load.connected); + s->post_load.connected = NULL; +} + static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) { VirtIOSerial *s = opaque; @@ -673,10 +705,13 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &nr_active_ports); + s->post_load.nr_active_ports = nr_active_ports; + s->post_load.connected = + g_malloc0(sizeof(*s->post_load.connected) * nr_active_ports); + /* Items in struct VirtIOSerialPort */ for (i = 0; i < nr_active_ports; i++) { uint32_t id; - bool host_connected; id = qemu_get_be32(f); port = find_port_by_id(s, id); @@ -685,15 +720,8 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) } port->guest_connected = qemu_get_byte(f); - host_connected = qemu_get_byte(f); - if (host_connected != port->host_connected) { - /* - * We have to let the guest know of the host connection - * status change - */ - send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, - port->host_connected); - } + s->post_load.connected[i].port = port; + s->post_load.connected[i].host_connected = qemu_get_byte(f); if (version_id > 2) { uint32_t elem_popped; @@ -718,6 +746,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) } } } + qemu_mod_timer(s->post_load.timer, 1); return 0; } @@ -967,6 +996,9 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf) register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save, virtio_serial_load, vser); + vser->post_load.timer = qemu_new_timer_ns(vm_clock, + virtio_serial_post_load_timer_cb, vser); + return vdev; } @@ -979,6 +1011,8 @@ void virtio_serial_exit(VirtIODevice *vdev) g_free(vser->ivqs); g_free(vser->ovqs); g_free(vser->ports_map); + g_free(vser->post_load.connected); + qemu_free_timer(vser->post_load.timer); virtio_cleanup(vdev); } diff --git a/hw/virtio.h b/hw/virtio.h index ac482be24c..df8d0f7b69 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -203,6 +203,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial); VirtIODevice *virtio_balloon_init(DeviceState *dev); typedef struct VirtIOSCSIConf VirtIOSCSIConf; VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf); +typedef struct VirtIORNGConf VirtIORNGConf; +VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf); #ifdef CONFIG_LINUX VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); #endif @@ -213,6 +215,7 @@ void virtio_blk_exit(VirtIODevice *vdev); void virtio_serial_exit(VirtIODevice *vdev); void virtio_balloon_exit(VirtIODevice *vdev); void virtio_scsi_exit(VirtIODevice *vdev); +void virtio_rng_exit(VirtIODevice *vdev); #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ DEFINE_PROP_BIT("indirect_desc", _state, _field, \ @@ -8,6 +8,7 @@ */ #include <inttypes.h> +#include "hw/irq.h" #include "qemu-common.h" /* xen-machine.c */ diff --git a/include/qemu/object.h b/include/qemu/object.h index cc75feed66..be707f1a36 100644 --- a/include/qemu/object.h +++ b/include/qemu/object.h @@ -947,6 +947,22 @@ void object_property_add_str(Object *obj, const char *name, struct Error **errp); /** + * object_property_add_bool: + * @obj: the object to add a property to + * @name: the name of the property + * @get: the getter or NULL if the property is write-only. + * @set: the setter or NULL if the property is read-only + * @errp: if an error occurs, a pointer to an area to store the error + * + * Add a bool property using getters/setters. This function will add a + * property of type 'bool'. + */ +void object_property_add_bool(Object *obj, const char *name, + bool (*get)(Object *, struct Error **), + void (*set)(Object *, bool, struct Error **), + struct Error **errp); + +/** * object_child_foreach: * @obj: the object whose children will be navigated * @fn: the iterator function to be called diff --git a/include/qemu/rng-random.h b/include/qemu/rng-random.h new file mode 100644 index 0000000000..6249290cc4 --- /dev/null +++ b/include/qemu/rng-random.h @@ -0,0 +1,22 @@ +/* + * QEMU Random Number Generator Backend + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_RNG_RANDOM_H +#define QEMU_RNG_RANDOM_H + +#include "qemu/object.h" + +#define TYPE_RNG_RANDOM "rng-random" +#define RNG_RANDOM(obj) OBJECT_CHECK(RndRandom, (obj), TYPE_RNG_RANDOM) + +typedef struct RndRandom RndRandom; + +#endif diff --git a/include/qemu/rng.h b/include/qemu/rng.h new file mode 100644 index 0000000000..7e9d6723ff --- /dev/null +++ b/include/qemu/rng.h @@ -0,0 +1,93 @@ +/* + * QEMU Random Number Generator Backend + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori <aliguori@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_RNG_H +#define QEMU_RNG_H + +#include "qemu/object.h" +#include "qemu-common.h" +#include "error.h" + +#define TYPE_RNG_BACKEND "rng-backend" +#define RNG_BACKEND(obj) \ + OBJECT_CHECK(RngBackend, (obj), TYPE_RNG_BACKEND) +#define RNG_BACKEND_GET_CLASS(obj) \ + OBJECT_GET_CLASS(RngBackendClass, (obj), TYPE_RNG_BACKEND) +#define RNG_BACKEND_CLASS(klass) \ + OBJECT_CLASS_CHECK(RngBackendClass, (klass), TYPE_RNG_BACKEND) + +typedef struct RngBackendClass RngBackendClass; +typedef struct RngBackend RngBackend; + +typedef void (EntropyReceiveFunc)(void *opaque, + const void *data, + size_t size); + +struct RngBackendClass +{ + ObjectClass parent_class; + + void (*request_entropy)(RngBackend *s, size_t size, + EntropyReceiveFunc *recieve_entropy, void *opaque); + void (*cancel_requests)(RngBackend *s); + + void (*opened)(RngBackend *s, Error **errp); +}; + +struct RngBackend +{ + Object parent; + + /*< protected >*/ + bool opened; +}; + +/** + * rng_backend_request_entropy: + * @s: the backend to request entropy from + * @size: the number of bytes of data to request + * @receive_entropy: a function to be invoked when entropy is available + * @opaque: data that should be passed to @receive_entropy + * + * This function is used by the front-end to request entropy from an entropy + * source. This function can be called multiple times before @receive_entropy + * is invoked with different values of @receive_entropy and @opaque. The + * backend will queue each request and handle appropriate. + * + * The backend does not need to pass the full amount of data to @receive_entropy + * but will pass at a value greater than 0. + */ +void rng_backend_request_entropy(RngBackend *s, size_t size, + EntropyReceiveFunc *receive_entropy, + void *opaque); + +/** + * rng_backend_cancel_requests: + * @s: the backend to cancel all pending requests in + * + * Cancels all pending requests submitted by @rng_backend_request_entropy. This + * should be used by a device during reset or in preparation for live migration + * to stop tracking any request. + */ +void rng_backend_cancel_requests(RngBackend *s); + +/** + * rng_backend_open: + * @s: the backend to open + * @errp: a pointer to return the #Error object if an error occurs. + * + * This function will open the backend if it is not already open. Calling this + * function on an already opened backend will not result in an error. + */ +void rng_backend_open(RngBackend *s, Error **errp); + +#endif @@ -1905,6 +1905,8 @@ void kvm_remove_all_breakpoints(CPUArchState *current_env) } } } + QTAILQ_REMOVE(&s->kvm_sw_breakpoints, bp, entry); + g_free(bp); } kvm_arch_remove_all_hw_breakpoints(); diff --git a/libcacard/Makefile b/libcacard/Makefile index 487f434894..c26aac65c3 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -1,13 +1,13 @@ -include ../config-host.mak --include $(SRC_PATH)/Makefile.objs -include $(SRC_PATH)/rules.mak +-include $(SRC_PATH)/Makefile.objs libcacard_includedir=$(includedir)/cacard $(call set-vpath, $(SRC_PATH)) # objects linked into a shared library, built with libtool with -fPIC if required -QEMU_OBJS=$(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) +QEMU_OBJS=$(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) $(stub-obj-y) QEMU_OBJS_LIB=$(patsubst %.o,%.lo,$(QEMU_OBJS)) QEMU_CFLAGS+=-I../ @@ -54,38 +54,6 @@ static bool fips_enabled = false; static const char *qemu_version = QEMU_VERSION; -static int default_fdset_get_fd(int64_t fdset_id, int flags) -{ - return -1; -} -QEMU_WEAK_ALIAS(monitor_fdset_get_fd, default_fdset_get_fd); -#define monitor_fdset_get_fd \ - QEMU_WEAK_REF(monitor_fdset_get_fd, default_fdset_get_fd) - -static int default_fdset_dup_fd_add(int64_t fdset_id, int dup_fd) -{ - return -1; -} -QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add); -#define monitor_fdset_dup_fd_add \ - QEMU_WEAK_REF(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add) - -static int default_fdset_dup_fd_remove(int dup_fd) -{ - return -1; -} -QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove); -#define monitor_fdset_dup_fd_remove \ - QEMU_WEAK_REF(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove) - -static int default_fdset_dup_fd_find(int dup_fd) -{ - return -1; -} -QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_find, default_fdset_dup_fd_find); -#define monitor_fdset_dup_fd_find \ - QEMU_WEAK_REF(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_find) - int socket_set_cork(int fd, int v) { #if defined(SOL_TCP) && defined(TCP_CORK) @@ -136,6 +136,9 @@ void qemu_vfree(void *ptr); int qemu_madvise(void *addr, size_t len, int advice); +int qemu_open(const char *name, int flags, ...); +int qemu_close(int fd); + #if defined(__HAIKU__) && defined(__i386__) #define FMT_pid "%ld" #elif defined(WIN64) diff --git a/oslib-win32.c b/oslib-win32.c index 326a2bddb3..51b33e8b20 100644 --- a/oslib-win32.c +++ b/oslib-win32.c @@ -32,13 +32,6 @@ #include "trace.h" #include "qemu_socket.h" -static void default_qemu_fd_register(int fd) -{ -} -QEMU_WEAK_ALIAS(qemu_fd_register, default_qemu_fd_register); -#define qemu_fd_register \ - QEMU_WEAK_REF(qemu_fd_register, default_qemu_fd_register) - void *qemu_oom_check(void *ptr) { if (ptr == NULL) { diff --git a/qemu-aio.h b/qemu-aio.h index 1b7eb6ef5b..3889fe97a4 100644 --- a/qemu-aio.h +++ b/qemu-aio.h @@ -21,21 +21,19 @@ typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); -typedef struct AIOPool { +typedef struct AIOCBInfo { void (*cancel)(BlockDriverAIOCB *acb); - int aiocb_size; - BlockDriverAIOCB *free_aiocb; -} AIOPool; + size_t aiocb_size; +} AIOCBInfo; struct BlockDriverAIOCB { - AIOPool *pool; + const AIOCBInfo *aiocb_info; BlockDriverState *bs; BlockDriverCompletionFunc *cb; void *opaque; - BlockDriverAIOCB *next; }; -void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs, +void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque); void qemu_aio_release(void *p); diff --git a/qemu-common.h b/qemu-common.h index ac9985cc6d..cef264cc85 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -1,5 +1,14 @@ -/* Common header file that is included by all of qemu. */ +/* Common header file that is included by all of QEMU. + * + * This file is supposed to be included only by .c files. No header file should + * depend on qemu-common.h, as this would easily lead to circular header + * dependencies. + * + * If a header file uses a definition from qemu-common.h, that definition + * must be moved to a separate header file, and the header that uses it + * must include that header. + */ #ifndef QEMU_COMMON_H #define QEMU_COMMON_H @@ -208,8 +217,6 @@ const char *path(const char *pathname); void *qemu_oom_check(void *ptr); -int qemu_open(const char *name, int flags, ...); -int qemu_close(int fd); ssize_t qemu_write_full(int fd, const void *buf, size_t count) QEMU_WARN_UNUSED_RESULT; ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags) @@ -283,7 +290,6 @@ typedef struct PCIEPort PCIEPort; typedef struct PCIESlot PCIESlot; typedef struct MSIMessage MSIMessage; typedef struct SerialState SerialState; -typedef struct IRQState *qemu_irq; typedef struct PCMCIACardState PCMCIACardState; typedef struct MouseTransformInfo MouseTransformInfo; typedef struct uWireSlave uWireSlave; diff --git a/qemu-config.c b/qemu-config.c index 3154cac10f..10d1ba4176 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -682,6 +682,15 @@ static QemuOptsList qemu_add_fd_opts = { }, }; +static QemuOptsList qemu_object_opts = { + .name = "object", + .implied_opt_name = "qom-type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head), + .desc = { + { } + }, +}; + static QemuOptsList *vm_config_groups[32] = { &qemu_drive_opts, &qemu_chardev_opts, @@ -699,6 +708,7 @@ static QemuOptsList *vm_config_groups[32] = { &qemu_iscsi_opts, &qemu_sandbox_opts, &qemu_add_fd_opts, + &qemu_object_opts, NULL, }; diff --git a/qemu-config.h b/qemu-config.h index 5557562c33..812c4c5b10 100644 --- a/qemu-config.h +++ b/qemu-config.h @@ -1,6 +1,8 @@ #ifndef QEMU_CONFIG_H #define QEMU_CONFIG_H +#include <stdio.h> +#include "qemu-option.h" #include "error.h" extern QemuOptsList qemu_fsdev_opts; diff --git a/qemu-doc.texi b/qemu-doc.texi index d8fb2de10e..6ff309ddf4 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -421,6 +421,7 @@ snapshots. * disk_images_nbd:: NBD access * disk_images_sheepdog:: Sheepdog disk images * disk_images_iscsi:: iSCSI LUNs +* disk_images_gluster:: GlusterFS disk images @end menu @node disk_images_quickstart @@ -814,7 +815,55 @@ qemu-system-i386 -iscsi initiator-name=iqn.qemu.test:my-initiator \ -cdrom iscsi://127.0.0.1/iqn.qemu.test/2 @end example +@node disk_images_gluster +@subsection GlusterFS disk images +GlusterFS is an user space distributed file system. + +You can boot from the GlusterFS disk image with the command: +@example +qemu-system-x86_64 -drive file=gluster[+@var{transport}]://[@var{server}[:@var{port}]]/@var{volname}/@var{image}[?socket=...] +@end example + +@var{gluster} is the protocol. + +@var{transport} specifies the transport type used to connect to gluster +management daemon (glusterd). Valid transport types are +tcp, unix and rdma. If a transport type isn't specified, then tcp +type is assumed. + +@var{server} specifies the server where the volume file specification for +the given volume resides. This can be either hostname, ipv4 address +or ipv6 address. ipv6 address needs to be within square brackets [ ]. +If transport type is unix, then @var{server} field should not be specifed. +Instead @var{socket} field needs to be populated with the path to unix domain +socket. + +@var{port} is the port number on which glusterd is listening. This is optional +and if not specified, QEMU will send 0 which will make gluster to use the +default port. If the transport type is unix, then @var{port} should not be +specified. + +@var{volname} is the name of the gluster volume which contains the disk image. + +@var{image} is the path to the actual disk image that resides on gluster volume. + +You can create a GlusterFS disk image with the command: +@example +qemu-img create gluster://@var{server}/@var{volname}/@var{image} @var{size} +@end example + +Examples +@example +qemu-system-x86_64 -drive file=gluster://1.2.3.4/testvol/a.img +qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4/testvol/a.img +qemu-system-x86_64 -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img +qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img +qemu-system-x86_64 -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img +qemu-system-x86_64 -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img +qemu-system-x86_64 -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket +qemu-system-x86_64 -drive file=gluster+rdma://1.2.3.4:24007/testvol/a.img +@end example @node pcsys_network @section Network emulation @@ -1362,7 +1362,7 @@ static int aio_write_f(int argc, char **argv) static int aio_flush_f(int argc, char **argv) { - qemu_aio_flush(); + bdrv_drain_all(); return 0; } diff --git a/qemu-options.hx b/qemu-options.hx index a165cff071..9bb29d3907 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2066,6 +2066,23 @@ qemu-system-i386 --drive file=sheepdog:192.0.2.1:30000:MyVirtualMachine See also @url{http://http://www.osrg.net/sheepdog/}. +@item GlusterFS +GlusterFS is an user space distributed file system. +QEMU supports the use of GlusterFS volumes for hosting VM disk images using +TCP, Unix Domain Sockets and RDMA transport protocols. + +Syntax for specifying a VM disk image on GlusterFS volume is +@example +gluster[+transport]://[server[:port]]/volname/image[?socket=...] +@end example + + +Example +@example +qemu-system-x86_84 --drive file=gluster://192.0.2.1/testvol/a.img +@end example + +See also @url{http://www.gluster.org}. @end table ETEXI @@ -2916,6 +2933,14 @@ DEF("no-kvm-irqchip", HAS_ARG, QEMU_OPTION_no_kvm_irqchip, "", QEMU_ARCH_I386) HXCOMM Deprecated (ignored) DEF("tdf", 0, QEMU_OPTION_tdf,"", QEMU_ARCH_ALL) +DEF("object", HAS_ARG, QEMU_OPTION_object, + "-object TYPENAME[,PROP1=VALUE1,...]\n" + " create an new object of type TYPENAME setting properties\n" + " in the order they are specified. Note that the 'id'\n" + " property must be set. These objects are placed in the\n" + " '/objects' path.\n", + QEMU_ARCH_ALL) + HXCOMM This is the last statement. Insert new options before this line! STEXI @end table diff --git a/qemu-sockets.c b/qemu-sockets.c index abcd791cb6..cfed9c5a5b 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -61,28 +61,6 @@ static QemuOptsList dummy_opts = { }, }; -static int default_monitor_get_fd(Monitor *mon, const char *name, Error **errp) -{ - error_setg(errp, "only QEMU supports file descriptor passing"); - return -1; -} -QEMU_WEAK_ALIAS(monitor_get_fd, default_monitor_get_fd); -#define monitor_get_fd \ - QEMU_WEAK_REF(monitor_get_fd, default_monitor_get_fd) - -static int default_qemu_set_fd_handler2(int fd, - IOCanReadHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) - -{ - abort(); -} -QEMU_WEAK_ALIAS(qemu_set_fd_handler2, default_qemu_set_fd_handler2); -#define qemu_set_fd_handler2 \ - QEMU_WEAK_REF(qemu_set_fd_handler2, default_qemu_set_fd_handler2) - static int inet_getport(struct addrinfo *e) { struct sockaddr_in *i4; @@ -471,15 +471,6 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, return prop_list; } -static CpuDefinitionInfoList *default_arch_query_cpu_definitions(Error **errp) -{ - error_set(errp, QERR_NOT_SUPPORTED); - return NULL; -} -QEMU_WEAK_ALIAS(arch_query_cpu_definitions, default_arch_query_cpu_definitions); -#define arch_query_cpu_definitions \ - QEMU_WEAK_REF(arch_query_cpu_definitions, default_arch_query_cpu_definitions) - CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) { return arch_query_cpu_definitions(errp); diff --git a/qom/object.c b/qom/object.c index e3e9242638..d7092b09d8 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1183,6 +1183,62 @@ void object_property_add_str(Object *obj, const char *name, prop, errp); } +typedef struct BoolProperty +{ + bool (*get)(Object *, Error **); + void (*set)(Object *, bool, Error **); +} BoolProperty; + +static void property_get_bool(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + BoolProperty *prop = opaque; + bool value; + + value = prop->get(obj, errp); + visit_type_bool(v, &value, name, errp); +} + +static void property_set_bool(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + BoolProperty *prop = opaque; + bool value; + Error *local_err = NULL; + + visit_type_bool(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + prop->set(obj, value, errp); +} + +static void property_release_bool(Object *obj, const char *name, + void *opaque) +{ + BoolProperty *prop = opaque; + g_free(prop); +} + +void object_property_add_bool(Object *obj, const char *name, + bool (*get)(Object *, Error **), + void (*set)(Object *, bool, Error **), + Error **errp) +{ + BoolProperty *prop = g_malloc0(sizeof(*prop)); + + prop->get = get; + prop->set = set; + + object_property_add(obj, name, "bool", + get ? property_get_bool : NULL, + set ? property_set_bool : NULL, + property_release_bool, + prop, errp); +} + static char *qdev_get_type(Object *obj, Error **errp) { return g_strdup(object_get_typename(obj)); @@ -31,7 +31,7 @@ endif %.o: %.m $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@") -LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(sort $(1)) $(LIBS)," LINK $(TARGET_DIR)$@") +LINK = $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(LIBS)," LINK $(TARGET_DIR)$@") %$(EXESUF): %.o $(call LINK,$^) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 1b84834959..6bc2391874 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -273,7 +273,8 @@ fdecl.write(mcgen(''' #ifndef %(guard)s #define %(guard)s -#include "qemu-common.h" +#include <stdbool.h> +#include <stdint.h> ''', guard=guardname(h_file))) diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index 6be7047018..23c43e2772 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -73,6 +73,15 @@ def d(events): '};') +# Technically 'self' is not used by systemtap yet, but +# they recommended we keep it in the reserved list anyway +RESERVED_WORDS = ( + 'break', 'catch', 'continue', 'delete', 'else', 'for', + 'foreach', 'function', 'global', 'if', 'in', 'limit', + 'long', 'next', 'probe', 'return', 'self', 'string', + 'try', 'while' + ) + def stap(events): for e in events: # Define prototype for probe arguments @@ -87,7 +96,7 @@ def stap(events): if len(e.args) > 0: for name in e.args.names(): # Append underscore to reserved keywords - if name in ('limit', 'in', 'next', 'self', 'function'): + if name in RESERVED_WORDS: name += '_' out(' %s = $arg%d;' % (name, i)) i += 1 diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs new file mode 100644 index 0000000000..035b29a1f3 --- /dev/null +++ b/stubs/Makefile.objs @@ -0,0 +1,8 @@ +stub-obj-y += arch-query-cpu-def.o +stub-obj-y += fdset-add-fd.o +stub-obj-y += fdset-find-fd.o +stub-obj-y += fdset-get-fd.o +stub-obj-y += fdset-remove-fd.o +stub-obj-y += get-fd.o +stub-obj-y += set-fd-handler.o +stub-obj-$(CONFIG_WIN32) += fd-register.o diff --git a/stubs/arch-query-cpu-def.c b/stubs/arch-query-cpu-def.c new file mode 100644 index 0000000000..47b524628d --- /dev/null +++ b/stubs/arch-query-cpu-def.c @@ -0,0 +1,9 @@ +#include "qemu-common.h" +#include "arch_init.h" +#include "qerror.h" + +CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) +{ + error_set(errp, QERR_NOT_SUPPORTED); + return NULL; +} diff --git a/stubs/fd-register.c b/stubs/fd-register.c new file mode 100644 index 0000000000..813b6dd7c0 --- /dev/null +++ b/stubs/fd-register.c @@ -0,0 +1,6 @@ +#include "qemu-common.h" +#include "main-loop.h" + +void qemu_fd_register(int fd) +{ +} diff --git a/stubs/fdset-add-fd.c b/stubs/fdset-add-fd.c new file mode 100644 index 0000000000..09fe2a839a --- /dev/null +++ b/stubs/fdset-add-fd.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "monitor.h" + +int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd) +{ + return -1; +} diff --git a/stubs/fdset-find-fd.c b/stubs/fdset-find-fd.c new file mode 100644 index 0000000000..f82baa066c --- /dev/null +++ b/stubs/fdset-find-fd.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "monitor.h" + +int monitor_fdset_dup_fd_find(int dup_fd) +{ + return -1; +} diff --git a/stubs/fdset-get-fd.c b/stubs/fdset-get-fd.c new file mode 100644 index 0000000000..4106cf90f0 --- /dev/null +++ b/stubs/fdset-get-fd.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "monitor.h" + +int monitor_fdset_get_fd(int64_t fdset_id, int flags) +{ + return -1; +} diff --git a/stubs/fdset-remove-fd.c b/stubs/fdset-remove-fd.c new file mode 100644 index 0000000000..861b31247e --- /dev/null +++ b/stubs/fdset-remove-fd.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "monitor.h" + +int monitor_fdset_dup_fd_remove(int dupfd) +{ + return -1; +} diff --git a/stubs/get-fd.c b/stubs/get-fd.c new file mode 100644 index 0000000000..3561ab60e2 --- /dev/null +++ b/stubs/get-fd.c @@ -0,0 +1,8 @@ +#include "qemu-common.h" +#include "monitor.h" + +int monitor_get_fd(Monitor *mon, const char *name, Error **errp) +{ + error_setg(errp, "only QEMU supports file descriptor passing"); + return -1; +} diff --git a/stubs/set-fd-handler.c b/stubs/set-fd-handler.c new file mode 100644 index 0000000000..4807b5dc22 --- /dev/null +++ b/stubs/set-fd-handler.c @@ -0,0 +1,11 @@ +#include "qemu-common.h" +#include "main-loop.h" + +int qemu_set_fd_handler2(int fd, + IOCanReadHandler *fd_read_poll, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) +{ + abort(); +} diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 8c4dd021f3..4045f788ea 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -3373,7 +3373,7 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, int max_insns; pc_start = tb->pc; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; ctx.tb = tb; ctx.env = env; @@ -3406,7 +3406,7 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, } } if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -3432,7 +3432,7 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, or exhaust instruction count, stop generation. */ if (ret == NO_EXIT && ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0 - || gen_opc_ptr >= gen_opc_end + || tcg_ctx.gen_opc_ptr >= gen_opc_end || num_insns >= max_insns || singlestep || env->singlestep_enabled)) { @@ -3463,9 +3463,9 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; diff --git a/target-arm/translate.c b/target-arm/translate.c index 7d8f8e5edc..c42110ab0d 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9727,7 +9727,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, dc->tb = tb; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; @@ -9834,7 +9834,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, } } if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -9881,7 +9881,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, * Also stop translation when a page boundary is reached. This * ensures prefetch aborts occur at the right place. */ num_insns ++; - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && !singlestep && dc->pc < next_page_start && @@ -9962,7 +9962,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, done_generating: gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { @@ -9974,7 +9974,7 @@ done_generating: } #endif if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; diff --git a/target-cris/translate.c b/target-cris/translate.c index f8ebc43a86..0b0e86dbd1 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -74,89 +74,89 @@ static TCGv env_pc; /* This is the state at translation time. */ typedef struct DisasContext { - CPUCRISState *env; - target_ulong pc, ppc; + CPUCRISState *env; + target_ulong pc, ppc; - /* Decoder. */ + /* Decoder. */ unsigned int (*decoder)(CPUCRISState *env, struct DisasContext *dc); - uint32_t ir; - uint32_t opcode; - unsigned int op1; - unsigned int op2; - unsigned int zsize, zzsize; - unsigned int mode; - unsigned int postinc; - - unsigned int size; - unsigned int src; - unsigned int dst; - unsigned int cond; - - int update_cc; - int cc_op; - int cc_size; - uint32_t cc_mask; - - int cc_size_uptodate; /* -1 invalid or last written value. */ - - int cc_x_uptodate; /* 1 - ccs, 2 - known | X_FLAG. 0 not uptodate. */ - int flags_uptodate; /* Wether or not $ccs is uptodate. */ - int flagx_known; /* Wether or not flags_x has the x flag known at - translation time. */ - int flags_x; - - int clear_x; /* Clear x after this insn? */ - int clear_prefix; /* Clear prefix after this insn? */ - int clear_locked_irq; /* Clear the irq lockout. */ - int cpustate_changed; - unsigned int tb_flags; /* tb dependent flags. */ - int is_jmp; + uint32_t ir; + uint32_t opcode; + unsigned int op1; + unsigned int op2; + unsigned int zsize, zzsize; + unsigned int mode; + unsigned int postinc; + + unsigned int size; + unsigned int src; + unsigned int dst; + unsigned int cond; + + int update_cc; + int cc_op; + int cc_size; + uint32_t cc_mask; + + int cc_size_uptodate; /* -1 invalid or last written value. */ + + int cc_x_uptodate; /* 1 - ccs, 2 - known | X_FLAG. 0 not uptodate. */ + int flags_uptodate; /* Wether or not $ccs is uptodate. */ + int flagx_known; /* Wether or not flags_x has the x flag known at + translation time. */ + int flags_x; + + int clear_x; /* Clear x after this insn? */ + int clear_prefix; /* Clear prefix after this insn? */ + int clear_locked_irq; /* Clear the irq lockout. */ + int cpustate_changed; + unsigned int tb_flags; /* tb dependent flags. */ + int is_jmp; #define JMP_NOJMP 0 #define JMP_DIRECT 1 #define JMP_DIRECT_CC 2 #define JMP_INDIRECT 3 - int jmp; /* 0=nojmp, 1=direct, 2=indirect. */ - uint32_t jmp_pc; + int jmp; /* 0=nojmp, 1=direct, 2=indirect. */ + uint32_t jmp_pc; - int delayed_branch; + int delayed_branch; - struct TranslationBlock *tb; - int singlestep_enabled; + struct TranslationBlock *tb; + int singlestep_enabled; } DisasContext; static void gen_BUG(DisasContext *dc, const char *file, int line) { - printf ("BUG: pc=%x %s %d\n", dc->pc, file, line); - qemu_log("BUG: pc=%x %s %d\n", dc->pc, file, line); - cpu_abort(dc->env, "%s:%d\n", file, line); + printf("BUG: pc=%x %s %d\n", dc->pc, file, line); + qemu_log("BUG: pc=%x %s %d\n", dc->pc, file, line); + cpu_abort(dc->env, "%s:%d\n", file, line); } static const char *regnames[] = { - "$r0", "$r1", "$r2", "$r3", - "$r4", "$r5", "$r6", "$r7", - "$r8", "$r9", "$r10", "$r11", - "$r12", "$r13", "$sp", "$acr", + "$r0", "$r1", "$r2", "$r3", + "$r4", "$r5", "$r6", "$r7", + "$r8", "$r9", "$r10", "$r11", + "$r12", "$r13", "$sp", "$acr", }; static const char *pregnames[] = { - "$bz", "$vr", "$pid", "$srs", - "$wz", "$exs", "$eda", "$mof", - "$dz", "$ebp", "$erp", "$srp", - "$nrp", "$ccs", "$usp", "$spc", + "$bz", "$vr", "$pid", "$srs", + "$wz", "$exs", "$eda", "$mof", + "$dz", "$ebp", "$erp", "$srp", + "$nrp", "$ccs", "$usp", "$spc", }; /* We need this table to handle preg-moves with implicit width. */ static int preg_sizes[] = { - 1, /* bz. */ - 1, /* vr. */ - 4, /* pid. */ - 1, /* srs. */ - 2, /* wz. */ - 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, + 1, /* bz. */ + 1, /* vr. */ + 4, /* pid. */ + 1, /* srs. */ + 2, /* wz. */ + 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, }; #define t_gen_mov_TN_env(tn, member) \ @@ -166,113 +166,122 @@ static int preg_sizes[] = { static inline void t_gen_mov_TN_reg(TCGv tn, int r) { - if (r < 0 || r > 15) - fprintf(stderr, "wrong register read $r%d\n", r); - tcg_gen_mov_tl(tn, cpu_R[r]); + if (r < 0 || r > 15) { + fprintf(stderr, "wrong register read $r%d\n", r); + } + tcg_gen_mov_tl(tn, cpu_R[r]); } static inline void t_gen_mov_reg_TN(int r, TCGv tn) { - if (r < 0 || r > 15) - fprintf(stderr, "wrong register write $r%d\n", r); - tcg_gen_mov_tl(cpu_R[r], tn); + if (r < 0 || r > 15) { + fprintf(stderr, "wrong register write $r%d\n", r); + } + tcg_gen_mov_tl(cpu_R[r], tn); } static inline void _t_gen_mov_TN_env(TCGv tn, int offset) { - if (offset > sizeof (CPUCRISState)) - fprintf(stderr, "wrong load from env from off=%d\n", offset); - tcg_gen_ld_tl(tn, cpu_env, offset); + if (offset > sizeof(CPUCRISState)) { + fprintf(stderr, "wrong load from env from off=%d\n", offset); + } + tcg_gen_ld_tl(tn, cpu_env, offset); } static inline void _t_gen_mov_env_TN(int offset, TCGv tn) { - if (offset > sizeof (CPUCRISState)) - fprintf(stderr, "wrong store to env at off=%d\n", offset); - tcg_gen_st_tl(tn, cpu_env, offset); + if (offset > sizeof(CPUCRISState)) { + fprintf(stderr, "wrong store to env at off=%d\n", offset); + } + tcg_gen_st_tl(tn, cpu_env, offset); } static inline void t_gen_mov_TN_preg(TCGv tn, int r) { - if (r < 0 || r > 15) - fprintf(stderr, "wrong register read $p%d\n", r); - if (r == PR_BZ || r == PR_WZ || r == PR_DZ) - tcg_gen_mov_tl(tn, tcg_const_tl(0)); - else if (r == PR_VR) - tcg_gen_mov_tl(tn, tcg_const_tl(32)); - else - tcg_gen_mov_tl(tn, cpu_PR[r]); + if (r < 0 || r > 15) { + fprintf(stderr, "wrong register read $p%d\n", r); + } + if (r == PR_BZ || r == PR_WZ || r == PR_DZ) { + tcg_gen_mov_tl(tn, tcg_const_tl(0)); + } else if (r == PR_VR) { + tcg_gen_mov_tl(tn, tcg_const_tl(32)); + } else { + tcg_gen_mov_tl(tn, cpu_PR[r]); + } } static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn) { - if (r < 0 || r > 15) - fprintf(stderr, "wrong register write $p%d\n", r); - if (r == PR_BZ || r == PR_WZ || r == PR_DZ) - return; - else if (r == PR_SRS) - tcg_gen_andi_tl(cpu_PR[r], tn, 3); - else { - if (r == PR_PID) - gen_helper_tlb_flush_pid(cpu_env, tn); - if (dc->tb_flags & S_FLAG && r == PR_SPC) - gen_helper_spc_write(cpu_env, tn); - else if (r == PR_CCS) - dc->cpustate_changed = 1; - tcg_gen_mov_tl(cpu_PR[r], tn); - } + if (r < 0 || r > 15) { + fprintf(stderr, "wrong register write $p%d\n", r); + } + if (r == PR_BZ || r == PR_WZ || r == PR_DZ) { + return; + } else if (r == PR_SRS) { + tcg_gen_andi_tl(cpu_PR[r], tn, 3); + } else { + if (r == PR_PID) { + gen_helper_tlb_flush_pid(cpu_env, tn); + } + if (dc->tb_flags & S_FLAG && r == PR_SPC) { + gen_helper_spc_write(cpu_env, tn); + } else if (r == PR_CCS) { + dc->cpustate_changed = 1; + } + tcg_gen_mov_tl(cpu_PR[r], tn); + } } /* Sign extend at translation time. */ static int sign_extend(unsigned int val, unsigned int width) { - int sval; + int sval; - /* LSL. */ - val <<= 31 - width; - sval = val; - /* ASR. */ - sval >>= 31 - width; - return sval; + /* LSL. */ + val <<= 31 - width; + sval = val; + /* ASR. */ + sval >>= 31 - width; + return sval; } static int cris_fetch(CPUCRISState *env, DisasContext *dc, uint32_t addr, - unsigned int size, unsigned int sign) -{ - int r; - - switch (size) { - case 4: - { - r = cpu_ldl_code(env, addr); - break; - } - case 2: - { - if (sign) { - r = cpu_ldsw_code(env, addr); - } else { - r = cpu_lduw_code(env, addr); - } - break; - } - case 1: - { - if (sign) { - r = cpu_ldsb_code(env, addr); - } else { - r = cpu_ldub_code(env, addr); - } - break; - } - default: - cpu_abort(dc->env, "Invalid fetch size %d\n", size); - break; - } - return r; + unsigned int size, unsigned int sign) +{ + int r; + + switch (size) { + case 4: + { + r = cpu_ldl_code(env, addr); + break; + } + case 2: + { + if (sign) { + r = cpu_ldsw_code(env, addr); + } else { + r = cpu_lduw_code(env, addr); + } + break; + } + case 1: + { + if (sign) { + r = cpu_ldsb_code(env, addr); + } else { + r = cpu_ldub_code(env, addr); + } + break; + } + default: + cpu_abort(dc->env, "Invalid fetch size %d\n", size); + break; + } + return r; } static void cris_lock_irq(DisasContext *dc) { - dc->clear_locked_irq = 0; - t_gen_mov_env_TN(locked_irq, tcg_const_tl(1)); + dc->clear_locked_irq = 0; + t_gen_mov_env_TN(locked_irq, tcg_const_tl(1)); } static inline void t_gen_raise_exception(uint32_t index) @@ -284,240 +293,241 @@ static inline void t_gen_raise_exception(uint32_t index) static void t_gen_lsl(TCGv d, TCGv a, TCGv b) { - TCGv t0, t_31; + TCGv t0, t_31; - t0 = tcg_temp_new(); - t_31 = tcg_const_tl(31); - tcg_gen_shl_tl(d, a, b); + t0 = tcg_temp_new(); + t_31 = tcg_const_tl(31); + tcg_gen_shl_tl(d, a, b); - tcg_gen_sub_tl(t0, t_31, b); - tcg_gen_sar_tl(t0, t0, t_31); - tcg_gen_and_tl(t0, t0, d); - tcg_gen_xor_tl(d, d, t0); - tcg_temp_free(t0); - tcg_temp_free(t_31); + tcg_gen_sub_tl(t0, t_31, b); + tcg_gen_sar_tl(t0, t0, t_31); + tcg_gen_and_tl(t0, t0, d); + tcg_gen_xor_tl(d, d, t0); + tcg_temp_free(t0); + tcg_temp_free(t_31); } static void t_gen_lsr(TCGv d, TCGv a, TCGv b) { - TCGv t0, t_31; + TCGv t0, t_31; - t0 = tcg_temp_new(); - t_31 = tcg_temp_new(); - tcg_gen_shr_tl(d, a, b); + t0 = tcg_temp_new(); + t_31 = tcg_temp_new(); + tcg_gen_shr_tl(d, a, b); - tcg_gen_movi_tl(t_31, 31); - tcg_gen_sub_tl(t0, t_31, b); - tcg_gen_sar_tl(t0, t0, t_31); - tcg_gen_and_tl(t0, t0, d); - tcg_gen_xor_tl(d, d, t0); - tcg_temp_free(t0); - tcg_temp_free(t_31); + tcg_gen_movi_tl(t_31, 31); + tcg_gen_sub_tl(t0, t_31, b); + tcg_gen_sar_tl(t0, t0, t_31); + tcg_gen_and_tl(t0, t0, d); + tcg_gen_xor_tl(d, d, t0); + tcg_temp_free(t0); + tcg_temp_free(t_31); } static void t_gen_asr(TCGv d, TCGv a, TCGv b) { - TCGv t0, t_31; + TCGv t0, t_31; - t0 = tcg_temp_new(); - t_31 = tcg_temp_new(); - tcg_gen_sar_tl(d, a, b); + t0 = tcg_temp_new(); + t_31 = tcg_temp_new(); + tcg_gen_sar_tl(d, a, b); - tcg_gen_movi_tl(t_31, 31); - tcg_gen_sub_tl(t0, t_31, b); - tcg_gen_sar_tl(t0, t0, t_31); - tcg_gen_or_tl(d, d, t0); - tcg_temp_free(t0); - tcg_temp_free(t_31); + tcg_gen_movi_tl(t_31, 31); + tcg_gen_sub_tl(t0, t_31, b); + tcg_gen_sar_tl(t0, t0, t_31); + tcg_gen_or_tl(d, d, t0); + tcg_temp_free(t0); + tcg_temp_free(t_31); } /* 64-bit signed mul, lower result in d and upper in d2. */ static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b) { - TCGv_i64 t0, t1; + TCGv_i64 t0, t1; - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(t0, a); - tcg_gen_ext_i32_i64(t1, b); - tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_ext_i32_i64(t0, a); + tcg_gen_ext_i32_i64(t1, b); + tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_trunc_i64_i32(d, t0); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_i32(d2, t0); + tcg_gen_trunc_i64_i32(d, t0); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(d2, t0); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } /* 64-bit unsigned muls, lower result in d and upper in d2. */ static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b) { - TCGv_i64 t0, t1; + TCGv_i64 t0, t1; - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(t0, a); - tcg_gen_extu_i32_i64(t1, b); - tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_extu_i32_i64(t0, a); + tcg_gen_extu_i32_i64(t1, b); + tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_trunc_i64_i32(d, t0); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_i32(d2, t0); + tcg_gen_trunc_i64_i32(d, t0); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(d2, t0); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); } static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b) { - int l1; + int l1; - l1 = gen_new_label(); + l1 = gen_new_label(); - /* - * d <<= 1 - * if (d >= s) - * d -= s; - */ - tcg_gen_shli_tl(d, a, 1); - tcg_gen_brcond_tl(TCG_COND_LTU, d, b, l1); - tcg_gen_sub_tl(d, d, b); - gen_set_label(l1); + /* + * d <<= 1 + * if (d >= s) + * d -= s; + */ + tcg_gen_shli_tl(d, a, 1); + tcg_gen_brcond_tl(TCG_COND_LTU, d, b, l1); + tcg_gen_sub_tl(d, d, b); + gen_set_label(l1); } static void t_gen_cris_mstep(TCGv d, TCGv a, TCGv b, TCGv ccs) { - TCGv t; + TCGv t; - /* - * d <<= 1 - * if (n) - * d += s; - */ - t = tcg_temp_new(); - tcg_gen_shli_tl(d, a, 1); - tcg_gen_shli_tl(t, ccs, 31 - 3); - tcg_gen_sari_tl(t, t, 31); - tcg_gen_and_tl(t, t, b); - tcg_gen_add_tl(d, d, t); - tcg_temp_free(t); + /* + * d <<= 1 + * if (n) + * d += s; + */ + t = tcg_temp_new(); + tcg_gen_shli_tl(d, a, 1); + tcg_gen_shli_tl(t, ccs, 31 - 3); + tcg_gen_sari_tl(t, t, 31); + tcg_gen_and_tl(t, t, b); + tcg_gen_add_tl(d, d, t); + tcg_temp_free(t); } /* Extended arithmetics on CRIS. */ static inline void t_gen_add_flag(TCGv d, int flag) { - TCGv c; + TCGv c; - c = tcg_temp_new(); - t_gen_mov_TN_preg(c, PR_CCS); - /* Propagate carry into d. */ - tcg_gen_andi_tl(c, c, 1 << flag); - if (flag) - tcg_gen_shri_tl(c, c, flag); - tcg_gen_add_tl(d, d, c); - tcg_temp_free(c); + c = tcg_temp_new(); + t_gen_mov_TN_preg(c, PR_CCS); + /* Propagate carry into d. */ + tcg_gen_andi_tl(c, c, 1 << flag); + if (flag) { + tcg_gen_shri_tl(c, c, flag); + } + tcg_gen_add_tl(d, d, c); + tcg_temp_free(c); } static inline void t_gen_addx_carry(DisasContext *dc, TCGv d) { - if (dc->flagx_known) { - if (dc->flags_x) { - TCGv c; + if (dc->flagx_known) { + if (dc->flags_x) { + TCGv c; - c = tcg_temp_new(); - t_gen_mov_TN_preg(c, PR_CCS); - /* C flag is already at bit 0. */ - tcg_gen_andi_tl(c, c, C_FLAG); - tcg_gen_add_tl(d, d, c); - tcg_temp_free(c); - } - } else { - TCGv x, c; - - x = tcg_temp_new(); - c = tcg_temp_new(); - t_gen_mov_TN_preg(x, PR_CCS); - tcg_gen_mov_tl(c, x); - - /* Propagate carry into d if X is set. Branch free. */ - tcg_gen_andi_tl(c, c, C_FLAG); - tcg_gen_andi_tl(x, x, X_FLAG); - tcg_gen_shri_tl(x, x, 4); - - tcg_gen_and_tl(x, x, c); - tcg_gen_add_tl(d, d, x); - tcg_temp_free(x); - tcg_temp_free(c); - } + c = tcg_temp_new(); + t_gen_mov_TN_preg(c, PR_CCS); + /* C flag is already at bit 0. */ + tcg_gen_andi_tl(c, c, C_FLAG); + tcg_gen_add_tl(d, d, c); + tcg_temp_free(c); + } + } else { + TCGv x, c; + + x = tcg_temp_new(); + c = tcg_temp_new(); + t_gen_mov_TN_preg(x, PR_CCS); + tcg_gen_mov_tl(c, x); + + /* Propagate carry into d if X is set. Branch free. */ + tcg_gen_andi_tl(c, c, C_FLAG); + tcg_gen_andi_tl(x, x, X_FLAG); + tcg_gen_shri_tl(x, x, 4); + + tcg_gen_and_tl(x, x, c); + tcg_gen_add_tl(d, d, x); + tcg_temp_free(x); + tcg_temp_free(c); + } } static inline void t_gen_subx_carry(DisasContext *dc, TCGv d) { - if (dc->flagx_known) { - if (dc->flags_x) { - TCGv c; + if (dc->flagx_known) { + if (dc->flags_x) { + TCGv c; - c = tcg_temp_new(); - t_gen_mov_TN_preg(c, PR_CCS); - /* C flag is already at bit 0. */ - tcg_gen_andi_tl(c, c, C_FLAG); - tcg_gen_sub_tl(d, d, c); - tcg_temp_free(c); - } - } else { - TCGv x, c; - - x = tcg_temp_new(); - c = tcg_temp_new(); - t_gen_mov_TN_preg(x, PR_CCS); - tcg_gen_mov_tl(c, x); - - /* Propagate carry into d if X is set. Branch free. */ - tcg_gen_andi_tl(c, c, C_FLAG); - tcg_gen_andi_tl(x, x, X_FLAG); - tcg_gen_shri_tl(x, x, 4); - - tcg_gen_and_tl(x, x, c); - tcg_gen_sub_tl(d, d, x); - tcg_temp_free(x); - tcg_temp_free(c); - } + c = tcg_temp_new(); + t_gen_mov_TN_preg(c, PR_CCS); + /* C flag is already at bit 0. */ + tcg_gen_andi_tl(c, c, C_FLAG); + tcg_gen_sub_tl(d, d, c); + tcg_temp_free(c); + } + } else { + TCGv x, c; + + x = tcg_temp_new(); + c = tcg_temp_new(); + t_gen_mov_TN_preg(x, PR_CCS); + tcg_gen_mov_tl(c, x); + + /* Propagate carry into d if X is set. Branch free. */ + tcg_gen_andi_tl(c, c, C_FLAG); + tcg_gen_andi_tl(x, x, X_FLAG); + tcg_gen_shri_tl(x, x, 4); + + tcg_gen_and_tl(x, x, c); + tcg_gen_sub_tl(d, d, x); + tcg_temp_free(x); + tcg_temp_free(c); + } } /* Swap the two bytes within each half word of the s operand. T0 = ((T0 << 8) & 0xff00ff00) | ((T0 >> 8) & 0x00ff00ff) */ static inline void t_gen_swapb(TCGv d, TCGv s) { - TCGv t, org_s; + TCGv t, org_s; - t = tcg_temp_new(); - org_s = tcg_temp_new(); + t = tcg_temp_new(); + org_s = tcg_temp_new(); - /* d and s may refer to the same object. */ - tcg_gen_mov_tl(org_s, s); - tcg_gen_shli_tl(t, org_s, 8); - tcg_gen_andi_tl(d, t, 0xff00ff00); - tcg_gen_shri_tl(t, org_s, 8); - tcg_gen_andi_tl(t, t, 0x00ff00ff); - tcg_gen_or_tl(d, d, t); - tcg_temp_free(t); - tcg_temp_free(org_s); + /* d and s may refer to the same object. */ + tcg_gen_mov_tl(org_s, s); + tcg_gen_shli_tl(t, org_s, 8); + tcg_gen_andi_tl(d, t, 0xff00ff00); + tcg_gen_shri_tl(t, org_s, 8); + tcg_gen_andi_tl(t, t, 0x00ff00ff); + tcg_gen_or_tl(d, d, t); + tcg_temp_free(t); + tcg_temp_free(org_s); } /* Swap the halfwords of the s operand. */ static inline void t_gen_swapw(TCGv d, TCGv s) { - TCGv t; - /* d and s refer the same object. */ - t = tcg_temp_new(); - tcg_gen_mov_tl(t, s); - tcg_gen_shli_tl(d, t, 16); - tcg_gen_shri_tl(t, t, 16); - tcg_gen_or_tl(d, d, t); - tcg_temp_free(t); + TCGv t; + /* d and s refer the same object. */ + t = tcg_temp_new(); + tcg_gen_mov_tl(t, s); + tcg_gen_shli_tl(d, t, 16); + tcg_gen_shri_tl(t, t, 16); + tcg_gen_or_tl(d, d, t); + tcg_temp_free(t); } /* Reverse the within each byte. @@ -532,607 +542,611 @@ static inline void t_gen_swapw(TCGv d, TCGv s) */ static inline void t_gen_swapr(TCGv d, TCGv s) { - struct { - int shift; /* LSL when positive, LSR when negative. */ - uint32_t mask; - } bitrev [] = { - {7, 0x80808080}, - {5, 0x40404040}, - {3, 0x20202020}, - {1, 0x10101010}, - {-1, 0x08080808}, - {-3, 0x04040404}, - {-5, 0x02020202}, - {-7, 0x01010101} - }; - int i; - TCGv t, org_s; - - /* d and s refer the same object. */ - t = tcg_temp_new(); - org_s = tcg_temp_new(); - tcg_gen_mov_tl(org_s, s); - - tcg_gen_shli_tl(t, org_s, bitrev[0].shift); - tcg_gen_andi_tl(d, t, bitrev[0].mask); - for (i = 1; i < ARRAY_SIZE(bitrev); i++) { - if (bitrev[i].shift >= 0) { - tcg_gen_shli_tl(t, org_s, bitrev[i].shift); - } else { - tcg_gen_shri_tl(t, org_s, -bitrev[i].shift); - } - tcg_gen_andi_tl(t, t, bitrev[i].mask); - tcg_gen_or_tl(d, d, t); - } - tcg_temp_free(t); - tcg_temp_free(org_s); + struct { + int shift; /* LSL when positive, LSR when negative. */ + uint32_t mask; + } bitrev[] = { + {7, 0x80808080}, + {5, 0x40404040}, + {3, 0x20202020}, + {1, 0x10101010}, + {-1, 0x08080808}, + {-3, 0x04040404}, + {-5, 0x02020202}, + {-7, 0x01010101} + }; + int i; + TCGv t, org_s; + + /* d and s refer the same object. */ + t = tcg_temp_new(); + org_s = tcg_temp_new(); + tcg_gen_mov_tl(org_s, s); + + tcg_gen_shli_tl(t, org_s, bitrev[0].shift); + tcg_gen_andi_tl(d, t, bitrev[0].mask); + for (i = 1; i < ARRAY_SIZE(bitrev); i++) { + if (bitrev[i].shift >= 0) { + tcg_gen_shli_tl(t, org_s, bitrev[i].shift); + } else { + tcg_gen_shri_tl(t, org_s, -bitrev[i].shift); + } + tcg_gen_andi_tl(t, t, bitrev[i].mask); + tcg_gen_or_tl(d, d, t); + } + tcg_temp_free(t); + tcg_temp_free(org_s); } static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false) { - int l1; + int l1; - l1 = gen_new_label(); + l1 = gen_new_label(); - /* Conditional jmp. */ - tcg_gen_mov_tl(env_pc, pc_false); - tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1); - tcg_gen_mov_tl(env_pc, pc_true); - gen_set_label(l1); + /* Conditional jmp. */ + tcg_gen_mov_tl(env_pc, pc_false); + tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1); + tcg_gen_mov_tl(env_pc, pc_true); + gen_set_label(l1); } static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) { - TranslationBlock *tb; - tb = dc->tb; - if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { - tcg_gen_goto_tb(n); - tcg_gen_movi_tl(env_pc, dest); + TranslationBlock *tb; + tb = dc->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + tcg_gen_goto_tb(n); + tcg_gen_movi_tl(env_pc, dest); tcg_gen_exit_tb((tcg_target_long)tb + n); - } else { - tcg_gen_movi_tl(env_pc, dest); - tcg_gen_exit_tb(0); - } + } else { + tcg_gen_movi_tl(env_pc, dest); + tcg_gen_exit_tb(0); + } } static inline void cris_clear_x_flag(DisasContext *dc) { - if (dc->flagx_known && dc->flags_x) - dc->flags_uptodate = 0; + if (dc->flagx_known && dc->flags_x) { + dc->flags_uptodate = 0; + } - dc->flagx_known = 1; - dc->flags_x = 0; + dc->flagx_known = 1; + dc->flags_x = 0; } static void cris_flush_cc_state(DisasContext *dc) { - if (dc->cc_size_uptodate != dc->cc_size) { - tcg_gen_movi_tl(cc_size, dc->cc_size); - dc->cc_size_uptodate = dc->cc_size; - } - tcg_gen_movi_tl(cc_op, dc->cc_op); - tcg_gen_movi_tl(cc_mask, dc->cc_mask); + if (dc->cc_size_uptodate != dc->cc_size) { + tcg_gen_movi_tl(cc_size, dc->cc_size); + dc->cc_size_uptodate = dc->cc_size; + } + tcg_gen_movi_tl(cc_op, dc->cc_op); + tcg_gen_movi_tl(cc_mask, dc->cc_mask); } static void cris_evaluate_flags(DisasContext *dc) { - if (dc->flags_uptodate) - return; - - cris_flush_cc_state(dc); - - switch (dc->cc_op) - { - case CC_OP_MCP: - gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS], cpu_env, - cpu_PR[PR_CCS], cc_src, - cc_dest, cc_result); - break; - case CC_OP_MULS: - gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS], cpu_env, - cpu_PR[PR_CCS], cc_result, - cpu_PR[PR_MOF]); - break; - case CC_OP_MULU: - gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS], cpu_env, - cpu_PR[PR_CCS], cc_result, - cpu_PR[PR_MOF]); - break; - case CC_OP_MOVE: - case CC_OP_AND: - case CC_OP_OR: - case CC_OP_XOR: - case CC_OP_ASR: - case CC_OP_LSR: - case CC_OP_LSL: - switch (dc->cc_size) - { - case 4: - gen_helper_evaluate_flags_move_4(cpu_PR[PR_CCS], - cpu_env, cpu_PR[PR_CCS], cc_result); - break; - case 2: - gen_helper_evaluate_flags_move_2(cpu_PR[PR_CCS], - cpu_env, cpu_PR[PR_CCS], cc_result); - break; - default: - gen_helper_evaluate_flags(cpu_env); - break; - } - break; - case CC_OP_FLAGS: - /* live. */ - break; - case CC_OP_SUB: - case CC_OP_CMP: - if (dc->cc_size == 4) - gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS], cpu_env, - cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); - else - gen_helper_evaluate_flags(cpu_env); - - break; - default: - switch (dc->cc_size) - { - case 4: - gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS], cpu_env, - cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); - break; - default: - gen_helper_evaluate_flags(cpu_env); - break; - } - break; - } - - if (dc->flagx_known) { - if (dc->flags_x) - tcg_gen_ori_tl(cpu_PR[PR_CCS], - cpu_PR[PR_CCS], X_FLAG); - else if (dc->cc_op == CC_OP_FLAGS) - tcg_gen_andi_tl(cpu_PR[PR_CCS], - cpu_PR[PR_CCS], ~X_FLAG); + if (dc->flags_uptodate) { + return; + } + + cris_flush_cc_state(dc); + + switch (dc->cc_op) { + case CC_OP_MCP: + gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_src, + cc_dest, cc_result); + break; + case CC_OP_MULS: + gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_result, + cpu_PR[PR_MOF]); + break; + case CC_OP_MULU: + gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_result, + cpu_PR[PR_MOF]); + break; + case CC_OP_MOVE: + case CC_OP_AND: + case CC_OP_OR: + case CC_OP_XOR: + case CC_OP_ASR: + case CC_OP_LSR: + case CC_OP_LSL: + switch (dc->cc_size) { + case 4: + gen_helper_evaluate_flags_move_4(cpu_PR[PR_CCS], + cpu_env, cpu_PR[PR_CCS], cc_result); + break; + case 2: + gen_helper_evaluate_flags_move_2(cpu_PR[PR_CCS], + cpu_env, cpu_PR[PR_CCS], cc_result); + break; + default: + gen_helper_evaluate_flags(cpu_env); + break; + } + break; + case CC_OP_FLAGS: + /* live. */ + break; + case CC_OP_SUB: + case CC_OP_CMP: + if (dc->cc_size == 4) { + gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); + } else { + gen_helper_evaluate_flags(cpu_env); + } + + break; + default: + switch (dc->cc_size) { + case 4: + gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); + break; + default: + gen_helper_evaluate_flags(cpu_env); + break; } - dc->flags_uptodate = 1; + break; + } + + if (dc->flagx_known) { + if (dc->flags_x) { + tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], X_FLAG); + } else if (dc->cc_op == CC_OP_FLAGS) { + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~X_FLAG); + } + } + dc->flags_uptodate = 1; } static void cris_cc_mask(DisasContext *dc, unsigned int mask) { - uint32_t ovl; + uint32_t ovl; - if (!mask) { - dc->update_cc = 0; - return; - } + if (!mask) { + dc->update_cc = 0; + return; + } - /* Check if we need to evaluate the condition codes due to - CC overlaying. */ - ovl = (dc->cc_mask ^ mask) & ~mask; - if (ovl) { - /* TODO: optimize this case. It trigs all the time. */ - cris_evaluate_flags (dc); - } - dc->cc_mask = mask; - dc->update_cc = 1; + /* Check if we need to evaluate the condition codes due to + CC overlaying. */ + ovl = (dc->cc_mask ^ mask) & ~mask; + if (ovl) { + /* TODO: optimize this case. It trigs all the time. */ + cris_evaluate_flags(dc); + } + dc->cc_mask = mask; + dc->update_cc = 1; } static void cris_update_cc_op(DisasContext *dc, int op, int size) { - dc->cc_op = op; - dc->cc_size = size; - dc->flags_uptodate = 0; + dc->cc_op = op; + dc->cc_size = size; + dc->flags_uptodate = 0; } static inline void cris_update_cc_x(DisasContext *dc) { - /* Save the x flag state at the time of the cc snapshot. */ - if (dc->flagx_known) { - if (dc->cc_x_uptodate == (2 | dc->flags_x)) - return; - tcg_gen_movi_tl(cc_x, dc->flags_x); - dc->cc_x_uptodate = 2 | dc->flags_x; - } - else { - tcg_gen_andi_tl(cc_x, cpu_PR[PR_CCS], X_FLAG); - dc->cc_x_uptodate = 1; - } + /* Save the x flag state at the time of the cc snapshot. */ + if (dc->flagx_known) { + if (dc->cc_x_uptodate == (2 | dc->flags_x)) { + return; + } + tcg_gen_movi_tl(cc_x, dc->flags_x); + dc->cc_x_uptodate = 2 | dc->flags_x; + } else { + tcg_gen_andi_tl(cc_x, cpu_PR[PR_CCS], X_FLAG); + dc->cc_x_uptodate = 1; + } } /* Update cc prior to executing ALU op. Needs source operands untouched. */ static void cris_pre_alu_update_cc(DisasContext *dc, int op, - TCGv dst, TCGv src, int size) -{ - if (dc->update_cc) { - cris_update_cc_op(dc, op, size); - tcg_gen_mov_tl(cc_src, src); - - if (op != CC_OP_MOVE - && op != CC_OP_AND - && op != CC_OP_OR - && op != CC_OP_XOR - && op != CC_OP_ASR - && op != CC_OP_LSR - && op != CC_OP_LSL) - tcg_gen_mov_tl(cc_dest, dst); + TCGv dst, TCGv src, int size) +{ + if (dc->update_cc) { + cris_update_cc_op(dc, op, size); + tcg_gen_mov_tl(cc_src, src); + + if (op != CC_OP_MOVE + && op != CC_OP_AND + && op != CC_OP_OR + && op != CC_OP_XOR + && op != CC_OP_ASR + && op != CC_OP_LSR + && op != CC_OP_LSL) { + tcg_gen_mov_tl(cc_dest, dst); + } - cris_update_cc_x(dc); - } + cris_update_cc_x(dc); + } } /* Update cc after executing ALU op. needs the result. */ static inline void cris_update_result(DisasContext *dc, TCGv res) { - if (dc->update_cc) - tcg_gen_mov_tl(cc_result, res); + if (dc->update_cc) { + tcg_gen_mov_tl(cc_result, res); + } } /* Returns one if the write back stage should execute. */ static void cris_alu_op_exec(DisasContext *dc, int op, - TCGv dst, TCGv a, TCGv b, int size) -{ - /* Emit the ALU insns. */ - switch (op) - { - case CC_OP_ADD: - tcg_gen_add_tl(dst, a, b); - /* Extended arithmetics. */ - t_gen_addx_carry(dc, dst); - break; - case CC_OP_ADDC: - tcg_gen_add_tl(dst, a, b); - t_gen_add_flag(dst, 0); /* C_FLAG. */ - break; - case CC_OP_MCP: - tcg_gen_add_tl(dst, a, b); - t_gen_add_flag(dst, 8); /* R_FLAG. */ - break; - case CC_OP_SUB: - tcg_gen_sub_tl(dst, a, b); - /* Extended arithmetics. */ - t_gen_subx_carry(dc, dst); - break; - case CC_OP_MOVE: - tcg_gen_mov_tl(dst, b); - break; - case CC_OP_OR: - tcg_gen_or_tl(dst, a, b); - break; - case CC_OP_AND: - tcg_gen_and_tl(dst, a, b); - break; - case CC_OP_XOR: - tcg_gen_xor_tl(dst, a, b); - break; - case CC_OP_LSL: - t_gen_lsl(dst, a, b); - break; - case CC_OP_LSR: - t_gen_lsr(dst, a, b); - break; - case CC_OP_ASR: - t_gen_asr(dst, a, b); - break; - case CC_OP_NEG: - tcg_gen_neg_tl(dst, b); - /* Extended arithmetics. */ - t_gen_subx_carry(dc, dst); - break; - case CC_OP_LZ: - gen_helper_lz(dst, b); - break; - case CC_OP_MULS: - t_gen_muls(dst, cpu_PR[PR_MOF], a, b); - break; - case CC_OP_MULU: - t_gen_mulu(dst, cpu_PR[PR_MOF], a, b); - break; - case CC_OP_DSTEP: - t_gen_cris_dstep(dst, a, b); - break; - case CC_OP_MSTEP: - t_gen_cris_mstep(dst, a, b, cpu_PR[PR_CCS]); - break; - case CC_OP_BOUND: - { - int l1; - l1 = gen_new_label(); - tcg_gen_mov_tl(dst, a); - tcg_gen_brcond_tl(TCG_COND_LEU, a, b, l1); - tcg_gen_mov_tl(dst, b); - gen_set_label(l1); - } - break; - case CC_OP_CMP: - tcg_gen_sub_tl(dst, a, b); - /* Extended arithmetics. */ - t_gen_subx_carry(dc, dst); - break; - default: - qemu_log("illegal ALU op.\n"); - BUG(); - break; - } - - if (size == 1) - tcg_gen_andi_tl(dst, dst, 0xff); - else if (size == 2) - tcg_gen_andi_tl(dst, dst, 0xffff); + TCGv dst, TCGv a, TCGv b, int size) +{ + /* Emit the ALU insns. */ + switch (op) { + case CC_OP_ADD: + tcg_gen_add_tl(dst, a, b); + /* Extended arithmetics. */ + t_gen_addx_carry(dc, dst); + break; + case CC_OP_ADDC: + tcg_gen_add_tl(dst, a, b); + t_gen_add_flag(dst, 0); /* C_FLAG. */ + break; + case CC_OP_MCP: + tcg_gen_add_tl(dst, a, b); + t_gen_add_flag(dst, 8); /* R_FLAG. */ + break; + case CC_OP_SUB: + tcg_gen_sub_tl(dst, a, b); + /* Extended arithmetics. */ + t_gen_subx_carry(dc, dst); + break; + case CC_OP_MOVE: + tcg_gen_mov_tl(dst, b); + break; + case CC_OP_OR: + tcg_gen_or_tl(dst, a, b); + break; + case CC_OP_AND: + tcg_gen_and_tl(dst, a, b); + break; + case CC_OP_XOR: + tcg_gen_xor_tl(dst, a, b); + break; + case CC_OP_LSL: + t_gen_lsl(dst, a, b); + break; + case CC_OP_LSR: + t_gen_lsr(dst, a, b); + break; + case CC_OP_ASR: + t_gen_asr(dst, a, b); + break; + case CC_OP_NEG: + tcg_gen_neg_tl(dst, b); + /* Extended arithmetics. */ + t_gen_subx_carry(dc, dst); + break; + case CC_OP_LZ: + gen_helper_lz(dst, b); + break; + case CC_OP_MULS: + t_gen_muls(dst, cpu_PR[PR_MOF], a, b); + break; + case CC_OP_MULU: + t_gen_mulu(dst, cpu_PR[PR_MOF], a, b); + break; + case CC_OP_DSTEP: + t_gen_cris_dstep(dst, a, b); + break; + case CC_OP_MSTEP: + t_gen_cris_mstep(dst, a, b, cpu_PR[PR_CCS]); + break; + case CC_OP_BOUND: + { + int l1; + l1 = gen_new_label(); + tcg_gen_mov_tl(dst, a); + tcg_gen_brcond_tl(TCG_COND_LEU, a, b, l1); + tcg_gen_mov_tl(dst, b); + gen_set_label(l1); + } + break; + case CC_OP_CMP: + tcg_gen_sub_tl(dst, a, b); + /* Extended arithmetics. */ + t_gen_subx_carry(dc, dst); + break; + default: + qemu_log("illegal ALU op.\n"); + BUG(); + break; + } + + if (size == 1) { + tcg_gen_andi_tl(dst, dst, 0xff); + } else if (size == 2) { + tcg_gen_andi_tl(dst, dst, 0xffff); + } } static void cris_alu(DisasContext *dc, int op, - TCGv d, TCGv op_a, TCGv op_b, int size) + TCGv d, TCGv op_a, TCGv op_b, int size) { - TCGv tmp; - int writeback; + TCGv tmp; + int writeback; - writeback = 1; + writeback = 1; - if (op == CC_OP_CMP) { - tmp = tcg_temp_new(); - writeback = 0; - } else if (size == 4) { - tmp = d; - writeback = 0; - } else - tmp = tcg_temp_new(); + if (op == CC_OP_CMP) { + tmp = tcg_temp_new(); + writeback = 0; + } else if (size == 4) { + tmp = d; + writeback = 0; + } else { + tmp = tcg_temp_new(); + } - cris_pre_alu_update_cc(dc, op, op_a, op_b, size); - cris_alu_op_exec(dc, op, tmp, op_a, op_b, size); - cris_update_result(dc, tmp); + cris_pre_alu_update_cc(dc, op, op_a, op_b, size); + cris_alu_op_exec(dc, op, tmp, op_a, op_b, size); + cris_update_result(dc, tmp); - /* Writeback. */ - if (writeback) { - if (size == 1) - tcg_gen_andi_tl(d, d, ~0xff); - else - tcg_gen_andi_tl(d, d, ~0xffff); - tcg_gen_or_tl(d, d, tmp); - } - if (!TCGV_EQUAL(tmp, d)) - tcg_temp_free(tmp); + /* Writeback. */ + if (writeback) { + if (size == 1) { + tcg_gen_andi_tl(d, d, ~0xff); + } else { + tcg_gen_andi_tl(d, d, ~0xffff); + } + tcg_gen_or_tl(d, d, tmp); + } + if (!TCGV_EQUAL(tmp, d)) { + tcg_temp_free(tmp); + } } static int arith_cc(DisasContext *dc) { - if (dc->update_cc) { - switch (dc->cc_op) { - case CC_OP_ADDC: return 1; - case CC_OP_ADD: return 1; - case CC_OP_SUB: return 1; - case CC_OP_DSTEP: return 1; - case CC_OP_LSL: return 1; - case CC_OP_LSR: return 1; - case CC_OP_ASR: return 1; - case CC_OP_CMP: return 1; - case CC_OP_NEG: return 1; - case CC_OP_OR: return 1; - case CC_OP_AND: return 1; - case CC_OP_XOR: return 1; - case CC_OP_MULU: return 1; - case CC_OP_MULS: return 1; - default: - return 0; - } - } - return 0; + if (dc->update_cc) { + switch (dc->cc_op) { + case CC_OP_ADDC: return 1; + case CC_OP_ADD: return 1; + case CC_OP_SUB: return 1; + case CC_OP_DSTEP: return 1; + case CC_OP_LSL: return 1; + case CC_OP_LSR: return 1; + case CC_OP_ASR: return 1; + case CC_OP_CMP: return 1; + case CC_OP_NEG: return 1; + case CC_OP_OR: return 1; + case CC_OP_AND: return 1; + case CC_OP_XOR: return 1; + case CC_OP_MULU: return 1; + case CC_OP_MULS: return 1; + default: + return 0; + } + } + return 0; } static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond) { - int arith_opt, move_opt; - - /* TODO: optimize more condition codes. */ - - /* - * If the flags are live, we've gotta look into the bits of CCS. - * Otherwise, if we just did an arithmetic operation we try to - * evaluate the condition code faster. - * - * When this function is done, T0 should be non-zero if the condition - * code is true. - */ - arith_opt = arith_cc(dc) && !dc->flags_uptodate; - move_opt = (dc->cc_op == CC_OP_MOVE); - switch (cond) { - case CC_EQ: - if ((arith_opt || move_opt) - && dc->cc_x_uptodate != (2 | X_FLAG)) { - tcg_gen_setcond_tl(TCG_COND_EQ, cc, - cc_result, tcg_const_tl(0)); - } - else { - cris_evaluate_flags(dc); - tcg_gen_andi_tl(cc, - cpu_PR[PR_CCS], Z_FLAG); - } - break; - case CC_NE: - if ((arith_opt || move_opt) - && dc->cc_x_uptodate != (2 | X_FLAG)) { - tcg_gen_mov_tl(cc, cc_result); - } else { - cris_evaluate_flags(dc); - tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], - Z_FLAG); - tcg_gen_andi_tl(cc, cc, Z_FLAG); - } - break; - case CC_CS: - cris_evaluate_flags(dc); - tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], C_FLAG); - break; - case CC_CC: - cris_evaluate_flags(dc); - tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], C_FLAG); - tcg_gen_andi_tl(cc, cc, C_FLAG); - break; - case CC_VS: - cris_evaluate_flags(dc); - tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], V_FLAG); - break; - case CC_VC: - cris_evaluate_flags(dc); - tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], - V_FLAG); - tcg_gen_andi_tl(cc, cc, V_FLAG); - break; - case CC_PL: - if (arith_opt || move_opt) { - int bits = 31; - - if (dc->cc_size == 1) - bits = 7; - else if (dc->cc_size == 2) - bits = 15; - - tcg_gen_shri_tl(cc, cc_result, bits); - tcg_gen_xori_tl(cc, cc, 1); - } else { - cris_evaluate_flags(dc); - tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], - N_FLAG); - tcg_gen_andi_tl(cc, cc, N_FLAG); - } - break; - case CC_MI: - if (arith_opt || move_opt) { - int bits = 31; - - if (dc->cc_size == 1) - bits = 7; - else if (dc->cc_size == 2) - bits = 15; - - tcg_gen_shri_tl(cc, cc_result, bits); - tcg_gen_andi_tl(cc, cc, 1); - } - else { - cris_evaluate_flags(dc); - tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], - N_FLAG); - } - break; - case CC_LS: - cris_evaluate_flags(dc); - tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], - C_FLAG | Z_FLAG); - break; - case CC_HI: - cris_evaluate_flags(dc); - { - TCGv tmp; - - tmp = tcg_temp_new(); - tcg_gen_xori_tl(tmp, cpu_PR[PR_CCS], - C_FLAG | Z_FLAG); - /* Overlay the C flag on top of the Z. */ - tcg_gen_shli_tl(cc, tmp, 2); - tcg_gen_and_tl(cc, tmp, cc); - tcg_gen_andi_tl(cc, cc, Z_FLAG); - - tcg_temp_free(tmp); - } - break; - case CC_GE: - cris_evaluate_flags(dc); - /* Overlay the V flag on top of the N. */ - tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2); - tcg_gen_xor_tl(cc, - cpu_PR[PR_CCS], cc); - tcg_gen_andi_tl(cc, cc, N_FLAG); - tcg_gen_xori_tl(cc, cc, N_FLAG); - break; - case CC_LT: - cris_evaluate_flags(dc); - /* Overlay the V flag on top of the N. */ - tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2); - tcg_gen_xor_tl(cc, - cpu_PR[PR_CCS], cc); - tcg_gen_andi_tl(cc, cc, N_FLAG); - break; - case CC_GT: - cris_evaluate_flags(dc); - { - TCGv n, z; - - n = tcg_temp_new(); - z = tcg_temp_new(); - - /* To avoid a shift we overlay everything on - the V flag. */ - tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2); - tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1); - /* invert Z. */ - tcg_gen_xori_tl(z, z, 2); - - tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]); - tcg_gen_xori_tl(n, n, 2); - tcg_gen_and_tl(cc, z, n); - tcg_gen_andi_tl(cc, cc, 2); - - tcg_temp_free(n); - tcg_temp_free(z); - } - break; - case CC_LE: - cris_evaluate_flags(dc); - { - TCGv n, z; - - n = tcg_temp_new(); - z = tcg_temp_new(); - - /* To avoid a shift we overlay everything on - the V flag. */ - tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2); - tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1); - - tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]); - tcg_gen_or_tl(cc, z, n); - tcg_gen_andi_tl(cc, cc, 2); - - tcg_temp_free(n); - tcg_temp_free(z); - } - break; - case CC_P: - cris_evaluate_flags(dc); - tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], P_FLAG); - break; - case CC_A: - tcg_gen_movi_tl(cc, 1); - break; - default: - BUG(); - break; - }; + int arith_opt, move_opt; + + /* TODO: optimize more condition codes. */ + + /* + * If the flags are live, we've gotta look into the bits of CCS. + * Otherwise, if we just did an arithmetic operation we try to + * evaluate the condition code faster. + * + * When this function is done, T0 should be non-zero if the condition + * code is true. + */ + arith_opt = arith_cc(dc) && !dc->flags_uptodate; + move_opt = (dc->cc_op == CC_OP_MOVE); + switch (cond) { + case CC_EQ: + if ((arith_opt || move_opt) + && dc->cc_x_uptodate != (2 | X_FLAG)) { + tcg_gen_setcond_tl(TCG_COND_EQ, cc, + cc_result, tcg_const_tl(0)); + } else { + cris_evaluate_flags(dc); + tcg_gen_andi_tl(cc, + cpu_PR[PR_CCS], Z_FLAG); + } + break; + case CC_NE: + if ((arith_opt || move_opt) + && dc->cc_x_uptodate != (2 | X_FLAG)) { + tcg_gen_mov_tl(cc, cc_result); + } else { + cris_evaluate_flags(dc); + tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], + Z_FLAG); + tcg_gen_andi_tl(cc, cc, Z_FLAG); + } + break; + case CC_CS: + cris_evaluate_flags(dc); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], C_FLAG); + break; + case CC_CC: + cris_evaluate_flags(dc); + tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], C_FLAG); + tcg_gen_andi_tl(cc, cc, C_FLAG); + break; + case CC_VS: + cris_evaluate_flags(dc); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], V_FLAG); + break; + case CC_VC: + cris_evaluate_flags(dc); + tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], + V_FLAG); + tcg_gen_andi_tl(cc, cc, V_FLAG); + break; + case CC_PL: + if (arith_opt || move_opt) { + int bits = 31; + + if (dc->cc_size == 1) { + bits = 7; + } else if (dc->cc_size == 2) { + bits = 15; + } + + tcg_gen_shri_tl(cc, cc_result, bits); + tcg_gen_xori_tl(cc, cc, 1); + } else { + cris_evaluate_flags(dc); + tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], + N_FLAG); + tcg_gen_andi_tl(cc, cc, N_FLAG); + } + break; + case CC_MI: + if (arith_opt || move_opt) { + int bits = 31; + + if (dc->cc_size == 1) { + bits = 7; + } else if (dc->cc_size == 2) { + bits = 15; + } + + tcg_gen_shri_tl(cc, cc_result, bits); + tcg_gen_andi_tl(cc, cc, 1); + } else { + cris_evaluate_flags(dc); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], + N_FLAG); + } + break; + case CC_LS: + cris_evaluate_flags(dc); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], + C_FLAG | Z_FLAG); + break; + case CC_HI: + cris_evaluate_flags(dc); + { + TCGv tmp; + + tmp = tcg_temp_new(); + tcg_gen_xori_tl(tmp, cpu_PR[PR_CCS], + C_FLAG | Z_FLAG); + /* Overlay the C flag on top of the Z. */ + tcg_gen_shli_tl(cc, tmp, 2); + tcg_gen_and_tl(cc, tmp, cc); + tcg_gen_andi_tl(cc, cc, Z_FLAG); + + tcg_temp_free(tmp); + } + break; + case CC_GE: + cris_evaluate_flags(dc); + /* Overlay the V flag on top of the N. */ + tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2); + tcg_gen_xor_tl(cc, + cpu_PR[PR_CCS], cc); + tcg_gen_andi_tl(cc, cc, N_FLAG); + tcg_gen_xori_tl(cc, cc, N_FLAG); + break; + case CC_LT: + cris_evaluate_flags(dc); + /* Overlay the V flag on top of the N. */ + tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2); + tcg_gen_xor_tl(cc, + cpu_PR[PR_CCS], cc); + tcg_gen_andi_tl(cc, cc, N_FLAG); + break; + case CC_GT: + cris_evaluate_flags(dc); + { + TCGv n, z; + + n = tcg_temp_new(); + z = tcg_temp_new(); + + /* To avoid a shift we overlay everything on + the V flag. */ + tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2); + tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1); + /* invert Z. */ + tcg_gen_xori_tl(z, z, 2); + + tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]); + tcg_gen_xori_tl(n, n, 2); + tcg_gen_and_tl(cc, z, n); + tcg_gen_andi_tl(cc, cc, 2); + + tcg_temp_free(n); + tcg_temp_free(z); + } + break; + case CC_LE: + cris_evaluate_flags(dc); + { + TCGv n, z; + + n = tcg_temp_new(); + z = tcg_temp_new(); + + /* To avoid a shift we overlay everything on + the V flag. */ + tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2); + tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1); + + tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]); + tcg_gen_or_tl(cc, z, n); + tcg_gen_andi_tl(cc, cc, 2); + + tcg_temp_free(n); + tcg_temp_free(z); + } + break; + case CC_P: + cris_evaluate_flags(dc); + tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], P_FLAG); + break; + case CC_A: + tcg_gen_movi_tl(cc, 1); + break; + default: + BUG(); + break; + }; } static void cris_store_direct_jmp(DisasContext *dc) { - /* Store the direct jmp state into the cpu-state. */ - if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { - if (dc->jmp == JMP_DIRECT) { - tcg_gen_movi_tl(env_btaken, 1); - } - tcg_gen_movi_tl(env_btarget, dc->jmp_pc); - dc->jmp = JMP_INDIRECT; - } + /* Store the direct jmp state into the cpu-state. */ + if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { + if (dc->jmp == JMP_DIRECT) { + tcg_gen_movi_tl(env_btaken, 1); + } + tcg_gen_movi_tl(env_btarget, dc->jmp_pc); + dc->jmp = JMP_INDIRECT; + } } static void cris_prepare_cc_branch (DisasContext *dc, - int offset, int cond) + int offset, int cond) { - /* This helps us re-schedule the micro-code to insns in delay-slots - before the actual jump. */ - dc->delayed_branch = 2; - dc->jmp = JMP_DIRECT_CC; - dc->jmp_pc = dc->pc + offset; + /* This helps us re-schedule the micro-code to insns in delay-slots + before the actual jump. */ + dc->delayed_branch = 2; + dc->jmp = JMP_DIRECT_CC; + dc->jmp_pc = dc->pc + offset; - gen_tst_cc (dc, env_btaken, cond); - tcg_gen_movi_tl(env_btarget, dc->jmp_pc); + gen_tst_cc(dc, env_btaken, cond); + tcg_gen_movi_tl(env_btarget, dc->jmp_pc); } @@ -1140,199 +1154,207 @@ static void cris_prepare_cc_branch (DisasContext *dc, when the dest addr is constant to allow tb chaining. */ static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type) { - /* This helps us re-schedule the micro-code to insns in delay-slots - before the actual jump. */ - dc->delayed_branch = 2; - dc->jmp = type; - if (type == JMP_INDIRECT) { - tcg_gen_movi_tl(env_btaken, 1); - } + /* This helps us re-schedule the micro-code to insns in delay-slots + before the actual jump. */ + dc->delayed_branch = 2; + dc->jmp = type; + if (type == JMP_INDIRECT) { + tcg_gen_movi_tl(env_btaken, 1); + } } static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr) { - int mem_index = cpu_mmu_index(dc->env); + int mem_index = cpu_mmu_index(dc->env); - /* If we get a fault on a delayslot we must keep the jmp state in - the cpu-state to be able to re-execute the jmp. */ - if (dc->delayed_branch == 1) - cris_store_direct_jmp(dc); + /* If we get a fault on a delayslot we must keep the jmp state in + the cpu-state to be able to re-execute the jmp. */ + if (dc->delayed_branch == 1) { + cris_store_direct_jmp(dc); + } - tcg_gen_qemu_ld64(dst, addr, mem_index); + tcg_gen_qemu_ld64(dst, addr, mem_index); } static void gen_load(DisasContext *dc, TCGv dst, TCGv addr, - unsigned int size, int sign) -{ - int mem_index = cpu_mmu_index(dc->env); - - /* If we get a fault on a delayslot we must keep the jmp state in - the cpu-state to be able to re-execute the jmp. */ - if (dc->delayed_branch == 1) - cris_store_direct_jmp(dc); - - if (size == 1) { - if (sign) - tcg_gen_qemu_ld8s(dst, addr, mem_index); - else - tcg_gen_qemu_ld8u(dst, addr, mem_index); - } - else if (size == 2) { - if (sign) - tcg_gen_qemu_ld16s(dst, addr, mem_index); - else - tcg_gen_qemu_ld16u(dst, addr, mem_index); - } - else if (size == 4) { - tcg_gen_qemu_ld32u(dst, addr, mem_index); - } - else { - abort(); - } + unsigned int size, int sign) +{ + int mem_index = cpu_mmu_index(dc->env); + + /* If we get a fault on a delayslot we must keep the jmp state in + the cpu-state to be able to re-execute the jmp. */ + if (dc->delayed_branch == 1) { + cris_store_direct_jmp(dc); + } + + if (size == 1) { + if (sign) { + tcg_gen_qemu_ld8s(dst, addr, mem_index); + } else { + tcg_gen_qemu_ld8u(dst, addr, mem_index); + } + } else if (size == 2) { + if (sign) { + tcg_gen_qemu_ld16s(dst, addr, mem_index); + } else { + tcg_gen_qemu_ld16u(dst, addr, mem_index); + } + } else if (size == 4) { + tcg_gen_qemu_ld32u(dst, addr, mem_index); + } else { + abort(); + } } static void gen_store (DisasContext *dc, TCGv addr, TCGv val, - unsigned int size) + unsigned int size) { - int mem_index = cpu_mmu_index(dc->env); + int mem_index = cpu_mmu_index(dc->env); - /* If we get a fault on a delayslot we must keep the jmp state in - the cpu-state to be able to re-execute the jmp. */ - if (dc->delayed_branch == 1) - cris_store_direct_jmp(dc); + /* If we get a fault on a delayslot we must keep the jmp state in + the cpu-state to be able to re-execute the jmp. */ + if (dc->delayed_branch == 1) { + cris_store_direct_jmp(dc); + } - /* Conditional writes. We only support the kind were X and P are known - at translation time. */ - if (dc->flagx_known && dc->flags_x && (dc->tb_flags & P_FLAG)) { - dc->postinc = 0; - cris_evaluate_flags(dc); - tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], C_FLAG); - return; - } + /* Conditional writes. We only support the kind were X and P are known + at translation time. */ + if (dc->flagx_known && dc->flags_x && (dc->tb_flags & P_FLAG)) { + dc->postinc = 0; + cris_evaluate_flags(dc); + tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], C_FLAG); + return; + } - if (size == 1) - tcg_gen_qemu_st8(val, addr, mem_index); - else if (size == 2) - tcg_gen_qemu_st16(val, addr, mem_index); - else - tcg_gen_qemu_st32(val, addr, mem_index); + if (size == 1) { + tcg_gen_qemu_st8(val, addr, mem_index); + } else if (size == 2) { + tcg_gen_qemu_st16(val, addr, mem_index); + } else { + tcg_gen_qemu_st32(val, addr, mem_index); + } - if (dc->flagx_known && dc->flags_x) { - cris_evaluate_flags(dc); - tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~C_FLAG); - } + if (dc->flagx_known && dc->flags_x) { + cris_evaluate_flags(dc); + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~C_FLAG); + } } static inline void t_gen_sext(TCGv d, TCGv s, int size) { - if (size == 1) - tcg_gen_ext8s_i32(d, s); - else if (size == 2) - tcg_gen_ext16s_i32(d, s); - else if(!TCGV_EQUAL(d, s)) - tcg_gen_mov_tl(d, s); + if (size == 1) { + tcg_gen_ext8s_i32(d, s); + } else if (size == 2) { + tcg_gen_ext16s_i32(d, s); + } else if (!TCGV_EQUAL(d, s)) { + tcg_gen_mov_tl(d, s); + } } static inline void t_gen_zext(TCGv d, TCGv s, int size) { - if (size == 1) - tcg_gen_ext8u_i32(d, s); - else if (size == 2) - tcg_gen_ext16u_i32(d, s); - else if (!TCGV_EQUAL(d, s)) - tcg_gen_mov_tl(d, s); + if (size == 1) { + tcg_gen_ext8u_i32(d, s); + } else if (size == 2) { + tcg_gen_ext16u_i32(d, s); + } else if (!TCGV_EQUAL(d, s)) { + tcg_gen_mov_tl(d, s); + } } #if DISAS_CRIS static char memsize_char(int size) { - switch (size) - { - case 1: return 'b'; break; - case 2: return 'w'; break; - case 4: return 'd'; break; - default: - return 'x'; - break; - } + switch (size) { + case 1: return 'b'; break; + case 2: return 'w'; break; + case 4: return 'd'; break; + default: + return 'x'; + break; + } } #endif static inline unsigned int memsize_z(DisasContext *dc) { - return dc->zsize + 1; + return dc->zsize + 1; } static inline unsigned int memsize_zz(DisasContext *dc) { - switch (dc->zzsize) - { - case 0: return 1; - case 1: return 2; - default: - return 4; - } + switch (dc->zzsize) { + case 0: return 1; + case 1: return 2; + default: + return 4; + } } static inline void do_postinc (DisasContext *dc, int size) { - if (dc->postinc) - tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], size); + if (dc->postinc) { + tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], size); + } } static inline void dec_prep_move_r(DisasContext *dc, int rs, int rd, - int size, int s_ext, TCGv dst) + int size, int s_ext, TCGv dst) { - if (s_ext) - t_gen_sext(dst, cpu_R[rs], size); - else - t_gen_zext(dst, cpu_R[rs], size); + if (s_ext) { + t_gen_sext(dst, cpu_R[rs], size); + } else { + t_gen_zext(dst, cpu_R[rs], size); + } } /* Prepare T0 and T1 for a register alu operation. s_ext decides if the operand1 should be sign-extended or zero-extended when needed. */ static void dec_prep_alu_r(DisasContext *dc, int rs, int rd, - int size, int s_ext, TCGv dst, TCGv src) + int size, int s_ext, TCGv dst, TCGv src) { - dec_prep_move_r(dc, rs, rd, size, s_ext, src); + dec_prep_move_r(dc, rs, rd, size, s_ext, src); - if (s_ext) - t_gen_sext(dst, cpu_R[rd], size); - else - t_gen_zext(dst, cpu_R[rd], size); + if (s_ext) { + t_gen_sext(dst, cpu_R[rd], size); + } else { + t_gen_zext(dst, cpu_R[rd], size); + } } static int dec_prep_move_m(CPUCRISState *env, DisasContext *dc, int s_ext, int memsize, TCGv dst) { - unsigned int rs; - uint32_t imm; - int is_imm; - int insn_len = 2; - - rs = dc->op1; - is_imm = rs == 15 && dc->postinc; - - /* Load [$rs] onto T1. */ - if (is_imm) { - insn_len = 2 + memsize; - if (memsize == 1) - insn_len++; - - imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext); - tcg_gen_movi_tl(dst, imm); - dc->postinc = 0; - } else { - cris_flush_cc_state(dc); - gen_load(dc, dst, cpu_R[rs], memsize, 0); - if (s_ext) - t_gen_sext(dst, dst, memsize); - else - t_gen_zext(dst, dst, memsize); - } - return insn_len; + unsigned int rs; + uint32_t imm; + int is_imm; + int insn_len = 2; + + rs = dc->op1; + is_imm = rs == 15 && dc->postinc; + + /* Load [$rs] onto T1. */ + if (is_imm) { + insn_len = 2 + memsize; + if (memsize == 1) { + insn_len++; + } + + imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext); + tcg_gen_movi_tl(dst, imm); + dc->postinc = 0; + } else { + cris_flush_cc_state(dc); + gen_load(dc, dst, cpu_R[rs], memsize, 0); + if (s_ext) { + t_gen_sext(dst, dst, memsize); + } else { + t_gen_zext(dst, dst, memsize); + } + } + return insn_len; } /* Prepare T0 and T1 for a memory + alu operation. @@ -1341,22 +1363,22 @@ static int dec_prep_move_m(CPUCRISState *env, DisasContext *dc, static int dec_prep_alu_m(CPUCRISState *env, DisasContext *dc, int s_ext, int memsize, TCGv dst, TCGv src) { - int insn_len; + int insn_len; - insn_len = dec_prep_move_m(env, dc, s_ext, memsize, src); - tcg_gen_mov_tl(dst, cpu_R[dc->op2]); - return insn_len; + insn_len = dec_prep_move_m(env, dc, s_ext, memsize, src); + tcg_gen_mov_tl(dst, cpu_R[dc->op2]); + return insn_len; } #if DISAS_CRIS static const char *cc_name(int cc) { - static const char *cc_names[16] = { - "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", - "ls", "hi", "ge", "lt", "gt", "le", "a", "p" - }; - assert(cc < 16); - return cc_names[cc]; + static const char *cc_names[16] = { + "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", + "ls", "hi", "ge", "lt", "gt", "le", "a", "p" + }; + assert(cc < 16); + return cc_names[cc]; } #endif @@ -1364,1773 +1386,1781 @@ static const char *cc_name(int cc) static int dec_bccq(CPUCRISState *env, DisasContext *dc) { - int32_t offset; - int sign; - uint32_t cond = dc->op2; + int32_t offset; + int sign; + uint32_t cond = dc->op2; - offset = EXTRACT_FIELD (dc->ir, 1, 7); - sign = EXTRACT_FIELD(dc->ir, 0, 0); + offset = EXTRACT_FIELD(dc->ir, 1, 7); + sign = EXTRACT_FIELD(dc->ir, 0, 0); - offset *= 2; - offset |= sign << 8; - offset = sign_extend(offset, 8); + offset *= 2; + offset |= sign << 8; + offset = sign_extend(offset, 8); - LOG_DIS("b%s %x\n", cc_name(cond), dc->pc + offset); + LOG_DIS("b%s %x\n", cc_name(cond), dc->pc + offset); - /* op2 holds the condition-code. */ - cris_cc_mask(dc, 0); - cris_prepare_cc_branch (dc, offset, cond); - return 2; + /* op2 holds the condition-code. */ + cris_cc_mask(dc, 0); + cris_prepare_cc_branch(dc, offset, cond); + return 2; } static int dec_addoq(CPUCRISState *env, DisasContext *dc) { - int32_t imm; + int32_t imm; - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 7); - imm = sign_extend(dc->op1, 7); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 7); + imm = sign_extend(dc->op1, 7); - LOG_DIS("addoq %d, $r%u\n", imm, dc->op2); - cris_cc_mask(dc, 0); - /* Fetch register operand, */ - tcg_gen_addi_tl(cpu_R[R_ACR], cpu_R[dc->op2], imm); + LOG_DIS("addoq %d, $r%u\n", imm, dc->op2); + cris_cc_mask(dc, 0); + /* Fetch register operand, */ + tcg_gen_addi_tl(cpu_R[R_ACR], cpu_R[dc->op2], imm); - return 2; + return 2; } static int dec_addq(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("addq %u, $r%u\n", dc->op1, dc->op2); + LOG_DIS("addq %u, $r%u\n", dc->op1, dc->op2); - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); - cris_cc_mask(dc, CC_MASK_NZVC); + cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_ADD, - cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); - return 2; + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); + return 2; } static int dec_moveq(CPUCRISState *env, DisasContext *dc) { - uint32_t imm; + uint32_t imm; - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); - imm = sign_extend(dc->op1, 5); - LOG_DIS("moveq %d, $r%u\n", imm, dc->op2); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + imm = sign_extend(dc->op1, 5); + LOG_DIS("moveq %d, $r%u\n", imm, dc->op2); - tcg_gen_movi_tl(cpu_R[dc->op2], imm); - return 2; + tcg_gen_movi_tl(cpu_R[dc->op2], imm); + return 2; } static int dec_subq(CPUCRISState *env, DisasContext *dc) { - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); - LOG_DIS("subq %u, $r%u\n", dc->op1, dc->op2); + LOG_DIS("subq %u, $r%u\n", dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_SUB, - cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); - return 2; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_SUB, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); + return 2; } static int dec_cmpq(CPUCRISState *env, DisasContext *dc) { - uint32_t imm; - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); - imm = sign_extend(dc->op1, 5); + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + imm = sign_extend(dc->op1, 5); - LOG_DIS("cmpq %d, $r%d\n", imm, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); + LOG_DIS("cmpq %d, $r%d\n", imm, dc->op2); + cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_CMP, - cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); - return 2; + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); + return 2; } static int dec_andq(CPUCRISState *env, DisasContext *dc) { - uint32_t imm; - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); - imm = sign_extend(dc->op1, 5); + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + imm = sign_extend(dc->op1, 5); - LOG_DIS("andq %d, $r%d\n", imm, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); + LOG_DIS("andq %d, $r%d\n", imm, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_AND, - cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); - return 2; + cris_alu(dc, CC_OP_AND, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); + return 2; } static int dec_orq(CPUCRISState *env, DisasContext *dc) { - uint32_t imm; - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); - imm = sign_extend(dc->op1, 5); - LOG_DIS("orq %d, $r%d\n", imm, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + imm = sign_extend(dc->op1, 5); + LOG_DIS("orq %d, $r%d\n", imm, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_OR, - cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); - return 2; + cris_alu(dc, CC_OP_OR, + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); + return 2; } static int dec_btstq(CPUCRISState *env, DisasContext *dc) { - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); - LOG_DIS("btstq %u, $r%d\n", dc->op1, dc->op2); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + LOG_DIS("btstq %u, $r%d\n", dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_NZ); + cris_evaluate_flags(dc); gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->op2], - tcg_const_tl(dc->op1), cpu_PR[PR_CCS]); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4); - cris_update_cc_op(dc, CC_OP_FLAGS, 4); - dc->flags_uptodate = 1; - return 2; + tcg_const_tl(dc->op1), cpu_PR[PR_CCS]); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4); + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + dc->flags_uptodate = 1; + return 2; } static int dec_asrq(CPUCRISState *env, DisasContext *dc) { - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); - LOG_DIS("asrq %u, $r%d\n", dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + LOG_DIS("asrq %u, $r%d\n", dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); - tcg_gen_sari_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], - cpu_R[dc->op2], cpu_R[dc->op2], 4); - return 2; + tcg_gen_sari_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], + cpu_R[dc->op2], cpu_R[dc->op2], 4); + return 2; } static int dec_lslq(CPUCRISState *env, DisasContext *dc) { - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); - LOG_DIS("lslq %u, $r%d\n", dc->op1, dc->op2); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + LOG_DIS("lslq %u, $r%d\n", dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); + cris_cc_mask(dc, CC_MASK_NZ); - tcg_gen_shli_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); + tcg_gen_shli_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], - cpu_R[dc->op2], cpu_R[dc->op2], 4); - return 2; + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], + cpu_R[dc->op2], cpu_R[dc->op2], 4); + return 2; } static int dec_lsrq(CPUCRISState *env, DisasContext *dc) { - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); - LOG_DIS("lsrq %u, $r%d\n", dc->op1, dc->op2); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + LOG_DIS("lsrq %u, $r%d\n", dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); + cris_cc_mask(dc, CC_MASK_NZ); - tcg_gen_shri_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], - cpu_R[dc->op2], cpu_R[dc->op2], 4); - return 2; + tcg_gen_shri_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], + cpu_R[dc->op2], cpu_R[dc->op2], 4); + return 2; } static int dec_move_r(CPUCRISState *env, DisasContext *dc) { - int size = memsize_zz(dc); - - LOG_DIS("move.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - - cris_cc_mask(dc, CC_MASK_NZ); - if (size == 4) { - dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, cpu_R[dc->op2]); - cris_cc_mask(dc, CC_MASK_NZ); - cris_update_cc_op(dc, CC_OP_MOVE, 4); - cris_update_cc_x(dc); - cris_update_result(dc, cpu_R[dc->op2]); - } - else { - TCGv t0; - - t0 = tcg_temp_new(); - dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], - cpu_R[dc->op2], t0, size); - tcg_temp_free(t0); - } - return 2; + int size = memsize_zz(dc); + + LOG_DIS("move.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + + cris_cc_mask(dc, CC_MASK_NZ); + if (size == 4) { + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, cpu_R[dc->op2]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_update_cc_op(dc, CC_OP_MOVE, 4); + cris_update_cc_x(dc); + cris_update_result(dc, cpu_R[dc->op2]); + } else { + TCGv t0; + + t0 = tcg_temp_new(); + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], + cpu_R[dc->op2], t0, size); + tcg_temp_free(t0); + } + return 2; } static int dec_scc_r(CPUCRISState *env, DisasContext *dc) { - int cond = dc->op2; + int cond = dc->op2; - LOG_DIS("s%s $r%u\n", - cc_name(cond), dc->op1); + LOG_DIS("s%s $r%u\n", + cc_name(cond), dc->op1); - if (cond != CC_A) - { - int l1; + if (cond != CC_A) { + int l1; - gen_tst_cc (dc, cpu_R[dc->op1], cond); - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[dc->op1], 0, l1); - tcg_gen_movi_tl(cpu_R[dc->op1], 1); - gen_set_label(l1); - } - else - tcg_gen_movi_tl(cpu_R[dc->op1], 1); + gen_tst_cc(dc, cpu_R[dc->op1], cond); + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[dc->op1], 0, l1); + tcg_gen_movi_tl(cpu_R[dc->op1], 1); + gen_set_label(l1); + } else { + tcg_gen_movi_tl(cpu_R[dc->op1], 1); + } - cris_cc_mask(dc, 0); - return 2; + cris_cc_mask(dc, 0); + return 2; } static inline void cris_alu_alloc_temps(DisasContext *dc, int size, TCGv *t) { - if (size == 4) { - t[0] = cpu_R[dc->op2]; - t[1] = cpu_R[dc->op1]; - } else { - t[0] = tcg_temp_new(); - t[1] = tcg_temp_new(); - } + if (size == 4) { + t[0] = cpu_R[dc->op2]; + t[1] = cpu_R[dc->op1]; + } else { + t[0] = tcg_temp_new(); + t[1] = tcg_temp_new(); + } } static inline void cris_alu_free_temps(DisasContext *dc, int size, TCGv *t) { - if (size != 4) { - tcg_temp_free(t[0]); - tcg_temp_free(t[1]); - } + if (size != 4) { + tcg_temp_free(t[0]); + tcg_temp_free(t[1]); + } } static int dec_and_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); + TCGv t[2]; + int size = memsize_zz(dc); - LOG_DIS("and.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); + LOG_DIS("and.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); + cris_cc_mask(dc, CC_MASK_NZ); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_free_temps(dc, size, t); - return 2; + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_lz_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - LOG_DIS("lz $r%u, $r%u\n", - dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - t0 = tcg_temp_new(); - dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0, cpu_R[dc->op2], t0); - cris_alu(dc, CC_OP_LZ, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); - tcg_temp_free(t0); - return 2; + TCGv t0; + LOG_DIS("lz $r%u, $r%u\n", + dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); + t0 = tcg_temp_new(); + dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0, cpu_R[dc->op2], t0); + cris_alu(dc, CC_OP_LZ, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); + return 2; } static int dec_lsl_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); + TCGv t[2]; + int size = memsize_zz(dc); - LOG_DIS("lsl.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); + LOG_DIS("lsl.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - tcg_gen_andi_tl(t[1], t[1], 63); - cris_alu(dc, CC_OP_LSL, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_alloc_temps(dc, size, t); - return 2; + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + tcg_gen_andi_tl(t[1], t[1], 63); + cris_alu(dc, CC_OP_LSL, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_alloc_temps(dc, size, t); + return 2; } static int dec_lsr_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); + TCGv t[2]; + int size = memsize_zz(dc); - LOG_DIS("lsr.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); + LOG_DIS("lsr.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - tcg_gen_andi_tl(t[1], t[1], 63); - cris_alu(dc, CC_OP_LSR, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_free_temps(dc, size, t); - return 2; + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + tcg_gen_andi_tl(t[1], t[1], 63); + cris_alu(dc, CC_OP_LSR, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_asr_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); + TCGv t[2]; + int size = memsize_zz(dc); - LOG_DIS("asr.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); + LOG_DIS("asr.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]); - tcg_gen_andi_tl(t[1], t[1], 63); - cris_alu(dc, CC_OP_ASR, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_free_temps(dc, size, t); - return 2; + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]); + tcg_gen_andi_tl(t[1], t[1], 63); + cris_alu(dc, CC_OP_ASR, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_muls_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); + TCGv t[2]; + int size = memsize_zz(dc); - LOG_DIS("muls.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZV); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]); + LOG_DIS("muls.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZV); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]); - cris_alu(dc, CC_OP_MULS, cpu_R[dc->op2], t[0], t[1], 4); - cris_alu_free_temps(dc, size, t); - return 2; + cris_alu(dc, CC_OP_MULS, cpu_R[dc->op2], t[0], t[1], 4); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_mulu_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); + TCGv t[2]; + int size = memsize_zz(dc); - LOG_DIS("mulu.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZV); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + LOG_DIS("mulu.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZV); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - cris_alu(dc, CC_OP_MULU, cpu_R[dc->op2], t[0], t[1], 4); - cris_alu_alloc_temps(dc, size, t); - return 2; + cris_alu(dc, CC_OP_MULU, cpu_R[dc->op2], t[0], t[1], 4); + cris_alu_alloc_temps(dc, size, t); + return 2; } static int dec_dstep_r(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("dstep $r%u, $r%u\n", dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_DSTEP, - cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4); - return 2; + LOG_DIS("dstep $r%u, $r%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_DSTEP, + cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4); + return 2; } static int dec_xor_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); - LOG_DIS("xor.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - BUG_ON(size != 4); /* xor is dword. */ - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + TCGv t[2]; + int size = memsize_zz(dc); + LOG_DIS("xor.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + BUG_ON(size != 4); /* xor is dword. */ + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - cris_alu(dc, CC_OP_XOR, cpu_R[dc->op2], t[0], t[1], 4); - cris_alu_free_temps(dc, size, t); - return 2; + cris_alu(dc, CC_OP_XOR, cpu_R[dc->op2], t[0], t[1], 4); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_bound_r(CPUCRISState *env, DisasContext *dc) { - TCGv l0; - int size = memsize_zz(dc); - LOG_DIS("bound.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - l0 = tcg_temp_local_new(); - dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, l0); - cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], cpu_R[dc->op2], l0, 4); - tcg_temp_free(l0); - return 2; + TCGv l0; + int size = memsize_zz(dc); + LOG_DIS("bound.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); + l0 = tcg_temp_local_new(); + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, l0); + cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], cpu_R[dc->op2], l0, 4); + tcg_temp_free(l0); + return 2; } static int dec_cmp_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); - LOG_DIS("cmp.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + TCGv t[2]; + int size = memsize_zz(dc); + LOG_DIS("cmp.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_free_temps(dc, size, t); - return 2; + cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_abs_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; + TCGv t0; - LOG_DIS("abs $r%u, $r%u\n", - dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); + LOG_DIS("abs $r%u, $r%u\n", + dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); - t0 = tcg_temp_new(); - tcg_gen_sari_tl(t0, cpu_R[dc->op1], 31); - tcg_gen_xor_tl(cpu_R[dc->op2], cpu_R[dc->op1], t0); - tcg_gen_sub_tl(cpu_R[dc->op2], cpu_R[dc->op2], t0); - tcg_temp_free(t0); + t0 = tcg_temp_new(); + tcg_gen_sari_tl(t0, cpu_R[dc->op1], 31); + tcg_gen_xor_tl(cpu_R[dc->op2], cpu_R[dc->op1], t0); + tcg_gen_sub_tl(cpu_R[dc->op2], cpu_R[dc->op2], t0); + tcg_temp_free(t0); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4); - return 2; + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4); + return 2; } static int dec_add_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); - LOG_DIS("add.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + TCGv t[2]; + int size = memsize_zz(dc); + LOG_DIS("add.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_free_temps(dc, size, t); - return 2; + cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_addc_r(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("addc $r%u, $r%u\n", - dc->op1, dc->op2); - cris_evaluate_flags(dc); - /* Set for this insn. */ - dc->flagx_known = 1; - dc->flags_x = X_FLAG; + LOG_DIS("addc $r%u, $r%u\n", + dc->op1, dc->op2); + cris_evaluate_flags(dc); + /* Set for this insn. */ + dc->flagx_known = 1; + dc->flags_x = X_FLAG; - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_ADDC, - cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4); - return 2; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADDC, + cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4); + return 2; } static int dec_mcp_r(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("mcp $p%u, $r%u\n", - dc->op2, dc->op1); - cris_evaluate_flags(dc); - cris_cc_mask(dc, CC_MASK_RNZV); - cris_alu(dc, CC_OP_MCP, - cpu_R[dc->op1], cpu_R[dc->op1], cpu_PR[dc->op2], 4); - return 2; + LOG_DIS("mcp $p%u, $r%u\n", + dc->op2, dc->op1); + cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_RNZV); + cris_alu(dc, CC_OP_MCP, + cpu_R[dc->op1], cpu_R[dc->op1], cpu_PR[dc->op2], 4); + return 2; } #if DISAS_CRIS static char * swapmode_name(int mode, char *modename) { - int i = 0; - if (mode & 8) - modename[i++] = 'n'; - if (mode & 4) - modename[i++] = 'w'; - if (mode & 2) - modename[i++] = 'b'; - if (mode & 1) - modename[i++] = 'r'; - modename[i++] = 0; - return modename; + int i = 0; + if (mode & 8) { + modename[i++] = 'n'; + } + if (mode & 4) { + modename[i++] = 'w'; + } + if (mode & 2) { + modename[i++] = 'b'; + } + if (mode & 1) { + modename[i++] = 'r'; + } + modename[i++] = 0; + return modename; } #endif static int dec_swap_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; + TCGv t0; #if DISAS_CRIS - char modename[4]; + char modename[4]; #endif - LOG_DIS("swap%s $r%u\n", - swapmode_name(dc->op2, modename), dc->op1); - - cris_cc_mask(dc, CC_MASK_NZ); - t0 = tcg_temp_new(); - t_gen_mov_TN_reg(t0, dc->op1); - if (dc->op2 & 8) - tcg_gen_not_tl(t0, t0); - if (dc->op2 & 4) - t_gen_swapw(t0, t0); - if (dc->op2 & 2) - t_gen_swapb(t0, t0); - if (dc->op2 & 1) - t_gen_swapr(t0, t0); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op1], cpu_R[dc->op1], t0, 4); - tcg_temp_free(t0); - return 2; + LOG_DIS("swap%s $r%u\n", + swapmode_name(dc->op2, modename), dc->op1); + + cris_cc_mask(dc, CC_MASK_NZ); + t0 = tcg_temp_new(); + t_gen_mov_TN_reg(t0, dc->op1); + if (dc->op2 & 8) { + tcg_gen_not_tl(t0, t0); + } + if (dc->op2 & 4) { + t_gen_swapw(t0, t0); + } + if (dc->op2 & 2) { + t_gen_swapb(t0, t0); + } + if (dc->op2 & 1) { + t_gen_swapr(t0, t0); + } + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op1], cpu_R[dc->op1], t0, 4); + tcg_temp_free(t0); + return 2; } static int dec_or_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); - LOG_DIS("or.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - cris_alu(dc, CC_OP_OR, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_free_temps(dc, size, t); - return 2; + TCGv t[2]; + int size = memsize_zz(dc); + LOG_DIS("or.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + cris_alu(dc, CC_OP_OR, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_addi_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - LOG_DIS("addi.%c $r%u, $r%u\n", - memsize_char(memsize_zz(dc)), dc->op2, dc->op1); - cris_cc_mask(dc, 0); - t0 = tcg_temp_new(); - tcg_gen_shl_tl(t0, cpu_R[dc->op2], tcg_const_tl(dc->zzsize)); - tcg_gen_add_tl(cpu_R[dc->op1], cpu_R[dc->op1], t0); - tcg_temp_free(t0); - return 2; + TCGv t0; + LOG_DIS("addi.%c $r%u, $r%u\n", + memsize_char(memsize_zz(dc)), dc->op2, dc->op1); + cris_cc_mask(dc, 0); + t0 = tcg_temp_new(); + tcg_gen_shl_tl(t0, cpu_R[dc->op2], tcg_const_tl(dc->zzsize)); + tcg_gen_add_tl(cpu_R[dc->op1], cpu_R[dc->op1], t0); + tcg_temp_free(t0); + return 2; } static int dec_addi_acr(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - LOG_DIS("addi.%c $r%u, $r%u, $acr\n", - memsize_char(memsize_zz(dc)), dc->op2, dc->op1); - cris_cc_mask(dc, 0); - t0 = tcg_temp_new(); - tcg_gen_shl_tl(t0, cpu_R[dc->op2], tcg_const_tl(dc->zzsize)); - tcg_gen_add_tl(cpu_R[R_ACR], cpu_R[dc->op1], t0); - tcg_temp_free(t0); - return 2; + TCGv t0; + LOG_DIS("addi.%c $r%u, $r%u, $acr\n", + memsize_char(memsize_zz(dc)), dc->op2, dc->op1); + cris_cc_mask(dc, 0); + t0 = tcg_temp_new(); + tcg_gen_shl_tl(t0, cpu_R[dc->op2], tcg_const_tl(dc->zzsize)); + tcg_gen_add_tl(cpu_R[R_ACR], cpu_R[dc->op1], t0); + tcg_temp_free(t0); + return 2; } static int dec_neg_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); - LOG_DIS("neg.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + TCGv t[2]; + int size = memsize_zz(dc); + LOG_DIS("neg.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - cris_alu(dc, CC_OP_NEG, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_free_temps(dc, size, t); - return 2; + cris_alu(dc, CC_OP_NEG, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); + return 2; } static int dec_btst_r(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("btst $r%u, $r%u\n", - dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - cris_evaluate_flags(dc); + LOG_DIS("btst $r%u, $r%u\n", + dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); + cris_evaluate_flags(dc); gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->op2], - cpu_R[dc->op1], cpu_PR[PR_CCS]); - cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], - cpu_R[dc->op2], cpu_R[dc->op2], 4); - cris_update_cc_op(dc, CC_OP_FLAGS, 4); - dc->flags_uptodate = 1; - return 2; + cpu_R[dc->op1], cpu_PR[PR_CCS]); + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], + cpu_R[dc->op2], cpu_R[dc->op2], 4); + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + dc->flags_uptodate = 1; + return 2; } static int dec_sub_r(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int size = memsize_zz(dc); - LOG_DIS("sub.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu_alloc_temps(dc, size, t); - dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); - cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], size); - cris_alu_free_temps(dc, size, t); - return 2; + TCGv t[2]; + int size = memsize_zz(dc); + LOG_DIS("sub.%c $r%u, $r%u\n", + memsize_char(size), dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu_alloc_temps(dc, size, t); + dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], size); + cris_alu_free_temps(dc, size, t); + return 2; } /* Zero extension. From size to dword. */ static int dec_movu_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - int size = memsize_z(dc); - LOG_DIS("movu.%c $r%u, $r%u\n", - memsize_char(size), - dc->op1, dc->op2); + TCGv t0; + int size = memsize_z(dc); + LOG_DIS("movu.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - t0 = tcg_temp_new(); - dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0); - cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); - tcg_temp_free(t0); - return 2; + cris_cc_mask(dc, CC_MASK_NZ); + t0 = tcg_temp_new(); + dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0); + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); + return 2; } /* Sign extension. From size to dword. */ static int dec_movs_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - int size = memsize_z(dc); - LOG_DIS("movs.%c $r%u, $r%u\n", - memsize_char(size), - dc->op1, dc->op2); + TCGv t0; + int size = memsize_z(dc); + LOG_DIS("movs.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZ); - t0 = tcg_temp_new(); - /* Size can only be qi or hi. */ - t_gen_sext(t0, cpu_R[dc->op1], size); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], cpu_R[dc->op1], t0, 4); - tcg_temp_free(t0); - return 2; + cris_cc_mask(dc, CC_MASK_NZ); + t0 = tcg_temp_new(); + /* Size can only be qi or hi. */ + t_gen_sext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op1], t0, 4); + tcg_temp_free(t0); + return 2; } /* zero extension. From size to dword. */ static int dec_addu_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - int size = memsize_z(dc); - LOG_DIS("addu.%c $r%u, $r%u\n", - memsize_char(size), - dc->op1, dc->op2); + TCGv t0; + int size = memsize_z(dc); + LOG_DIS("addu.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - t0 = tcg_temp_new(); - /* Size can only be qi or hi. */ - t_gen_zext(t0, cpu_R[dc->op1], size); - cris_alu(dc, CC_OP_ADD, - cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); - tcg_temp_free(t0); - return 2; + cris_cc_mask(dc, CC_MASK_NZVC); + t0 = tcg_temp_new(); + /* Size can only be qi or hi. */ + t_gen_zext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); + return 2; } /* Sign extension. From size to dword. */ static int dec_adds_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - int size = memsize_z(dc); - LOG_DIS("adds.%c $r%u, $r%u\n", - memsize_char(size), - dc->op1, dc->op2); + TCGv t0; + int size = memsize_z(dc); + LOG_DIS("adds.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - t0 = tcg_temp_new(); - /* Size can only be qi or hi. */ - t_gen_sext(t0, cpu_R[dc->op1], size); - cris_alu(dc, CC_OP_ADD, - cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); - tcg_temp_free(t0); - return 2; + cris_cc_mask(dc, CC_MASK_NZVC); + t0 = tcg_temp_new(); + /* Size can only be qi or hi. */ + t_gen_sext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); + return 2; } /* Zero extension. From size to dword. */ static int dec_subu_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - int size = memsize_z(dc); - LOG_DIS("subu.%c $r%u, $r%u\n", - memsize_char(size), - dc->op1, dc->op2); + TCGv t0; + int size = memsize_z(dc); + LOG_DIS("subu.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - t0 = tcg_temp_new(); - /* Size can only be qi or hi. */ - t_gen_zext(t0, cpu_R[dc->op1], size); - cris_alu(dc, CC_OP_SUB, - cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); - tcg_temp_free(t0); - return 2; + cris_cc_mask(dc, CC_MASK_NZVC); + t0 = tcg_temp_new(); + /* Size can only be qi or hi. */ + t_gen_zext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_SUB, + cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); + return 2; } /* Sign extension. From size to dword. */ static int dec_subs_r(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - int size = memsize_z(dc); - LOG_DIS("subs.%c $r%u, $r%u\n", - memsize_char(size), - dc->op1, dc->op2); + TCGv t0; + int size = memsize_z(dc); + LOG_DIS("subs.%c $r%u, $r%u\n", + memsize_char(size), + dc->op1, dc->op2); - cris_cc_mask(dc, CC_MASK_NZVC); - t0 = tcg_temp_new(); - /* Size can only be qi or hi. */ - t_gen_sext(t0, cpu_R[dc->op1], size); - cris_alu(dc, CC_OP_SUB, - cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); - tcg_temp_free(t0); - return 2; + cris_cc_mask(dc, CC_MASK_NZVC); + t0 = tcg_temp_new(); + /* Size can only be qi or hi. */ + t_gen_sext(t0, cpu_R[dc->op1], size); + cris_alu(dc, CC_OP_SUB, + cpu_R[dc->op2], cpu_R[dc->op2], t0, 4); + tcg_temp_free(t0); + return 2; } static int dec_setclrf(CPUCRISState *env, DisasContext *dc) { - uint32_t flags; - int set = (~dc->opcode >> 2) & 1; - - - flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4) - | EXTRACT_FIELD(dc->ir, 0, 3); - if (set && flags == 0) { - LOG_DIS("nop\n"); - return 2; - } else if (!set && (flags & 0x20)) { - LOG_DIS("di\n"); - } - else { - LOG_DIS("%sf %x\n", - set ? "set" : "clr", - flags); - } - - /* User space is not allowed to touch these. Silently ignore. */ - if (dc->tb_flags & U_FLAG) { - flags &= ~(S_FLAG | I_FLAG | U_FLAG); - } - - if (flags & X_FLAG) { - dc->flagx_known = 1; - if (set) - dc->flags_x = X_FLAG; - else - dc->flags_x = 0; - } - - /* Break the TB if any of the SPI flag changes. */ - if (flags & (P_FLAG | S_FLAG)) { - tcg_gen_movi_tl(env_pc, dc->pc + 2); - dc->is_jmp = DISAS_UPDATE; - dc->cpustate_changed = 1; - } - - /* For the I flag, only act on posedge. */ - if ((flags & I_FLAG)) { - tcg_gen_movi_tl(env_pc, dc->pc + 2); - dc->is_jmp = DISAS_UPDATE; - dc->cpustate_changed = 1; - } - - - /* Simply decode the flags. */ - cris_evaluate_flags (dc); - cris_update_cc_op(dc, CC_OP_FLAGS, 4); - cris_update_cc_x(dc); - tcg_gen_movi_tl(cc_op, dc->cc_op); - - if (set) { - if (!(dc->tb_flags & U_FLAG) && (flags & U_FLAG)) { - /* Enter user mode. */ - t_gen_mov_env_TN(ksp, cpu_R[R_SP]); - tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]); - dc->cpustate_changed = 1; - } - tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags); - } - else - tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags); - - dc->flags_uptodate = 1; - dc->clear_x = 0; - return 2; + uint32_t flags; + int set = (~dc->opcode >> 2) & 1; + + + flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4) + | EXTRACT_FIELD(dc->ir, 0, 3); + if (set && flags == 0) { + LOG_DIS("nop\n"); + return 2; + } else if (!set && (flags & 0x20)) { + LOG_DIS("di\n"); + } else { + LOG_DIS("%sf %x\n", set ? "set" : "clr", flags); + } + + /* User space is not allowed to touch these. Silently ignore. */ + if (dc->tb_flags & U_FLAG) { + flags &= ~(S_FLAG | I_FLAG | U_FLAG); + } + + if (flags & X_FLAG) { + dc->flagx_known = 1; + if (set) { + dc->flags_x = X_FLAG; + } else { + dc->flags_x = 0; + } + } + + /* Break the TB if any of the SPI flag changes. */ + if (flags & (P_FLAG | S_FLAG)) { + tcg_gen_movi_tl(env_pc, dc->pc + 2); + dc->is_jmp = DISAS_UPDATE; + dc->cpustate_changed = 1; + } + + /* For the I flag, only act on posedge. */ + if ((flags & I_FLAG)) { + tcg_gen_movi_tl(env_pc, dc->pc + 2); + dc->is_jmp = DISAS_UPDATE; + dc->cpustate_changed = 1; + } + + + /* Simply decode the flags. */ + cris_evaluate_flags(dc); + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + cris_update_cc_x(dc); + tcg_gen_movi_tl(cc_op, dc->cc_op); + + if (set) { + if (!(dc->tb_flags & U_FLAG) && (flags & U_FLAG)) { + /* Enter user mode. */ + t_gen_mov_env_TN(ksp, cpu_R[R_SP]); + tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]); + dc->cpustate_changed = 1; + } + tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags); + } else { + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags); + } + + dc->flags_uptodate = 1; + dc->clear_x = 0; + return 2; } static int dec_move_rs(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("move $r%u, $s%u\n", dc->op1, dc->op2); - cris_cc_mask(dc, 0); + LOG_DIS("move $r%u, $s%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, 0); gen_helper_movl_sreg_reg(cpu_env, tcg_const_tl(dc->op2), tcg_const_tl(dc->op1)); - return 2; + return 2; } static int dec_move_sr(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("move $s%u, $r%u\n", dc->op2, dc->op1); - cris_cc_mask(dc, 0); + LOG_DIS("move $s%u, $r%u\n", dc->op2, dc->op1); + cris_cc_mask(dc, 0); gen_helper_movl_reg_sreg(cpu_env, tcg_const_tl(dc->op1), tcg_const_tl(dc->op2)); - return 2; + return 2; } static int dec_move_rp(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - LOG_DIS("move $r%u, $p%u\n", dc->op1, dc->op2); - cris_cc_mask(dc, 0); - - t[0] = tcg_temp_new(); - if (dc->op2 == PR_CCS) { - cris_evaluate_flags(dc); - t_gen_mov_TN_reg(t[0], dc->op1); - if (dc->tb_flags & U_FLAG) { - t[1] = tcg_temp_new(); - /* User space is not allowed to touch all flags. */ - tcg_gen_andi_tl(t[0], t[0], 0x39f); - tcg_gen_andi_tl(t[1], cpu_PR[PR_CCS], ~0x39f); - tcg_gen_or_tl(t[0], t[1], t[0]); - tcg_temp_free(t[1]); - } - } - else - t_gen_mov_TN_reg(t[0], dc->op1); - - t_gen_mov_preg_TN(dc, dc->op2, t[0]); - if (dc->op2 == PR_CCS) { - cris_update_cc_op(dc, CC_OP_FLAGS, 4); - dc->flags_uptodate = 1; - } - tcg_temp_free(t[0]); - return 2; + TCGv t[2]; + LOG_DIS("move $r%u, $p%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, 0); + + t[0] = tcg_temp_new(); + if (dc->op2 == PR_CCS) { + cris_evaluate_flags(dc); + t_gen_mov_TN_reg(t[0], dc->op1); + if (dc->tb_flags & U_FLAG) { + t[1] = tcg_temp_new(); + /* User space is not allowed to touch all flags. */ + tcg_gen_andi_tl(t[0], t[0], 0x39f); + tcg_gen_andi_tl(t[1], cpu_PR[PR_CCS], ~0x39f); + tcg_gen_or_tl(t[0], t[1], t[0]); + tcg_temp_free(t[1]); + } + } else { + t_gen_mov_TN_reg(t[0], dc->op1); + } + + t_gen_mov_preg_TN(dc, dc->op2, t[0]); + if (dc->op2 == PR_CCS) { + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + dc->flags_uptodate = 1; + } + tcg_temp_free(t[0]); + return 2; } static int dec_move_pr(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - LOG_DIS("move $p%u, $r%u\n", dc->op2, dc->op1); - cris_cc_mask(dc, 0); + TCGv t0; + LOG_DIS("move $p%u, $r%u\n", dc->op2, dc->op1); + cris_cc_mask(dc, 0); - if (dc->op2 == PR_CCS) - cris_evaluate_flags(dc); + if (dc->op2 == PR_CCS) { + cris_evaluate_flags(dc); + } - if (dc->op2 == PR_DZ) { - tcg_gen_movi_tl(cpu_R[dc->op1], 0); - } else { - t0 = tcg_temp_new(); - t_gen_mov_TN_preg(t0, dc->op2); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op1], cpu_R[dc->op1], t0, - preg_sizes[dc->op2]); - tcg_temp_free(t0); - } - return 2; + if (dc->op2 == PR_DZ) { + tcg_gen_movi_tl(cpu_R[dc->op1], 0); + } else { + t0 = tcg_temp_new(); + t_gen_mov_TN_preg(t0, dc->op2); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op1], cpu_R[dc->op1], t0, + preg_sizes[dc->op2]); + tcg_temp_free(t0); + } + return 2; } static int dec_move_mr(CPUCRISState *env, DisasContext *dc) { - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("move.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); - - if (memsize == 4) { - insn_len = dec_prep_move_m(env, dc, 0, 4, cpu_R[dc->op2]); - cris_cc_mask(dc, CC_MASK_NZ); - cris_update_cc_op(dc, CC_OP_MOVE, 4); - cris_update_cc_x(dc); - cris_update_result(dc, cpu_R[dc->op2]); - } - else { - TCGv t0; - - t0 = tcg_temp_new(); - insn_len = dec_prep_move_m(env, dc, 0, memsize, t0); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], cpu_R[dc->op2], t0, memsize); - tcg_temp_free(t0); - } - do_postinc(dc, memsize); - return insn_len; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("move.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); + + if (memsize == 4) { + insn_len = dec_prep_move_m(env, dc, 0, 4, cpu_R[dc->op2]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_update_cc_op(dc, CC_OP_MOVE, 4); + cris_update_cc_x(dc); + cris_update_result(dc, cpu_R[dc->op2]); + } else { + TCGv t0; + + t0 = tcg_temp_new(); + insn_len = dec_prep_move_m(env, dc, 0, memsize, t0); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], t0, memsize); + tcg_temp_free(t0); + } + do_postinc(dc, memsize); + return insn_len; } static inline void cris_alu_m_alloc_temps(TCGv *t) { - t[0] = tcg_temp_new(); - t[1] = tcg_temp_new(); + t[0] = tcg_temp_new(); + t[1] = tcg_temp_new(); } static inline void cris_alu_m_free_temps(TCGv *t) { - tcg_temp_free(t[0]); - tcg_temp_free(t[1]); + tcg_temp_free(t[0]); + tcg_temp_free(t[1]); } static int dec_movs_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_z(dc); - int insn_len; - LOG_DIS("movs.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_z(dc); + int insn_len; + LOG_DIS("movs.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); - /* sign extend. */ + cris_alu_m_alloc_temps(t); + /* sign extend. */ insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_MOVE, - cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_addu_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_z(dc); - int insn_len; - LOG_DIS("addu.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_z(dc); + int insn_len; + LOG_DIS("addu.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); - /* sign extend. */ + cris_alu_m_alloc_temps(t); + /* sign extend. */ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_ADD, - cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_adds_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_z(dc); - int insn_len; - LOG_DIS("adds.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_z(dc); + int insn_len; + LOG_DIS("adds.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); - /* sign extend. */ + cris_alu_m_alloc_temps(t); + /* sign extend. */ insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_subu_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_z(dc); - int insn_len; - LOG_DIS("subu.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_z(dc); + int insn_len; + LOG_DIS("subu.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); - /* sign extend. */ + cris_alu_m_alloc_temps(t); + /* sign extend. */ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_subs_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_z(dc); - int insn_len; - LOG_DIS("subs.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_z(dc); + int insn_len; + LOG_DIS("subs.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); - /* sign extend. */ + cris_alu_m_alloc_temps(t); + /* sign extend. */ insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_movu_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_z(dc); - int insn_len; + TCGv t[2]; + int memsize = memsize_z(dc); + int insn_len; - LOG_DIS("movu.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + LOG_DIS("movu.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_cmpu_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_z(dc); - int insn_len; - LOG_DIS("cmpu.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_z(dc); + int insn_len; + LOG_DIS("cmpu.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_cmps_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_z(dc); - int insn_len; - LOG_DIS("cmps.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_z(dc); + int insn_len; + LOG_DIS("cmps.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_CMP, - cpu_R[dc->op2], cpu_R[dc->op2], t[1], - memsize_zz(dc)); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], + memsize_zz(dc)); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_cmp_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("cmp.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("cmp.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_CMP, - cpu_R[dc->op2], cpu_R[dc->op2], t[1], - memsize_zz(dc)); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], + memsize_zz(dc)); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_test_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("test.%c [$r%u%s] op2=%x\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("test.%c [$r%u%s] op2=%x\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_evaluate_flags(dc); + cris_evaluate_flags(dc); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZ); - tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3); + cris_cc_mask(dc, CC_MASK_NZ); + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3); - cris_alu(dc, CC_OP_CMP, - cpu_R[dc->op2], t[1], tcg_const_tl(0), memsize_zz(dc)); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], t[1], tcg_const_tl(0), memsize_zz(dc)); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_and_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("and.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("and.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_add_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("add.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("add.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_ADD, - cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_addo_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("add.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("add.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); - cris_cc_mask(dc, 0); - cris_alu(dc, CC_OP_ADD, cpu_R[R_ACR], t[0], t[1], 4); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, 0); + cris_alu(dc, CC_OP_ADD, cpu_R[R_ACR], t[0], t[1], 4); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_bound_m(CPUCRISState *env, DisasContext *dc) { - TCGv l[2]; - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("bound.%c [$r%u%s, $r%u\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv l[2]; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("bound.%c [$r%u%s, $r%u\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - l[0] = tcg_temp_local_new(); - l[1] = tcg_temp_local_new(); + l[0] = tcg_temp_local_new(); + l[1] = tcg_temp_local_new(); insn_len = dec_prep_alu_m(env, dc, 0, memsize, l[0], l[1]); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], l[0], l[1], 4); - do_postinc(dc, memsize); - tcg_temp_free(l[0]); - tcg_temp_free(l[1]); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], l[0], l[1], 4); + do_postinc(dc, memsize); + tcg_temp_free(l[0]); + tcg_temp_free(l[1]); + return insn_len; } static int dec_addc_mr(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int insn_len = 2; - LOG_DIS("addc [$r%u%s, $r%u\n", - dc->op1, dc->postinc ? "+]" : "]", - dc->op2); + TCGv t[2]; + int insn_len = 2; + LOG_DIS("addc [$r%u%s, $r%u\n", + dc->op1, dc->postinc ? "+]" : "]", + dc->op2); - cris_evaluate_flags(dc); + cris_evaluate_flags(dc); - /* Set for this insn. */ - dc->flagx_known = 1; - dc->flags_x = X_FLAG; + /* Set for this insn. */ + dc->flagx_known = 1; + dc->flags_x = X_FLAG; - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, 4, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_ADDC, cpu_R[dc->op2], t[0], t[1], 4); - do_postinc(dc, 4); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADDC, cpu_R[dc->op2], t[0], t[1], 4); + do_postinc(dc, 4); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_sub_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("sub.%c [$r%u%s, $r%u ir=%x zz=%x\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2, dc->ir, dc->zzsize); + TCGv t[2]; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("sub.%c [$r%u%s, $r%u ir=%x zz=%x\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2, dc->ir, dc->zzsize); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZVC); - cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], memsize); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], memsize); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_or_m(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_zz(dc); - int insn_len; - LOG_DIS("or.%c [$r%u%s, $r%u pc=%x\n", - memsize_char(memsize), - dc->op1, dc->postinc ? "+]" : "]", - dc->op2, dc->pc); + TCGv t[2]; + int memsize = memsize_zz(dc); + int insn_len; + LOG_DIS("or.%c [$r%u%s, $r%u pc=%x\n", + memsize_char(memsize), + dc->op1, dc->postinc ? "+]" : "]", + dc->op2, dc->pc); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, CC_MASK_NZ); - cris_alu(dc, CC_OP_OR, - cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_OR, + cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_move_mp(CPUCRISState *env, DisasContext *dc) { - TCGv t[2]; - int memsize = memsize_zz(dc); - int insn_len = 2; + TCGv t[2]; + int memsize = memsize_zz(dc); + int insn_len = 2; - LOG_DIS("move.%c [$r%u%s, $p%u\n", - memsize_char(memsize), - dc->op1, - dc->postinc ? "+]" : "]", - dc->op2); + LOG_DIS("move.%c [$r%u%s, $p%u\n", + memsize_char(memsize), + dc->op1, + dc->postinc ? "+]" : "]", + dc->op2); - cris_alu_m_alloc_temps(t); + cris_alu_m_alloc_temps(t); insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); - cris_cc_mask(dc, 0); - if (dc->op2 == PR_CCS) { - cris_evaluate_flags(dc); - if (dc->tb_flags & U_FLAG) { - /* User space is not allowed to touch all flags. */ - tcg_gen_andi_tl(t[1], t[1], 0x39f); - tcg_gen_andi_tl(t[0], cpu_PR[PR_CCS], ~0x39f); - tcg_gen_or_tl(t[1], t[0], t[1]); - } - } + cris_cc_mask(dc, 0); + if (dc->op2 == PR_CCS) { + cris_evaluate_flags(dc); + if (dc->tb_flags & U_FLAG) { + /* User space is not allowed to touch all flags. */ + tcg_gen_andi_tl(t[1], t[1], 0x39f); + tcg_gen_andi_tl(t[0], cpu_PR[PR_CCS], ~0x39f); + tcg_gen_or_tl(t[1], t[0], t[1]); + } + } - t_gen_mov_preg_TN(dc, dc->op2, t[1]); + t_gen_mov_preg_TN(dc, dc->op2, t[1]); - do_postinc(dc, memsize); - cris_alu_m_free_temps(t); - return insn_len; + do_postinc(dc, memsize); + cris_alu_m_free_temps(t); + return insn_len; } static int dec_move_pm(CPUCRISState *env, DisasContext *dc) { - TCGv t0; - int memsize; + TCGv t0; + int memsize; - memsize = preg_sizes[dc->op2]; + memsize = preg_sizes[dc->op2]; - LOG_DIS("move.%c $p%u, [$r%u%s\n", - memsize_char(memsize), - dc->op2, dc->op1, dc->postinc ? "+]" : "]"); + LOG_DIS("move.%c $p%u, [$r%u%s\n", + memsize_char(memsize), + dc->op2, dc->op1, dc->postinc ? "+]" : "]"); - /* prepare store. Address in T0, value in T1. */ - if (dc->op2 == PR_CCS) - cris_evaluate_flags(dc); - t0 = tcg_temp_new(); - t_gen_mov_TN_preg(t0, dc->op2); - cris_flush_cc_state(dc); - gen_store(dc, cpu_R[dc->op1], t0, memsize); - tcg_temp_free(t0); - - cris_cc_mask(dc, 0); - if (dc->postinc) - tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize); - return 2; + /* prepare store. Address in T0, value in T1. */ + if (dc->op2 == PR_CCS) { + cris_evaluate_flags(dc); + } + t0 = tcg_temp_new(); + t_gen_mov_TN_preg(t0, dc->op2); + cris_flush_cc_state(dc); + gen_store(dc, cpu_R[dc->op1], t0, memsize); + tcg_temp_free(t0); + + cris_cc_mask(dc, 0); + if (dc->postinc) { + tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize); + } + return 2; } static int dec_movem_mr(CPUCRISState *env, DisasContext *dc) { - TCGv_i64 tmp[16]; - TCGv tmp32; - TCGv addr; - int i; - int nr = dc->op2 + 1; - - LOG_DIS("movem [$r%u%s, $r%u\n", dc->op1, - dc->postinc ? "+]" : "]", dc->op2); - - addr = tcg_temp_new(); - /* There are probably better ways of doing this. */ - cris_flush_cc_state(dc); - for (i = 0; i < (nr >> 1); i++) { - tmp[i] = tcg_temp_new_i64(); - tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8); - gen_load64(dc, tmp[i], addr); - } - if (nr & 1) { - tmp32 = tcg_temp_new_i32(); - tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8); - gen_load(dc, tmp32, addr, 4, 0); - } else - TCGV_UNUSED(tmp32); - tcg_temp_free(addr); - - for (i = 0; i < (nr >> 1); i++) { - tcg_gen_trunc_i64_i32(cpu_R[i * 2], tmp[i]); - tcg_gen_shri_i64(tmp[i], tmp[i], 32); - tcg_gen_trunc_i64_i32(cpu_R[i * 2 + 1], tmp[i]); - tcg_temp_free_i64(tmp[i]); - } - if (nr & 1) { - tcg_gen_mov_tl(cpu_R[dc->op2], tmp32); - tcg_temp_free(tmp32); - } - - /* writeback the updated pointer value. */ - if (dc->postinc) - tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], nr * 4); - - /* gen_load might want to evaluate the previous insns flags. */ - cris_cc_mask(dc, 0); - return 2; + TCGv_i64 tmp[16]; + TCGv tmp32; + TCGv addr; + int i; + int nr = dc->op2 + 1; + + LOG_DIS("movem [$r%u%s, $r%u\n", dc->op1, + dc->postinc ? "+]" : "]", dc->op2); + + addr = tcg_temp_new(); + /* There are probably better ways of doing this. */ + cris_flush_cc_state(dc); + for (i = 0; i < (nr >> 1); i++) { + tmp[i] = tcg_temp_new_i64(); + tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8); + gen_load64(dc, tmp[i], addr); + } + if (nr & 1) { + tmp32 = tcg_temp_new_i32(); + tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8); + gen_load(dc, tmp32, addr, 4, 0); + } else { + TCGV_UNUSED(tmp32); + } + tcg_temp_free(addr); + + for (i = 0; i < (nr >> 1); i++) { + tcg_gen_trunc_i64_i32(cpu_R[i * 2], tmp[i]); + tcg_gen_shri_i64(tmp[i], tmp[i], 32); + tcg_gen_trunc_i64_i32(cpu_R[i * 2 + 1], tmp[i]); + tcg_temp_free_i64(tmp[i]); + } + if (nr & 1) { + tcg_gen_mov_tl(cpu_R[dc->op2], tmp32); + tcg_temp_free(tmp32); + } + + /* writeback the updated pointer value. */ + if (dc->postinc) { + tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], nr * 4); + } + + /* gen_load might want to evaluate the previous insns flags. */ + cris_cc_mask(dc, 0); + return 2; } static int dec_movem_rm(CPUCRISState *env, DisasContext *dc) { - TCGv tmp; - TCGv addr; - int i; - - LOG_DIS("movem $r%u, [$r%u%s\n", dc->op2, dc->op1, - dc->postinc ? "+]" : "]"); - - cris_flush_cc_state(dc); - - tmp = tcg_temp_new(); - addr = tcg_temp_new(); - tcg_gen_movi_tl(tmp, 4); - tcg_gen_mov_tl(addr, cpu_R[dc->op1]); - for (i = 0; i <= dc->op2; i++) { - /* Displace addr. */ - /* Perform the store. */ - gen_store(dc, addr, cpu_R[i], 4); - tcg_gen_add_tl(addr, addr, tmp); - } - if (dc->postinc) - tcg_gen_mov_tl(cpu_R[dc->op1], addr); - cris_cc_mask(dc, 0); - tcg_temp_free(tmp); - tcg_temp_free(addr); - return 2; + TCGv tmp; + TCGv addr; + int i; + + LOG_DIS("movem $r%u, [$r%u%s\n", dc->op2, dc->op1, + dc->postinc ? "+]" : "]"); + + cris_flush_cc_state(dc); + + tmp = tcg_temp_new(); + addr = tcg_temp_new(); + tcg_gen_movi_tl(tmp, 4); + tcg_gen_mov_tl(addr, cpu_R[dc->op1]); + for (i = 0; i <= dc->op2; i++) { + /* Displace addr. */ + /* Perform the store. */ + gen_store(dc, addr, cpu_R[i], 4); + tcg_gen_add_tl(addr, addr, tmp); + } + if (dc->postinc) { + tcg_gen_mov_tl(cpu_R[dc->op1], addr); + } + cris_cc_mask(dc, 0); + tcg_temp_free(tmp); + tcg_temp_free(addr); + return 2; } static int dec_move_rm(CPUCRISState *env, DisasContext *dc) { - int memsize; + int memsize; - memsize = memsize_zz(dc); + memsize = memsize_zz(dc); - LOG_DIS("move.%c $r%u, [$r%u]\n", - memsize_char(memsize), dc->op2, dc->op1); + LOG_DIS("move.%c $r%u, [$r%u]\n", + memsize_char(memsize), dc->op2, dc->op1); - /* prepare store. */ - cris_flush_cc_state(dc); - gen_store(dc, cpu_R[dc->op1], cpu_R[dc->op2], memsize); + /* prepare store. */ + cris_flush_cc_state(dc); + gen_store(dc, cpu_R[dc->op1], cpu_R[dc->op2], memsize); - if (dc->postinc) - tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize); - cris_cc_mask(dc, 0); - return 2; + if (dc->postinc) { + tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize); + } + cris_cc_mask(dc, 0); + return 2; } static int dec_lapcq(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("lapcq %x, $r%u\n", - dc->pc + dc->op1*2, dc->op2); - cris_cc_mask(dc, 0); - tcg_gen_movi_tl(cpu_R[dc->op2], dc->pc + dc->op1 * 2); - return 2; + LOG_DIS("lapcq %x, $r%u\n", + dc->pc + dc->op1*2, dc->op2); + cris_cc_mask(dc, 0); + tcg_gen_movi_tl(cpu_R[dc->op2], dc->pc + dc->op1 * 2); + return 2; } static int dec_lapc_im(CPUCRISState *env, DisasContext *dc) { - unsigned int rd; - int32_t imm; - int32_t pc; + unsigned int rd; + int32_t imm; + int32_t pc; - rd = dc->op2; + rd = dc->op2; - cris_cc_mask(dc, 0); - imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); - LOG_DIS("lapc 0x%x, $r%u\n", imm + dc->pc, dc->op2); + cris_cc_mask(dc, 0); + imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + LOG_DIS("lapc 0x%x, $r%u\n", imm + dc->pc, dc->op2); - pc = dc->pc; - pc += imm; - tcg_gen_movi_tl(cpu_R[rd], pc); - return 6; + pc = dc->pc; + pc += imm; + tcg_gen_movi_tl(cpu_R[rd], pc); + return 6; } /* Jump to special reg. */ static int dec_jump_p(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("jump $p%u\n", dc->op2); + LOG_DIS("jump $p%u\n", dc->op2); - if (dc->op2 == PR_CCS) - cris_evaluate_flags(dc); - t_gen_mov_TN_preg(env_btarget, dc->op2); - /* rete will often have low bit set to indicate delayslot. */ - tcg_gen_andi_tl(env_btarget, env_btarget, ~1); - cris_cc_mask(dc, 0); - cris_prepare_jmp(dc, JMP_INDIRECT); - return 2; + if (dc->op2 == PR_CCS) { + cris_evaluate_flags(dc); + } + t_gen_mov_TN_preg(env_btarget, dc->op2); + /* rete will often have low bit set to indicate delayslot. */ + tcg_gen_andi_tl(env_btarget, env_btarget, ~1); + cris_cc_mask(dc, 0); + cris_prepare_jmp(dc, JMP_INDIRECT); + return 2; } /* Jump and save. */ static int dec_jas_r(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("jas $r%u, $p%u\n", dc->op1, dc->op2); - cris_cc_mask(dc, 0); - /* Store the return address in Pd. */ - tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]); - if (dc->op2 > 15) - abort(); - t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4)); + LOG_DIS("jas $r%u, $p%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, 0); + /* Store the return address in Pd. */ + tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]); + if (dc->op2 > 15) { + abort(); + } + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4)); - cris_prepare_jmp(dc, JMP_INDIRECT); - return 2; + cris_prepare_jmp(dc, JMP_INDIRECT); + return 2; } static int dec_jas_im(CPUCRISState *env, DisasContext *dc) { - uint32_t imm; + uint32_t imm; - imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); - LOG_DIS("jas 0x%x\n", imm); - cris_cc_mask(dc, 0); - /* Store the return address in Pd. */ - t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8)); + LOG_DIS("jas 0x%x\n", imm); + cris_cc_mask(dc, 0); + /* Store the return address in Pd. */ + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8)); - dc->jmp_pc = imm; - cris_prepare_jmp(dc, JMP_DIRECT); - return 6; + dc->jmp_pc = imm; + cris_prepare_jmp(dc, JMP_DIRECT); + return 6; } static int dec_jasc_im(CPUCRISState *env, DisasContext *dc) { - uint32_t imm; + uint32_t imm; - imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); - LOG_DIS("jasc 0x%x\n", imm); - cris_cc_mask(dc, 0); - /* Store the return address in Pd. */ - t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8 + 4)); + LOG_DIS("jasc 0x%x\n", imm); + cris_cc_mask(dc, 0); + /* Store the return address in Pd. */ + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8 + 4)); - dc->jmp_pc = imm; - cris_prepare_jmp(dc, JMP_DIRECT); - return 6; + dc->jmp_pc = imm; + cris_prepare_jmp(dc, JMP_DIRECT); + return 6; } static int dec_jasc_r(CPUCRISState *env, DisasContext *dc) { - LOG_DIS("jasc_r $r%u, $p%u\n", dc->op1, dc->op2); - cris_cc_mask(dc, 0); - /* Store the return address in Pd. */ - tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]); - t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4 + 4)); - cris_prepare_jmp(dc, JMP_INDIRECT); - return 2; + LOG_DIS("jasc_r $r%u, $p%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, 0); + /* Store the return address in Pd. */ + tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]); + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 4 + 4)); + cris_prepare_jmp(dc, JMP_INDIRECT); + return 2; } static int dec_bcc_im(CPUCRISState *env, DisasContext *dc) { - int32_t offset; - uint32_t cond = dc->op2; + int32_t offset; + uint32_t cond = dc->op2; - offset = cris_fetch(env, dc, dc->pc + 2, 2, 1); + offset = cris_fetch(env, dc, dc->pc + 2, 2, 1); - LOG_DIS("b%s %d pc=%x dst=%x\n", - cc_name(cond), offset, - dc->pc, dc->pc + offset); + LOG_DIS("b%s %d pc=%x dst=%x\n", + cc_name(cond), offset, + dc->pc, dc->pc + offset); - cris_cc_mask(dc, 0); - /* op2 holds the condition-code. */ - cris_prepare_cc_branch (dc, offset, cond); - return 4; + cris_cc_mask(dc, 0); + /* op2 holds the condition-code. */ + cris_prepare_cc_branch(dc, offset, cond); + return 4; } static int dec_bas_im(CPUCRISState *env, DisasContext *dc) { - int32_t simm; + int32_t simm; + simm = cris_fetch(env, dc, dc->pc + 2, 4, 0); - simm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + LOG_DIS("bas 0x%x, $p%u\n", dc->pc + simm, dc->op2); + cris_cc_mask(dc, 0); + /* Store the return address in Pd. */ + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8)); - LOG_DIS("bas 0x%x, $p%u\n", dc->pc + simm, dc->op2); - cris_cc_mask(dc, 0); - /* Store the return address in Pd. */ - t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8)); - - dc->jmp_pc = dc->pc + simm; - cris_prepare_jmp(dc, JMP_DIRECT); - return 6; + dc->jmp_pc = dc->pc + simm; + cris_prepare_jmp(dc, JMP_DIRECT); + return 6; } static int dec_basc_im(CPUCRISState *env, DisasContext *dc) { - int32_t simm; - simm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + int32_t simm; + simm = cris_fetch(env, dc, dc->pc + 2, 4, 0); - LOG_DIS("basc 0x%x, $p%u\n", dc->pc + simm, dc->op2); - cris_cc_mask(dc, 0); - /* Store the return address in Pd. */ - t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 12)); + LOG_DIS("basc 0x%x, $p%u\n", dc->pc + simm, dc->op2); + cris_cc_mask(dc, 0); + /* Store the return address in Pd. */ + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 12)); - dc->jmp_pc = dc->pc + simm; - cris_prepare_jmp(dc, JMP_DIRECT); - return 6; + dc->jmp_pc = dc->pc + simm; + cris_prepare_jmp(dc, JMP_DIRECT); + return 6; } static int dec_rfe_etc(CPUCRISState *env, DisasContext *dc) { - cris_cc_mask(dc, 0); - - if (dc->op2 == 15) { - t_gen_mov_env_TN(halted, tcg_const_tl(1)); - tcg_gen_movi_tl(env_pc, dc->pc + 2); - t_gen_raise_exception(EXCP_HLT); - return 2; - } - - switch (dc->op2 & 7) { - case 2: - /* rfe. */ - LOG_DIS("rfe\n"); - cris_evaluate_flags(dc); - gen_helper_rfe(cpu_env); - dc->is_jmp = DISAS_UPDATE; - break; - case 5: - /* rfn. */ - LOG_DIS("rfn\n"); - cris_evaluate_flags(dc); - gen_helper_rfn(cpu_env); - dc->is_jmp = DISAS_UPDATE; - break; - case 6: - LOG_DIS("break %d\n", dc->op1); - cris_evaluate_flags (dc); - /* break. */ - tcg_gen_movi_tl(env_pc, dc->pc + 2); - - /* Breaks start at 16 in the exception vector. */ - t_gen_mov_env_TN(trap_vector, - tcg_const_tl(dc->op1 + 16)); - t_gen_raise_exception(EXCP_BREAK); - dc->is_jmp = DISAS_UPDATE; - break; - default: - printf ("op2=%x\n", dc->op2); - BUG(); - break; - - } - return 2; + cris_cc_mask(dc, 0); + + if (dc->op2 == 15) { + t_gen_mov_env_TN(halted, tcg_const_tl(1)); + tcg_gen_movi_tl(env_pc, dc->pc + 2); + t_gen_raise_exception(EXCP_HLT); + return 2; + } + + switch (dc->op2 & 7) { + case 2: + /* rfe. */ + LOG_DIS("rfe\n"); + cris_evaluate_flags(dc); + gen_helper_rfe(cpu_env); + dc->is_jmp = DISAS_UPDATE; + break; + case 5: + /* rfn. */ + LOG_DIS("rfn\n"); + cris_evaluate_flags(dc); + gen_helper_rfn(cpu_env); + dc->is_jmp = DISAS_UPDATE; + break; + case 6: + LOG_DIS("break %d\n", dc->op1); + cris_evaluate_flags(dc); + /* break. */ + tcg_gen_movi_tl(env_pc, dc->pc + 2); + + /* Breaks start at 16 in the exception vector. */ + t_gen_mov_env_TN(trap_vector, + tcg_const_tl(dc->op1 + 16)); + t_gen_raise_exception(EXCP_BREAK); + dc->is_jmp = DISAS_UPDATE; + break; + default: + printf("op2=%x\n", dc->op2); + BUG(); + break; + + } + return 2; } static int dec_ftag_fidx_d_m(CPUCRISState *env, DisasContext *dc) { - return 2; + return 2; } static int dec_ftag_fidx_i_m(CPUCRISState *env, DisasContext *dc) { - return 2; + return 2; } static int dec_null(CPUCRISState *env, DisasContext *dc) { - printf ("unknown insn pc=%x opc=%x op1=%x op2=%x\n", - dc->pc, dc->opcode, dc->op1, dc->op2); - fflush(NULL); - BUG(); - return 2; + printf("unknown insn pc=%x opc=%x op1=%x op2=%x\n", + dc->pc, dc->opcode, dc->op1, dc->op2); + fflush(NULL); + BUG(); + return 2; } static struct decoder_info { - struct { - uint32_t bits; - uint32_t mask; - }; - int (*dec)(CPUCRISState *env, DisasContext *dc); + struct { + uint32_t bits; + uint32_t mask; + }; + int (*dec)(CPUCRISState *env, DisasContext *dc); } decinfo[] = { - /* Order matters here. */ - {DEC_MOVEQ, dec_moveq}, - {DEC_BTSTQ, dec_btstq}, - {DEC_CMPQ, dec_cmpq}, - {DEC_ADDOQ, dec_addoq}, - {DEC_ADDQ, dec_addq}, - {DEC_SUBQ, dec_subq}, - {DEC_ANDQ, dec_andq}, - {DEC_ORQ, dec_orq}, - {DEC_ASRQ, dec_asrq}, - {DEC_LSLQ, dec_lslq}, - {DEC_LSRQ, dec_lsrq}, - {DEC_BCCQ, dec_bccq}, - - {DEC_BCC_IM, dec_bcc_im}, - {DEC_JAS_IM, dec_jas_im}, - {DEC_JAS_R, dec_jas_r}, - {DEC_JASC_IM, dec_jasc_im}, - {DEC_JASC_R, dec_jasc_r}, - {DEC_BAS_IM, dec_bas_im}, - {DEC_BASC_IM, dec_basc_im}, - {DEC_JUMP_P, dec_jump_p}, - {DEC_LAPC_IM, dec_lapc_im}, - {DEC_LAPCQ, dec_lapcq}, - - {DEC_RFE_ETC, dec_rfe_etc}, - {DEC_ADDC_MR, dec_addc_mr}, - - {DEC_MOVE_MP, dec_move_mp}, - {DEC_MOVE_PM, dec_move_pm}, - {DEC_MOVEM_MR, dec_movem_mr}, - {DEC_MOVEM_RM, dec_movem_rm}, - {DEC_MOVE_PR, dec_move_pr}, - {DEC_SCC_R, dec_scc_r}, - {DEC_SETF, dec_setclrf}, - {DEC_CLEARF, dec_setclrf}, - - {DEC_MOVE_SR, dec_move_sr}, - {DEC_MOVE_RP, dec_move_rp}, - {DEC_SWAP_R, dec_swap_r}, - {DEC_ABS_R, dec_abs_r}, - {DEC_LZ_R, dec_lz_r}, - {DEC_MOVE_RS, dec_move_rs}, - {DEC_BTST_R, dec_btst_r}, - {DEC_ADDC_R, dec_addc_r}, - - {DEC_DSTEP_R, dec_dstep_r}, - {DEC_XOR_R, dec_xor_r}, - {DEC_MCP_R, dec_mcp_r}, - {DEC_CMP_R, dec_cmp_r}, - - {DEC_ADDI_R, dec_addi_r}, - {DEC_ADDI_ACR, dec_addi_acr}, - - {DEC_ADD_R, dec_add_r}, - {DEC_SUB_R, dec_sub_r}, - - {DEC_ADDU_R, dec_addu_r}, - {DEC_ADDS_R, dec_adds_r}, - {DEC_SUBU_R, dec_subu_r}, - {DEC_SUBS_R, dec_subs_r}, - {DEC_LSL_R, dec_lsl_r}, - - {DEC_AND_R, dec_and_r}, - {DEC_OR_R, dec_or_r}, - {DEC_BOUND_R, dec_bound_r}, - {DEC_ASR_R, dec_asr_r}, - {DEC_LSR_R, dec_lsr_r}, - - {DEC_MOVU_R, dec_movu_r}, - {DEC_MOVS_R, dec_movs_r}, - {DEC_NEG_R, dec_neg_r}, - {DEC_MOVE_R, dec_move_r}, - - {DEC_FTAG_FIDX_I_M, dec_ftag_fidx_i_m}, - {DEC_FTAG_FIDX_D_M, dec_ftag_fidx_d_m}, - - {DEC_MULS_R, dec_muls_r}, - {DEC_MULU_R, dec_mulu_r}, - - {DEC_ADDU_M, dec_addu_m}, - {DEC_ADDS_M, dec_adds_m}, - {DEC_SUBU_M, dec_subu_m}, - {DEC_SUBS_M, dec_subs_m}, - - {DEC_CMPU_M, dec_cmpu_m}, - {DEC_CMPS_M, dec_cmps_m}, - {DEC_MOVU_M, dec_movu_m}, - {DEC_MOVS_M, dec_movs_m}, - - {DEC_CMP_M, dec_cmp_m}, - {DEC_ADDO_M, dec_addo_m}, - {DEC_BOUND_M, dec_bound_m}, - {DEC_ADD_M, dec_add_m}, - {DEC_SUB_M, dec_sub_m}, - {DEC_AND_M, dec_and_m}, - {DEC_OR_M, dec_or_m}, - {DEC_MOVE_RM, dec_move_rm}, - {DEC_TEST_M, dec_test_m}, - {DEC_MOVE_MR, dec_move_mr}, - - {{0, 0}, dec_null} + /* Order matters here. */ + {DEC_MOVEQ, dec_moveq}, + {DEC_BTSTQ, dec_btstq}, + {DEC_CMPQ, dec_cmpq}, + {DEC_ADDOQ, dec_addoq}, + {DEC_ADDQ, dec_addq}, + {DEC_SUBQ, dec_subq}, + {DEC_ANDQ, dec_andq}, + {DEC_ORQ, dec_orq}, + {DEC_ASRQ, dec_asrq}, + {DEC_LSLQ, dec_lslq}, + {DEC_LSRQ, dec_lsrq}, + {DEC_BCCQ, dec_bccq}, + + {DEC_BCC_IM, dec_bcc_im}, + {DEC_JAS_IM, dec_jas_im}, + {DEC_JAS_R, dec_jas_r}, + {DEC_JASC_IM, dec_jasc_im}, + {DEC_JASC_R, dec_jasc_r}, + {DEC_BAS_IM, dec_bas_im}, + {DEC_BASC_IM, dec_basc_im}, + {DEC_JUMP_P, dec_jump_p}, + {DEC_LAPC_IM, dec_lapc_im}, + {DEC_LAPCQ, dec_lapcq}, + + {DEC_RFE_ETC, dec_rfe_etc}, + {DEC_ADDC_MR, dec_addc_mr}, + + {DEC_MOVE_MP, dec_move_mp}, + {DEC_MOVE_PM, dec_move_pm}, + {DEC_MOVEM_MR, dec_movem_mr}, + {DEC_MOVEM_RM, dec_movem_rm}, + {DEC_MOVE_PR, dec_move_pr}, + {DEC_SCC_R, dec_scc_r}, + {DEC_SETF, dec_setclrf}, + {DEC_CLEARF, dec_setclrf}, + + {DEC_MOVE_SR, dec_move_sr}, + {DEC_MOVE_RP, dec_move_rp}, + {DEC_SWAP_R, dec_swap_r}, + {DEC_ABS_R, dec_abs_r}, + {DEC_LZ_R, dec_lz_r}, + {DEC_MOVE_RS, dec_move_rs}, + {DEC_BTST_R, dec_btst_r}, + {DEC_ADDC_R, dec_addc_r}, + + {DEC_DSTEP_R, dec_dstep_r}, + {DEC_XOR_R, dec_xor_r}, + {DEC_MCP_R, dec_mcp_r}, + {DEC_CMP_R, dec_cmp_r}, + + {DEC_ADDI_R, dec_addi_r}, + {DEC_ADDI_ACR, dec_addi_acr}, + + {DEC_ADD_R, dec_add_r}, + {DEC_SUB_R, dec_sub_r}, + + {DEC_ADDU_R, dec_addu_r}, + {DEC_ADDS_R, dec_adds_r}, + {DEC_SUBU_R, dec_subu_r}, + {DEC_SUBS_R, dec_subs_r}, + {DEC_LSL_R, dec_lsl_r}, + + {DEC_AND_R, dec_and_r}, + {DEC_OR_R, dec_or_r}, + {DEC_BOUND_R, dec_bound_r}, + {DEC_ASR_R, dec_asr_r}, + {DEC_LSR_R, dec_lsr_r}, + + {DEC_MOVU_R, dec_movu_r}, + {DEC_MOVS_R, dec_movs_r}, + {DEC_NEG_R, dec_neg_r}, + {DEC_MOVE_R, dec_move_r}, + + {DEC_FTAG_FIDX_I_M, dec_ftag_fidx_i_m}, + {DEC_FTAG_FIDX_D_M, dec_ftag_fidx_d_m}, + + {DEC_MULS_R, dec_muls_r}, + {DEC_MULU_R, dec_mulu_r}, + + {DEC_ADDU_M, dec_addu_m}, + {DEC_ADDS_M, dec_adds_m}, + {DEC_SUBU_M, dec_subu_m}, + {DEC_SUBS_M, dec_subs_m}, + + {DEC_CMPU_M, dec_cmpu_m}, + {DEC_CMPS_M, dec_cmps_m}, + {DEC_MOVU_M, dec_movu_m}, + {DEC_MOVS_M, dec_movs_m}, + + {DEC_CMP_M, dec_cmp_m}, + {DEC_ADDO_M, dec_addo_m}, + {DEC_BOUND_M, dec_bound_m}, + {DEC_ADD_M, dec_add_m}, + {DEC_SUB_M, dec_sub_m}, + {DEC_AND_M, dec_and_m}, + {DEC_OR_M, dec_or_m}, + {DEC_MOVE_RM, dec_move_rm}, + {DEC_TEST_M, dec_test_m}, + {DEC_MOVE_MR, dec_move_mr}, + + {{0, 0}, dec_null} }; static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc) { - int insn_len = 2; - int i; + int insn_len = 2; + int i; - if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { - tcg_gen_debug_insn_start(dc->pc); + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { + tcg_gen_debug_insn_start(dc->pc); } - /* Load a halfword onto the instruction register. */ + /* Load a halfword onto the instruction register. */ dc->ir = cris_fetch(env, dc, dc->pc, 2, 0); - /* Now decode it. */ - dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11); - dc->op1 = EXTRACT_FIELD(dc->ir, 0, 3); - dc->op2 = EXTRACT_FIELD(dc->ir, 12, 15); - dc->zsize = EXTRACT_FIELD(dc->ir, 4, 4); - dc->zzsize = EXTRACT_FIELD(dc->ir, 4, 5); - dc->postinc = EXTRACT_FIELD(dc->ir, 10, 10); - - /* Large switch for all insns. */ - for (i = 0; i < ARRAY_SIZE(decinfo); i++) { - if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) - { - insn_len = decinfo[i].dec(env, dc); - break; - } - } + /* Now decode it. */ + dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11); + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 3); + dc->op2 = EXTRACT_FIELD(dc->ir, 12, 15); + dc->zsize = EXTRACT_FIELD(dc->ir, 4, 4); + dc->zzsize = EXTRACT_FIELD(dc->ir, 4, 5); + dc->postinc = EXTRACT_FIELD(dc->ir, 10, 10); + + /* Large switch for all insns. */ + for (i = 0; i < ARRAY_SIZE(decinfo); i++) { + if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { + insn_len = decinfo[i].dec(env, dc); + break; + } + } #if !defined(CONFIG_USER_ONLY) - /* Single-stepping ? */ - if (dc->tb_flags & S_FLAG) { - int l1; - - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_PR[PR_SPC], dc->pc, l1); - /* We treat SPC as a break with an odd trap vector. */ - cris_evaluate_flags (dc); - t_gen_mov_env_TN(trap_vector, tcg_const_tl(3)); - tcg_gen_movi_tl(env_pc, dc->pc + insn_len); - tcg_gen_movi_tl(cpu_PR[PR_SPC], dc->pc + insn_len); - t_gen_raise_exception(EXCP_BREAK); - gen_set_label(l1); - } + /* Single-stepping ? */ + if (dc->tb_flags & S_FLAG) { + int l1; + + l1 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_PR[PR_SPC], dc->pc, l1); + /* We treat SPC as a break with an odd trap vector. */ + cris_evaluate_flags(dc); + t_gen_mov_env_TN(trap_vector, tcg_const_tl(3)); + tcg_gen_movi_tl(env_pc, dc->pc + insn_len); + tcg_gen_movi_tl(cpu_PR[PR_SPC], dc->pc + insn_len); + t_gen_raise_exception(EXCP_BREAK); + gen_set_label(l1); + } #endif - return insn_len; + return insn_len; } static void check_breakpoint(CPUCRISState *env, DisasContext *dc) { - CPUBreakpoint *bp; + CPUBreakpoint *bp; - if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { - QTAILQ_FOREACH(bp, &env->breakpoints, entry) { - if (bp->pc == dc->pc) { - cris_evaluate_flags (dc); - tcg_gen_movi_tl(env_pc, dc->pc); - t_gen_raise_exception(EXCP_DEBUG); - dc->is_jmp = DISAS_UPDATE; - } - } - } + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc->pc) { + cris_evaluate_flags(dc); + tcg_gen_movi_tl(env_pc, dc->pc); + t_gen_raise_exception(EXCP_DEBUG); + dc->is_jmp = DISAS_UPDATE; + } + } + } } #include "translate_v10.c" @@ -3174,250 +3204,256 @@ static void gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, int search_pc) { - uint16_t *gen_opc_end; - uint32_t pc_start; - unsigned int insn_len; - int j, lj; - struct DisasContext ctx; - struct DisasContext *dc = &ctx; - uint32_t next_page_start; - target_ulong npc; - int num_insns; - int max_insns; - - qemu_log_try_set_file(stderr); - - if (env->pregs[PR_VR] == 32) { - dc->decoder = crisv32_decoder; - dc->clear_locked_irq = 0; - } else { - dc->decoder = crisv10_decoder; - dc->clear_locked_irq = 1; - } - - /* Odd PC indicates that branch is rexecuting due to exception in the - * delayslot, like in real hw. - */ - pc_start = tb->pc & ~1; - dc->env = env; - dc->tb = tb; - - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - - dc->is_jmp = DISAS_NEXT; - dc->ppc = pc_start; - dc->pc = pc_start; - dc->singlestep_enabled = env->singlestep_enabled; - dc->flags_uptodate = 1; - dc->flagx_known = 1; - dc->flags_x = tb->flags & X_FLAG; - dc->cc_x_uptodate = 0; - dc->cc_mask = 0; - dc->update_cc = 0; - dc->clear_prefix = 0; - - cris_update_cc_op(dc, CC_OP_FLAGS, 4); - dc->cc_size_uptodate = -1; - - /* Decode TB flags. */ - dc->tb_flags = tb->flags & (S_FLAG | P_FLAG | U_FLAG \ - | X_FLAG | PFIX_FLAG); - dc->delayed_branch = !!(tb->flags & 7); - if (dc->delayed_branch) - dc->jmp = JMP_INDIRECT; - else - dc->jmp = JMP_NOJMP; - - dc->cpustate_changed = 0; - - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { - qemu_log( - "srch=%d pc=%x %x flg=%" PRIx64 " bt=%x ds=%u ccs=%x\n" - "pid=%x usp=%x\n" - "%x.%x.%x.%x\n" - "%x.%x.%x.%x\n" - "%x.%x.%x.%x\n" - "%x.%x.%x.%x\n", - search_pc, dc->pc, dc->ppc, - (uint64_t)tb->flags, - env->btarget, (unsigned)tb->flags & 7, - env->pregs[PR_CCS], - env->pregs[PR_PID], env->pregs[PR_USP], - env->regs[0], env->regs[1], env->regs[2], env->regs[3], - env->regs[4], env->regs[5], env->regs[6], env->regs[7], - env->regs[8], env->regs[9], - env->regs[10], env->regs[11], - env->regs[12], env->regs[13], - env->regs[14], env->regs[15]); - qemu_log("--------------\n"); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - } - - next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; - lj = -1; - num_insns = 0; - max_insns = tb->cflags & CF_COUNT_MASK; - if (max_insns == 0) - max_insns = CF_COUNT_MASK; - - gen_icount_start(); - do - { - check_breakpoint(env, dc); - - if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; - if (lj < j) { - lj++; - while (lj < j) - gen_opc_instr_start[lj++] = 0; - } - if (dc->delayed_branch == 1) - gen_opc_pc[lj] = dc->ppc | 1; - else - gen_opc_pc[lj] = dc->pc; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; - } - - /* Pretty disas. */ - LOG_DIS("%8.8x:\t", dc->pc); - - if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) - gen_io_start(); - dc->clear_x = 1; - - insn_len = dc->decoder(env, dc); - dc->ppc = dc->pc; - dc->pc += insn_len; - if (dc->clear_x) - cris_clear_x_flag(dc); - - num_insns++; - /* Check for delayed branches here. If we do it before - actually generating any host code, the simulator will just - loop doing nothing for on this program location. */ - if (dc->delayed_branch) { - dc->delayed_branch--; - if (dc->delayed_branch == 0) - { - if (tb->flags & 7) - t_gen_mov_env_TN(dslot, - tcg_const_tl(0)); - if (dc->cpustate_changed || !dc->flagx_known - || (dc->flags_x != (tb->flags & X_FLAG))) { - cris_store_direct_jmp(dc); - } - - if (dc->clear_locked_irq) { - dc->clear_locked_irq = 0; - t_gen_mov_env_TN(locked_irq, - tcg_const_tl(0)); - } - - if (dc->jmp == JMP_DIRECT_CC) { - int l1; - - l1 = gen_new_label(); - cris_evaluate_flags(dc); - - /* Conditional jmp. */ - tcg_gen_brcondi_tl(TCG_COND_EQ, - env_btaken, 0, l1); - gen_goto_tb(dc, 1, dc->jmp_pc); - gen_set_label(l1); - gen_goto_tb(dc, 0, dc->pc); - dc->is_jmp = DISAS_TB_JUMP; - dc->jmp = JMP_NOJMP; - } else if (dc->jmp == JMP_DIRECT) { - cris_evaluate_flags(dc); - gen_goto_tb(dc, 0, dc->jmp_pc); - dc->is_jmp = DISAS_TB_JUMP; - dc->jmp = JMP_NOJMP; - } else { - t_gen_cc_jmp(env_btarget, - tcg_const_tl(dc->pc)); - dc->is_jmp = DISAS_JUMP; - } - break; - } - } - - /* If we are rexecuting a branch due to exceptions on - delay slots dont break. */ - if (!(tb->pc & 1) && env->singlestep_enabled) - break; - } while (!dc->is_jmp && !dc->cpustate_changed - && gen_opc_ptr < gen_opc_end - && !singlestep - && (dc->pc < next_page_start) - && num_insns < max_insns); - - if (dc->clear_locked_irq) - t_gen_mov_env_TN(locked_irq, tcg_const_tl(0)); - - npc = dc->pc; + uint16_t *gen_opc_end; + uint32_t pc_start; + unsigned int insn_len; + int j, lj; + struct DisasContext ctx; + struct DisasContext *dc = &ctx; + uint32_t next_page_start; + target_ulong npc; + int num_insns; + int max_insns; + + qemu_log_try_set_file(stderr); + + if (env->pregs[PR_VR] == 32) { + dc->decoder = crisv32_decoder; + dc->clear_locked_irq = 0; + } else { + dc->decoder = crisv10_decoder; + dc->clear_locked_irq = 1; + } + + /* Odd PC indicates that branch is rexecuting due to exception in the + * delayslot, like in real hw. + */ + pc_start = tb->pc & ~1; + dc->env = env; + dc->tb = tb; + + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; + + dc->is_jmp = DISAS_NEXT; + dc->ppc = pc_start; + dc->pc = pc_start; + dc->singlestep_enabled = env->singlestep_enabled; + dc->flags_uptodate = 1; + dc->flagx_known = 1; + dc->flags_x = tb->flags & X_FLAG; + dc->cc_x_uptodate = 0; + dc->cc_mask = 0; + dc->update_cc = 0; + dc->clear_prefix = 0; + + cris_update_cc_op(dc, CC_OP_FLAGS, 4); + dc->cc_size_uptodate = -1; + + /* Decode TB flags. */ + dc->tb_flags = tb->flags & (S_FLAG | P_FLAG | U_FLAG \ + | X_FLAG | PFIX_FLAG); + dc->delayed_branch = !!(tb->flags & 7); + if (dc->delayed_branch) { + dc->jmp = JMP_INDIRECT; + } else { + dc->jmp = JMP_NOJMP; + } + + dc->cpustate_changed = 0; + + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log( + "srch=%d pc=%x %x flg=%" PRIx64 " bt=%x ds=%u ccs=%x\n" + "pid=%x usp=%x\n" + "%x.%x.%x.%x\n" + "%x.%x.%x.%x\n" + "%x.%x.%x.%x\n" + "%x.%x.%x.%x\n", + search_pc, dc->pc, dc->ppc, + (uint64_t)tb->flags, + env->btarget, (unsigned)tb->flags & 7, + env->pregs[PR_CCS], + env->pregs[PR_PID], env->pregs[PR_USP], + env->regs[0], env->regs[1], env->regs[2], env->regs[3], + env->regs[4], env->regs[5], env->regs[6], env->regs[7], + env->regs[8], env->regs[9], + env->regs[10], env->regs[11], + env->regs[12], env->regs[13], + env->regs[14], env->regs[15]); + qemu_log("--------------\n"); + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + } + + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) { + max_insns = CF_COUNT_MASK; + } + + gen_icount_start(); + do { + check_breakpoint(env, dc); + + if (search_pc) { + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) { + gen_opc_instr_start[lj++] = 0; + } + } + if (dc->delayed_branch == 1) { + gen_opc_pc[lj] = dc->ppc | 1; + } else { + gen_opc_pc[lj] = dc->pc; + } + gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; + } + + /* Pretty disas. */ + LOG_DIS("%8.8x:\t", dc->pc); + + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + gen_io_start(); + } + dc->clear_x = 1; + + insn_len = dc->decoder(env, dc); + dc->ppc = dc->pc; + dc->pc += insn_len; + if (dc->clear_x) { + cris_clear_x_flag(dc); + } + + num_insns++; + /* Check for delayed branches here. If we do it before + actually generating any host code, the simulator will just + loop doing nothing for on this program location. */ + if (dc->delayed_branch) { + dc->delayed_branch--; + if (dc->delayed_branch == 0) { + if (tb->flags & 7) { + t_gen_mov_env_TN(dslot, tcg_const_tl(0)); + } + if (dc->cpustate_changed || !dc->flagx_known + || (dc->flags_x != (tb->flags & X_FLAG))) { + cris_store_direct_jmp(dc); + } + + if (dc->clear_locked_irq) { + dc->clear_locked_irq = 0; + t_gen_mov_env_TN(locked_irq, tcg_const_tl(0)); + } + + if (dc->jmp == JMP_DIRECT_CC) { + int l1; + + l1 = gen_new_label(); + cris_evaluate_flags(dc); + + /* Conditional jmp. */ + tcg_gen_brcondi_tl(TCG_COND_EQ, + env_btaken, 0, l1); + gen_goto_tb(dc, 1, dc->jmp_pc); + gen_set_label(l1); + gen_goto_tb(dc, 0, dc->pc); + dc->is_jmp = DISAS_TB_JUMP; + dc->jmp = JMP_NOJMP; + } else if (dc->jmp == JMP_DIRECT) { + cris_evaluate_flags(dc); + gen_goto_tb(dc, 0, dc->jmp_pc); + dc->is_jmp = DISAS_TB_JUMP; + dc->jmp = JMP_NOJMP; + } else { + t_gen_cc_jmp(env_btarget, tcg_const_tl(dc->pc)); + dc->is_jmp = DISAS_JUMP; + } + break; + } + } + + /* If we are rexecuting a branch due to exceptions on + delay slots dont break. */ + if (!(tb->pc & 1) && env->singlestep_enabled) { + break; + } + } while (!dc->is_jmp && !dc->cpustate_changed + && tcg_ctx.gen_opc_ptr < gen_opc_end + && !singlestep + && (dc->pc < next_page_start) + && num_insns < max_insns); + + if (dc->clear_locked_irq) { + t_gen_mov_env_TN(locked_irq, tcg_const_tl(0)); + } + + npc = dc->pc; if (tb->cflags & CF_LAST_IO) gen_io_end(); - /* Force an update if the per-tb cpu state has changed. */ - if (dc->is_jmp == DISAS_NEXT - && (dc->cpustate_changed || !dc->flagx_known - || (dc->flags_x != (tb->flags & X_FLAG)))) { - dc->is_jmp = DISAS_UPDATE; - tcg_gen_movi_tl(env_pc, npc); - } - /* Broken branch+delayslot sequence. */ - if (dc->delayed_branch == 1) { - /* Set env->dslot to the size of the branch insn. */ - t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc)); - cris_store_direct_jmp(dc); - } - - cris_evaluate_flags (dc); - - if (unlikely(env->singlestep_enabled)) { - if (dc->is_jmp == DISAS_NEXT) - tcg_gen_movi_tl(env_pc, npc); - t_gen_raise_exception(EXCP_DEBUG); - } else { - switch(dc->is_jmp) { - case DISAS_NEXT: - gen_goto_tb(dc, 1, npc); - break; - default: - case DISAS_JUMP: - case DISAS_UPDATE: - /* indicate that the hash table must be used - to find the next TB */ - tcg_gen_exit_tb(0); - break; - case DISAS_SWI: - case DISAS_TB_JUMP: - /* nothing more to generate */ - break; - } - } - gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; - if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; - lj++; - while (lj <= j) - gen_opc_instr_start[lj++] = 0; - } else { - tb->size = dc->pc - pc_start; - tb->icount = num_insns; - } + /* Force an update if the per-tb cpu state has changed. */ + if (dc->is_jmp == DISAS_NEXT + && (dc->cpustate_changed || !dc->flagx_known + || (dc->flags_x != (tb->flags & X_FLAG)))) { + dc->is_jmp = DISAS_UPDATE; + tcg_gen_movi_tl(env_pc, npc); + } + /* Broken branch+delayslot sequence. */ + if (dc->delayed_branch == 1) { + /* Set env->dslot to the size of the branch insn. */ + t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc)); + cris_store_direct_jmp(dc); + } + + cris_evaluate_flags(dc); + + if (unlikely(env->singlestep_enabled)) { + if (dc->is_jmp == DISAS_NEXT) { + tcg_gen_movi_tl(env_pc, npc); + } + t_gen_raise_exception(EXCP_DEBUG); + } else { + switch (dc->is_jmp) { + case DISAS_NEXT: + gen_goto_tb(dc, 1, npc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + /* indicate that the hash table must be used + to find the next TB */ + tcg_gen_exit_tb(0); + break; + case DISAS_SWI: + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + } + } + gen_icount_end(tb, num_insns); + *tcg_ctx.gen_opc_ptr = INDEX_op_end; + if (search_pc) { + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; + lj++; + while (lj <= j) { + gen_opc_instr_start[lj++] = 0; + } + } else { + tb->size = dc->pc - pc_start; + tb->icount = num_insns; + } #ifdef DEBUG_DISAS #if !DISAS_CRIS - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { - log_target_disas(env, pc_start, dc->pc - pc_start, + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + log_target_disas(env, pc_start, dc->pc - pc_start, dc->env->pregs[PR_VR]); - qemu_log("\nisize=%d osize=%td\n", - dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); - } + qemu_log("\nisize=%d osize=%td\n", + dc->pc - pc_start, tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf); + } #endif #endif } @@ -3435,41 +3471,45 @@ void gen_intermediate_code_pc (CPUCRISState *env, struct TranslationBlock *tb) void cpu_dump_state (CPUCRISState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { - int i; - uint32_t srs; - - if (!env || !f) - return; - - cpu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n" - "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n", - env->pc, env->pregs[PR_CCS], env->btaken, env->btarget, - env->cc_op, - env->cc_src, env->cc_dest, env->cc_result, env->cc_mask); - - - for (i = 0; i < 16; i++) { - cpu_fprintf(f, "%s=%8.8x ",regnames[i], env->regs[i]); - if ((i + 1) % 4 == 0) - cpu_fprintf(f, "\n"); - } - cpu_fprintf(f, "\nspecial regs:\n"); - for (i = 0; i < 16; i++) { - cpu_fprintf(f, "%s=%8.8x ", pregnames[i], env->pregs[i]); - if ((i + 1) % 4 == 0) - cpu_fprintf(f, "\n"); - } - srs = env->pregs[PR_SRS]; - cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); - if (srs < ARRAY_SIZE(env->sregs)) { - for (i = 0; i < 16; i++) { - cpu_fprintf(f, "s%2.2d=%8.8x ", - i, env->sregs[srs][i]); - if ((i + 1) % 4 == 0) - cpu_fprintf(f, "\n"); - } - } - cpu_fprintf(f, "\n\n"); + int i; + uint32_t srs; + + if (!env || !f) { + return; + } + + cpu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n" + "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n", + env->pc, env->pregs[PR_CCS], env->btaken, env->btarget, + env->cc_op, + env->cc_src, env->cc_dest, env->cc_result, env->cc_mask); + + + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "%s=%8.8x ", regnames[i], env->regs[i]); + if ((i + 1) % 4 == 0) { + cpu_fprintf(f, "\n"); + } + } + cpu_fprintf(f, "\nspecial regs:\n"); + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "%s=%8.8x ", pregnames[i], env->pregs[i]); + if ((i + 1) % 4 == 0) { + cpu_fprintf(f, "\n"); + } + } + srs = env->pregs[PR_SRS]; + cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); + if (srs < ARRAY_SIZE(env->sregs)) { + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "s%2.2d=%8.8x ", + i, env->sregs[srs][i]); + if ((i + 1) % 4 == 0) { + cpu_fprintf(f, "\n"); + } + } + } + cpu_fprintf(f, "\n\n"); } @@ -3478,11 +3518,11 @@ struct uint32_t vr; const char *name; } cris_cores[] = { - {8, "crisv8"}, - {9, "crisv9"}, - {10, "crisv10"}, - {11, "crisv11"}, - {32, "crisv32"}, + {8, "crisv8"}, + {9, "crisv9"}, + {10, "crisv10"}, + {11, "crisv11"}, + {32, "crisv32"}, }; void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf) @@ -3581,5 +3621,5 @@ CRISCPU *cpu_cris_init(const char *cpu_model) void restore_state_to_opc(CPUCRISState *env, TranslationBlock *tb, int pc_pos) { - env->pc = gen_opc_pc[pc_pos]; + env->pc = gen_opc_pc[pc_pos]; } diff --git a/target-i386/cpu.c b/target-i386/cpu.c index e1db639295..64c34910a0 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -66,7 +66,7 @@ static const char *ext_feature_name[] = { NULL, "pcid", "dca", "sse4.1|sse4_1", "sse4.2|sse4_2", "x2apic", "movbe", "popcnt", "tsc-deadline", "aes", "xsave", "osxsave", - "avx", NULL, NULL, "hypervisor", + "avx", "f16c", "rdrand", "hypervisor", }; /* Feature names that are already defined on feature_name[] but are set on * CPUID[8000_0001].EDX on AMD CPUs don't have their names on @@ -87,10 +87,10 @@ static const char *ext3_feature_name[] = { "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse", "3dnowprefetch", "osvw", "ibs", "xop", - "skinit", "wdt", NULL, NULL, - "fma4", NULL, "cvt16", "nodeid_msr", - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, + "skinit", "wdt", NULL, "lwp", + "fma4", "tce", NULL, "nodeid_msr", + NULL, "tbm", "topoext", "perfctr_core", + "perfctr_nb", NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; @@ -119,7 +119,7 @@ static const char *svm_feature_name[] = { static const char *cpuid_7_0_ebx_feature_name[] = { "fsgsbase", NULL, NULL, "bmi1", "hle", "avx2", NULL, "smep", "bmi2", "erms", "invpcid", "rtm", NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, "smap", NULL, NULL, NULL, + NULL, NULL, "rdseed", "adx", "smap", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; @@ -647,6 +647,35 @@ static x86_def_t builtin_x86_defs[] = { .model_id = "Intel Xeon E312xx (Sandy Bridge)", }, { + .name = "Haswell", + .level = 0xd, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, + .family = 6, + .model = 60, + .stepping = 1, + .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | + CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | + CPUID_PGE | CPUID_MTRR | CPUID_APIC | CPUID_CX8 | + CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | + CPUID_DE | CPUID_FP87, + .ext_features = CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | + CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | + CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | + CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | + CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | + CPUID_EXT_PCID, + .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL, + .ext3_features = CPUID_EXT3_LAHF_LM, + .cpuid_7_0_ebx_features = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | + CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | + CPUID_7_0_EBX_RTM, + .xlevel = 0x8000000A, + .model_id = "Intel Core Processor (Haswell)", + }, + { .name = "Opteron_G1", .level = 5, .vendor1 = CPUID_VENDOR_AMD_1, @@ -756,6 +785,38 @@ static x86_def_t builtin_x86_defs[] = { .xlevel = 0x8000001A, .model_id = "AMD Opteron 62xx class CPU", }, + { + .name = "Opteron_G5", + .level = 0xd, + .vendor1 = CPUID_VENDOR_AMD_1, + .vendor2 = CPUID_VENDOR_AMD_2, + .vendor3 = CPUID_VENDOR_AMD_3, + .family = 21, + .model = 2, + .stepping = 0, + .features = CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | + CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | + CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | + CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | + CPUID_DE | CPUID_FP87, + .ext_features = CPUID_EXT_F16C | CPUID_EXT_AVX | CPUID_EXT_XSAVE | + CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | + CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_FMA | + CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, + .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | + CPUID_EXT2_PDPE1GB | CPUID_EXT2_FXSR | CPUID_EXT2_MMX | + CPUID_EXT2_NX | CPUID_EXT2_PSE36 | CPUID_EXT2_PAT | + CPUID_EXT2_CMOV | CPUID_EXT2_MCA | CPUID_EXT2_PGE | + CPUID_EXT2_MTRR | CPUID_EXT2_SYSCALL | CPUID_EXT2_APIC | + CPUID_EXT2_CX8 | CPUID_EXT2_MCE | CPUID_EXT2_PAE | CPUID_EXT2_MSR | + CPUID_EXT2_TSC | CPUID_EXT2_PSE | CPUID_EXT2_DE | CPUID_EXT2_FPU, + .ext3_features = CPUID_EXT3_TBM | CPUID_EXT3_FMA4 | CPUID_EXT3_XOP | + CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE | + CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM | + CPUID_EXT3_LAHF_LM, + .xlevel = 0x8000001A, + .model_id = "AMD Opteron 63xx class CPU", + }, }; #ifdef CONFIG_KVM diff --git a/target-i386/cpu.h b/target-i386/cpu.h index cdc59dc0ca..90ef1ff1e2 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -403,9 +403,11 @@ #define CPUID_EXT_TM2 (1 << 8) #define CPUID_EXT_SSSE3 (1 << 9) #define CPUID_EXT_CID (1 << 10) +#define CPUID_EXT_FMA (1 << 12) #define CPUID_EXT_CX16 (1 << 13) #define CPUID_EXT_XTPR (1 << 14) #define CPUID_EXT_PDCM (1 << 15) +#define CPUID_EXT_PCID (1 << 17) #define CPUID_EXT_DCA (1 << 18) #define CPUID_EXT_SSE41 (1 << 19) #define CPUID_EXT_SSE42 (1 << 20) @@ -417,6 +419,8 @@ #define CPUID_EXT_XSAVE (1 << 26) #define CPUID_EXT_OSXSAVE (1 << 27) #define CPUID_EXT_AVX (1 << 28) +#define CPUID_EXT_F16C (1 << 29) +#define CPUID_EXT_RDRAND (1 << 30) #define CPUID_EXT_HYPERVISOR (1 << 31) #define CPUID_EXT2_FPU (1 << 0) @@ -472,7 +476,15 @@ #define CPUID_EXT3_IBS (1 << 10) #define CPUID_EXT3_XOP (1 << 11) #define CPUID_EXT3_SKINIT (1 << 12) +#define CPUID_EXT3_WDT (1 << 13) +#define CPUID_EXT3_LWP (1 << 15) #define CPUID_EXT3_FMA4 (1 << 16) +#define CPUID_EXT3_TCE (1 << 17) +#define CPUID_EXT3_NODEID (1 << 19) +#define CPUID_EXT3_TBM (1 << 21) +#define CPUID_EXT3_TOPOEXT (1 << 22) +#define CPUID_EXT3_PERFCORE (1 << 23) +#define CPUID_EXT3_PERFNB (1 << 24) #define CPUID_SVM_NPT (1 << 0) #define CPUID_SVM_LBRV (1 << 1) @@ -485,7 +497,17 @@ #define CPUID_SVM_PAUSEFILTER (1 << 10) #define CPUID_SVM_PFTHRESHOLD (1 << 12) +#define CPUID_7_0_EBX_FSGSBASE (1 << 0) +#define CPUID_7_0_EBX_BMI1 (1 << 3) +#define CPUID_7_0_EBX_HLE (1 << 4) +#define CPUID_7_0_EBX_AVX2 (1 << 5) #define CPUID_7_0_EBX_SMEP (1 << 7) +#define CPUID_7_0_EBX_BMI2 (1 << 8) +#define CPUID_7_0_EBX_ERMS (1 << 9) +#define CPUID_7_0_EBX_INVPCID (1 << 10) +#define CPUID_7_0_EBX_RTM (1 << 11) +#define CPUID_7_0_EBX_RDSEED (1 << 18) +#define CPUID_7_0_EBX_ADX (1 << 19) #define CPUID_7_0_EBX_SMAP (1 << 20) #define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 7fdb8bcbbe..8e676ba1a8 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7962,7 +7962,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, cpu_ptr0 = tcg_temp_new_ptr(); cpu_ptr1 = tcg_temp_new_ptr(); - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; dc->is_jmp = DISAS_NEXT; pc_ptr = pc_start; @@ -7984,7 +7984,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, } } if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -8015,7 +8015,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, break; } /* if too long translation, stop generation too */ - if (gen_opc_ptr >= gen_opc_end || + if (tcg_ctx.gen_opc_ptr >= gen_opc_end || (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) || num_insns >= max_insns) { gen_jmp_im(pc_ptr - dc->cs_base); @@ -8031,10 +8031,10 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, if (tb->cflags & CF_LAST_IO) gen_io_end(); gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; /* we don't forget to fill the last values */ if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 3307daaf11..af986499f2 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -1018,7 +1018,7 @@ static void gen_intermediate_code_internal(CPULM32State *env, dc->env = env; dc->tb = tb; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; @@ -1047,7 +1047,7 @@ static void gen_intermediate_code_internal(CPULM32State *env, check_breakpoint(env, dc); if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -1071,7 +1071,7 @@ static void gen_intermediate_code_internal(CPULM32State *env, num_insns++; } while (!dc->is_jmp - && gen_opc_ptr < gen_opc_end + && tcg_ctx.gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && !singlestep && (dc->pc < next_page_start) @@ -1105,9 +1105,9 @@ static void gen_intermediate_code_internal(CPULM32State *env, } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) { gen_opc_instr_start[lj++] = 0; @@ -1122,7 +1122,8 @@ static void gen_intermediate_code_internal(CPULM32State *env, qemu_log("\n"); log_target_disas(env, pc_start, dc->pc - pc_start, 0); qemu_log("\nisize=%d osize=%td\n", - dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); + dc->pc - pc_start, tcg_ctx.gen_opc_ptr - + tcg_ctx.gen_opc_buf); } #endif } diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 1430d4c991..b13be4899e 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2982,7 +2982,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, dc->tb = tb; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; dc->env = env; dc->is_jmp = DISAS_NEXT; @@ -3015,7 +3015,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, break; } if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -3030,7 +3030,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, dc->insn_pc = dc->pc; disas_m68k_insn(env, dc); num_insns++; - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && !singlestep && (pc_offset) < (TARGET_PAGE_SIZE - 32) && @@ -3064,7 +3064,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, } } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { @@ -3075,7 +3075,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, } #endif if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 13fd73574b..cce4494954 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1741,7 +1741,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, dc->tb = tb; org_flags = dc->synced_flags = dc->tb_flags = tb->flags; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; dc->is_jmp = DISAS_NEXT; dc->jmp = 0; @@ -1784,7 +1784,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, check_breakpoint(env, dc); if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -1846,7 +1846,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, if (env->singlestep_enabled) break; } while (!dc->is_jmp && !dc->cpustate_changed - && gen_opc_ptr < gen_opc_end + && tcg_ctx.gen_opc_ptr < gen_opc_end && !singlestep && (dc->pc < next_page_start) && num_insns < max_insns); @@ -1897,9 +1897,9 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, } } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; @@ -1916,7 +1916,8 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, log_target_disas(env, pc_start, dc->pc - pc_start, 0); #endif qemu_log("\nisize=%d osize=%td\n", - dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); + dc->pc - pc_start, tcg_ctx.gen_opc_ptr - + tcg_ctx.gen_opc_buf); } #endif #endif diff --git a/target-mips/translate.c b/target-mips/translate.c index f6fc0c27ae..8b438f8bb0 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -10385,7 +10385,7 @@ enum { /* bits 13..12 for 0x32 */ MULT_ACC = 0x0, - MULTU_ACC = 0x0, + MULTU_ACC = 0x1, /* bits 15..12 for 0x2c */ SEB = 0x2, @@ -15513,7 +15513,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, qemu_log("search pc %d\n", search_pc); pc_start = tb->pc; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; ctx.pc = pc_start; ctx.saved_pc = -1; ctx.singlestep_enabled = env->singlestep_enabled; @@ -15549,7 +15549,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, } if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -15597,8 +15597,9 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) break; - if (gen_opc_ptr >= gen_opc_end) + if (tcg_ctx.gen_opc_ptr >= gen_opc_end) { break; + } if (num_insns >= max_insns) break; @@ -15630,9 +15631,9 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, } done_generating: gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index ff2feb48db..f14da7bd1a 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -1675,7 +1675,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, pc_start = tb->pc; dc->tb = tb; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; dc->is_jmp = DISAS_NEXT; dc->ppc = pc_start; dc->pc = pc_start; @@ -1703,7 +1703,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, do { check_breakpoint(cpu, dc); if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (k < j) { k++; while (k < j) { @@ -1744,7 +1744,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, } } } while (!dc->is_jmp - && gen_opc_ptr < gen_opc_end + && tcg_ctx.gen_opc_ptr < gen_opc_end && !cpu->env.singlestep_enabled && !singlestep && (dc->pc < next_page_start) @@ -1782,9 +1782,9 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; k++; while (k <= j) { gen_opc_instr_start[k++] = 0; @@ -1799,7 +1799,8 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, qemu_log("\n"); log_target_disas(&cpu->env, pc_start, dc->pc - pc_start, 0); qemu_log("\nisize=%d osize=%td\n", - dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); + dc->pc - pc_start, tcg_ctx.gen_opc_ptr - + tcg_ctx.gen_opc_buf); } #endif } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f0d49eea3f..16b9c5dd57 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9624,7 +9624,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, int max_insns; pc_start = tb->pc; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; ctx.nip = pc_start; ctx.tb = tb; ctx.exception = POWERPC_EXCP_NONE; @@ -9664,7 +9664,8 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, gen_icount_start(); /* Set env in case of segfault during code fetch */ - while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) { + while (ctx.exception == POWERPC_EXCP_NONE + && tcg_ctx.gen_opc_ptr < gen_opc_end) { if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { if (bp->pc == ctx.nip) { @@ -9674,7 +9675,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, } } if (unlikely(search_pc)) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -9774,9 +9775,9 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, tcg_gen_exit_tb(0); } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (unlikely(search_pc)) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c6267a8769..993f20752c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -5134,7 +5134,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, dc.tb = tb; dc.cc_op = CC_OP_DYNAMIC; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; @@ -5156,7 +5156,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, } } if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -5182,7 +5182,8 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, if (env->singlestep_enabled) { gen_debug(&dc); } - } while (!dc.is_jmp && gen_opc_ptr < gen_opc_end && dc.pc < next_page_start + } while (!dc.is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end + && dc.pc < next_page_start && num_insns < max_insns && !env->singlestep_enabled && !singlestep); @@ -5206,9 +5207,9 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_gen_exit_tb(0); } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) { gen_opc_instr_start[lj++] = 0; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 2ae7f03d35..5497dede05 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1967,7 +1967,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, int max_insns; pc_start = tb->pc; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; ctx.pc = pc_start; ctx.flags = (uint32_t)tb->flags; ctx.bstate = BS_NONE; @@ -1986,7 +1986,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, if (max_insns == 0) max_insns = CF_COUNT_MASK; gen_icount_start(); - while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { + while (ctx.bstate == BS_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end) { if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { if (ctx.pc == bp->pc) { @@ -1999,7 +1999,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, } } if (search_pc) { - i = gen_opc_ptr - gen_opc_buf; + i = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (ii < i) { ii++; while (ii < i) @@ -2056,9 +2056,9 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - i = gen_opc_ptr - gen_opc_buf; + i = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; ii++; while (ii <= i) gen_opc_instr_start[ii++] = 0; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 1d8b8ad9b9..2ae803695b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -5257,7 +5257,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, dc->fpu_enabled = tb_fpu_enabled(tb->flags); dc->address_mask_32bit = tb_am_enabled(tb->flags); dc->singlestep = (env->singlestep_enabled || singlestep); - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; @@ -5279,7 +5279,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, } if (spc) { qemu_log("Search PC...\n"); - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -5312,7 +5312,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, if (dc->singlestep) { break; } - } while ((gen_opc_ptr < gen_opc_end) && + } while ((tcg_ctx.gen_opc_ptr < gen_opc_end) && (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32) && num_insns < max_insns); @@ -5334,9 +5334,9 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, } } gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (spc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index 57b18ac0c6..052bb45d70 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -1956,7 +1956,7 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env, dc->tb = tb; - gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; @@ -1999,7 +1999,7 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env, } } if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -2031,7 +2031,7 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env, * Also stop translation when a page boundary is reached. This * ensures prefetch aborts occur at the right place. */ num_insns++; - } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && + } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && !singlestep && dc->pc < next_page_start && @@ -2103,7 +2103,7 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env, done_generating: gen_icount_end(tb, num_insns); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { @@ -2114,7 +2114,7 @@ done_generating: } #endif if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) { gen_opc_instr_start[lj++] = 0; diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 3c03775a76..e5a3f49a75 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -2849,7 +2849,7 @@ static void gen_intermediate_code_internal( DisasContext dc; int insn_count = 0; int j, lj = -1; - uint16_t *gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + uint16_t *gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; int max_insns = tb->cflags & CF_COUNT_MASK; uint32_t pc_start = tb->pc; uint32_t next_page_start = @@ -2893,7 +2893,7 @@ static void gen_intermediate_code_internal( check_breakpoint(env, &dc); if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -2944,7 +2944,7 @@ static void gen_intermediate_code_internal( } while (dc.is_jmp == DISAS_NEXT && insn_count < max_insns && dc.pc < next_page_start && - gen_opc_ptr < gen_opc_end); + tcg_ctx.gen_opc_ptr < gen_opc_end); reset_litbase(&dc); reset_sar_tracker(&dc); @@ -2960,7 +2960,7 @@ static void gen_intermediate_code_internal( gen_jumpi(&dc, dc.pc, 0); } gen_icount_end(tb, insn_count); - *gen_opc_ptr = INDEX_op_end; + *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (!search_pc) { tb->size = dc.pc - pc_start; diff --git a/tcg/optimize.c b/tcg/optimize.c index 8e5d918030..9109b813e0 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -484,10 +484,10 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, nb_globals = s->nb_globals; memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); - nb_ops = tcg_opc_ptr - gen_opc_buf; + nb_ops = tcg_opc_ptr - s->gen_opc_buf; gen_args = args; for (op_index = 0; op_index < nb_ops; op_index++) { - op = gen_opc_buf[op_index]; + op = s->gen_opc_buf[op_index]; def = &tcg_op_defs[op]; /* Do copy propagation */ if (op == INDEX_op_call) { @@ -569,7 +569,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(rotr): if (temps[args[1]].state == TCG_TEMP_CONST && temps[args[1]].val == 0) { - gen_opc_buf[op_index] = op_to_movi(op); + s->gen_opc_buf[op_index] = op_to_movi(op); tcg_opt_gen_movi(gen_args, args[0], 0); args += 3; gen_args += 2; @@ -598,9 +598,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, if (temps[args[2]].state == TCG_TEMP_CONST && temps[args[2]].val == 0) { if (temps_are_copies(args[0], args[1])) { - gen_opc_buf[op_index] = INDEX_op_nop; + s->gen_opc_buf[op_index] = INDEX_op_nop; } else { - gen_opc_buf[op_index] = op_to_mov(op); + s->gen_opc_buf[op_index] = op_to_mov(op); tcg_opt_gen_mov(s, gen_args, args[0], args[1]); gen_args += 2; } @@ -618,7 +618,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(mul): if ((temps[args[2]].state == TCG_TEMP_CONST && temps[args[2]].val == 0)) { - gen_opc_buf[op_index] = op_to_movi(op); + s->gen_opc_buf[op_index] = op_to_movi(op); tcg_opt_gen_movi(gen_args, args[0], 0); args += 3; gen_args += 2; @@ -635,9 +635,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(and): if (temps_are_copies(args[1], args[2])) { if (temps_are_copies(args[0], args[1])) { - gen_opc_buf[op_index] = INDEX_op_nop; + s->gen_opc_buf[op_index] = INDEX_op_nop; } else { - gen_opc_buf[op_index] = op_to_mov(op); + s->gen_opc_buf[op_index] = op_to_mov(op); tcg_opt_gen_mov(s, gen_args, args[0], args[1]); gen_args += 2; } @@ -654,7 +654,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(sub): CASE_OP_32_64(xor): if (temps_are_copies(args[1], args[2])) { - gen_opc_buf[op_index] = op_to_movi(op); + s->gen_opc_buf[op_index] = op_to_movi(op); tcg_opt_gen_movi(gen_args, args[0], 0); gen_args += 2; args += 3; @@ -672,7 +672,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(mov): if (temps_are_copies(args[0], args[1])) { args += 2; - gen_opc_buf[op_index] = INDEX_op_nop; + s->gen_opc_buf[op_index] = INDEX_op_nop; break; } if (temps[args[1]].state != TCG_TEMP_CONST) { @@ -684,7 +684,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, /* Source argument is constant. Rewrite the operation and let movi case handle it. */ op = op_to_movi(op); - gen_opc_buf[op_index] = op; + s->gen_opc_buf[op_index] = op; args[1] = temps[args[1]].val; /* fallthrough */ CASE_OP_32_64(movi): @@ -702,7 +702,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, case INDEX_op_ext32s_i64: case INDEX_op_ext32u_i64: if (temps[args[1]].state == TCG_TEMP_CONST) { - gen_opc_buf[op_index] = op_to_movi(op); + s->gen_opc_buf[op_index] = op_to_movi(op); tmp = do_constant_folding(op, temps[args[1]].val, 0); tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; @@ -729,7 +729,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(nor): if (temps[args[1]].state == TCG_TEMP_CONST && temps[args[2]].state == TCG_TEMP_CONST) { - gen_opc_buf[op_index] = op_to_movi(op); + s->gen_opc_buf[op_index] = op_to_movi(op); tmp = do_constant_folding(op, temps[args[1]].val, temps[args[2]].val); tcg_opt_gen_movi(gen_args, args[0], tmp); @@ -742,7 +742,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(deposit): if (temps[args[1]].state == TCG_TEMP_CONST && temps[args[2]].state == TCG_TEMP_CONST) { - gen_opc_buf[op_index] = op_to_movi(op); + s->gen_opc_buf[op_index] = op_to_movi(op); tmp = ((1ull << args[4]) - 1); tmp = (temps[args[1]].val & ~(tmp << args[3])) | ((temps[args[2]].val & tmp) << args[3]); @@ -756,7 +756,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(setcond): tmp = do_constant_folding_cond(op, args[1], args[2], args[3]); if (tmp != 2) { - gen_opc_buf[op_index] = op_to_movi(op); + s->gen_opc_buf[op_index] = op_to_movi(op); tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; args += 4; @@ -769,11 +769,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, if (tmp != 2) { if (tmp) { memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); - gen_opc_buf[op_index] = INDEX_op_br; + s->gen_opc_buf[op_index] = INDEX_op_br; gen_args[0] = args[3]; gen_args += 1; } else { - gen_opc_buf[op_index] = INDEX_op_nop; + s->gen_opc_buf[op_index] = INDEX_op_nop; } args += 4; break; @@ -784,13 +784,13 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, tmp = do_constant_folding_cond(op, args[1], args[2], args[5]); if (tmp != 2) { if (temps_are_copies(args[0], args[4-tmp])) { - gen_opc_buf[op_index] = INDEX_op_nop; + s->gen_opc_buf[op_index] = INDEX_op_nop; } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { - gen_opc_buf[op_index] = op_to_movi(op); + s->gen_opc_buf[op_index] = op_to_movi(op); tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val); gen_args += 2; } else { - gen_opc_buf[op_index] = op_to_mov(op); + s->gen_opc_buf[op_index] = op_to_mov(op); tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]); gen_args += 2; } @@ -820,12 +820,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, } /* We emit the extra nop when we emit the add2/sub2. */ - assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); rl = args[0]; rh = args[1]; - gen_opc_buf[op_index] = INDEX_op_movi_i32; - gen_opc_buf[++op_index] = INDEX_op_movi_i32; + s->gen_opc_buf[op_index] = INDEX_op_movi_i32; + s->gen_opc_buf[++op_index] = INDEX_op_movi_i32; tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)a); tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(a >> 32)); gen_args += 4; @@ -843,12 +843,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg rl, rh; /* We emit the extra nop when we emit the mulu2. */ - assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); rl = args[0]; rh = args[1]; - gen_opc_buf[op_index] = INDEX_op_movi_i32; - gen_opc_buf[++op_index] = INDEX_op_movi_i32; + s->gen_opc_buf[op_index] = INDEX_op_movi_i32; + s->gen_opc_buf[++op_index] = INDEX_op_movi_i32; tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)r); tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(r >> 32)); gen_args += 4; @@ -862,11 +862,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, if (tmp != 2) { if (tmp) { memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); - gen_opc_buf[op_index] = INDEX_op_br; + s->gen_opc_buf[op_index] = INDEX_op_br; gen_args[0] = args[5]; gen_args += 1; } else { - gen_opc_buf[op_index] = INDEX_op_nop; + s->gen_opc_buf[op_index] = INDEX_op_nop; } } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) && temps[args[2]].state == TCG_TEMP_CONST @@ -876,7 +876,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, /* Simplify LT/GE comparisons vs zero to a single compare vs the high word of the input. */ memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); - gen_opc_buf[op_index] = INDEX_op_brcond_i32; + s->gen_opc_buf[op_index] = INDEX_op_brcond_i32; gen_args[0] = args[1]; gen_args[1] = args[3]; gen_args[2] = args[4]; @@ -891,7 +891,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, case INDEX_op_setcond2_i32: tmp = do_constant_folding_cond2(&args[1], &args[3], args[5]); if (tmp != 2) { - gen_opc_buf[op_index] = INDEX_op_movi_i32; + s->gen_opc_buf[op_index] = INDEX_op_movi_i32; tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) @@ -901,7 +901,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, && temps[args[4]].val == 0) { /* Simplify LT/GE comparisons vs zero to a single compare vs the high word of the input. */ - gen_opc_buf[op_index] = INDEX_op_setcond_i32; + s->gen_opc_buf[op_index] = INDEX_op_setcond_i32; gen_args[0] = args[0]; gen_args[1] = args[2]; gen_args[2] = args[4]; diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 8d1da2b670..0b3cb0be3a 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -27,338 +27,338 @@ int gen_new_label(void); static inline void tcg_gen_op0(TCGOpcode opc) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; } static inline void tcg_gen_op1_i32(TCGOpcode opc, TCGv_i32 arg1) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); } static inline void tcg_gen_op1_i64(TCGOpcode opc, TCGv_i64 arg1) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); } static inline void tcg_gen_op1i(TCGOpcode opc, TCGArg arg1) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = arg1; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = arg1; } static inline void tcg_gen_op2_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); } static inline void tcg_gen_op2_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); } static inline void tcg_gen_op2i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGArg arg2) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = arg2; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = arg2; } static inline void tcg_gen_op2i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGArg arg2) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = arg2; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = arg2; } static inline void tcg_gen_op2ii(TCGOpcode opc, TCGArg arg1, TCGArg arg2) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = arg1; - *gen_opparam_ptr++ = arg2; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = arg1; + *tcg_ctx.gen_opparam_ptr++ = arg2; } static inline void tcg_gen_op3_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); } static inline void tcg_gen_op3_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); } static inline void tcg_gen_op3i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGArg arg3) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = arg3; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = arg3; } static inline void tcg_gen_op3i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGArg arg3) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = arg3; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = arg3; } static inline void tcg_gen_ldst_op_i32(TCGOpcode opc, TCGv_i32 val, TCGv_ptr base, TCGArg offset) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(val); - *gen_opparam_ptr++ = GET_TCGV_PTR(base); - *gen_opparam_ptr++ = offset; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(val); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_PTR(base); + *tcg_ctx.gen_opparam_ptr++ = offset; } static inline void tcg_gen_ldst_op_i64(TCGOpcode opc, TCGv_i64 val, TCGv_ptr base, TCGArg offset) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(val); - *gen_opparam_ptr++ = GET_TCGV_PTR(base); - *gen_opparam_ptr++ = offset; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(val); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_PTR(base); + *tcg_ctx.gen_opparam_ptr++ = offset; } static inline void tcg_gen_qemu_ldst_op_i64_i32(TCGOpcode opc, TCGv_i64 val, TCGv_i32 addr, TCGArg mem_index) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(val); - *gen_opparam_ptr++ = GET_TCGV_I32(addr); - *gen_opparam_ptr++ = mem_index; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(val); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(addr); + *tcg_ctx.gen_opparam_ptr++ = mem_index; } static inline void tcg_gen_qemu_ldst_op_i64_i64(TCGOpcode opc, TCGv_i64 val, TCGv_i64 addr, TCGArg mem_index) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(val); - *gen_opparam_ptr++ = GET_TCGV_I64(addr); - *gen_opparam_ptr++ = mem_index; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(val); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(addr); + *tcg_ctx.gen_opparam_ptr++ = mem_index; } static inline void tcg_gen_op4_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGv_i32 arg4) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); - *gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg4); } static inline void tcg_gen_op4_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGv_i64 arg4) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); - *gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg4); } static inline void tcg_gen_op4i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGArg arg4) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); - *gen_opparam_ptr++ = arg4; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opparam_ptr++ = arg4; } static inline void tcg_gen_op4i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGArg arg4) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); - *gen_opparam_ptr++ = arg4; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opparam_ptr++ = arg4; } static inline void tcg_gen_op4ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGArg arg3, TCGArg arg4) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = arg3; - *gen_opparam_ptr++ = arg4; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = arg3; + *tcg_ctx.gen_opparam_ptr++ = arg4; } static inline void tcg_gen_op4ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGArg arg3, TCGArg arg4) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = arg3; - *gen_opparam_ptr++ = arg4; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = arg3; + *tcg_ctx.gen_opparam_ptr++ = arg4; } static inline void tcg_gen_op5_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); - *gen_opparam_ptr++ = GET_TCGV_I32(arg4); - *gen_opparam_ptr++ = GET_TCGV_I32(arg5); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg5); } static inline void tcg_gen_op5_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); - *gen_opparam_ptr++ = GET_TCGV_I64(arg4); - *gen_opparam_ptr++ = GET_TCGV_I64(arg5); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg5); } static inline void tcg_gen_op5i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); - *gen_opparam_ptr++ = GET_TCGV_I32(arg4); - *gen_opparam_ptr++ = arg5; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *tcg_ctx.gen_opparam_ptr++ = arg5; } static inline void tcg_gen_op5i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); - *gen_opparam_ptr++ = GET_TCGV_I64(arg4); - *gen_opparam_ptr++ = arg5; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *tcg_ctx.gen_opparam_ptr++ = arg5; } static inline void tcg_gen_op5ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGArg arg4, TCGArg arg5) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); - *gen_opparam_ptr++ = arg4; - *gen_opparam_ptr++ = arg5; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opparam_ptr++ = arg4; + *tcg_ctx.gen_opparam_ptr++ = arg5; } static inline void tcg_gen_op5ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGArg arg4, TCGArg arg5) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); - *gen_opparam_ptr++ = arg4; - *gen_opparam_ptr++ = arg5; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opparam_ptr++ = arg4; + *tcg_ctx.gen_opparam_ptr++ = arg5; } static inline void tcg_gen_op6_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5, TCGv_i32 arg6) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); - *gen_opparam_ptr++ = GET_TCGV_I32(arg4); - *gen_opparam_ptr++ = GET_TCGV_I32(arg5); - *gen_opparam_ptr++ = GET_TCGV_I32(arg6); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg5); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg6); } static inline void tcg_gen_op6_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5, TCGv_i64 arg6) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); - *gen_opparam_ptr++ = GET_TCGV_I64(arg4); - *gen_opparam_ptr++ = GET_TCGV_I64(arg5); - *gen_opparam_ptr++ = GET_TCGV_I64(arg6); + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg5); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg6); } static inline void tcg_gen_op6i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGv_i32 arg4, TCGv_i32 arg5, TCGArg arg6) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); - *gen_opparam_ptr++ = GET_TCGV_I32(arg4); - *gen_opparam_ptr++ = GET_TCGV_I32(arg5); - *gen_opparam_ptr++ = arg6; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg5); + *tcg_ctx.gen_opparam_ptr++ = arg6; } static inline void tcg_gen_op6i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGv_i64 arg4, TCGv_i64 arg5, TCGArg arg6) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); - *gen_opparam_ptr++ = GET_TCGV_I64(arg4); - *gen_opparam_ptr++ = GET_TCGV_I64(arg5); - *gen_opparam_ptr++ = arg6; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg5); + *tcg_ctx.gen_opparam_ptr++ = arg6; } static inline void tcg_gen_op6ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGv_i32 arg4, TCGArg arg5, TCGArg arg6) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); - *gen_opparam_ptr++ = GET_TCGV_I32(arg3); - *gen_opparam_ptr++ = GET_TCGV_I32(arg4); - *gen_opparam_ptr++ = arg5; - *gen_opparam_ptr++ = arg6; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg4); + *tcg_ctx.gen_opparam_ptr++ = arg5; + *tcg_ctx.gen_opparam_ptr++ = arg6; } static inline void tcg_gen_op6ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGv_i64 arg4, TCGArg arg5, TCGArg arg6) { - *gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); - *gen_opparam_ptr++ = GET_TCGV_I64(arg3); - *gen_opparam_ptr++ = GET_TCGV_I64(arg4); - *gen_opparam_ptr++ = arg5; - *gen_opparam_ptr++ = arg6; + *tcg_ctx.gen_opc_ptr++ = opc; + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg3); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg4); + *tcg_ctx.gen_opparam_ptr++ = arg5; + *tcg_ctx.gen_opparam_ptr++ = arg6; } static inline void gen_set_label(int n) @@ -96,10 +96,6 @@ 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; -/* XXX: move that inside the context */ -uint16_t *gen_opc_ptr; -TCGArg *gen_opparam_ptr; - static inline void tcg_out8(TCGContext *s, uint8_t v) { *s->code_ptr++ = v; @@ -297,8 +293,8 @@ void tcg_func_start(TCGContext *s) s->goto_tb_issue_mask = 0; #endif - gen_opc_ptr = gen_opc_buf; - gen_opparam_ptr = gen_opparam_buf; + s->gen_opc_ptr = s->gen_opc_buf; + s->gen_opparam_ptr = s->gen_opparam_buf; #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) /* Initialize qemu_ld/st labels to assist code generation at the end of TB @@ -641,23 +637,23 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, } #endif /* TCG_TARGET_EXTEND_ARGS */ - *gen_opc_ptr++ = INDEX_op_call; - nparam = gen_opparam_ptr++; + *s->gen_opc_ptr++ = INDEX_op_call; + nparam = s->gen_opparam_ptr++; if (ret != TCG_CALL_DUMMY_ARG) { #if TCG_TARGET_REG_BITS < 64 if (sizemask & 1) { #ifdef TCG_TARGET_WORDS_BIGENDIAN - *gen_opparam_ptr++ = ret + 1; - *gen_opparam_ptr++ = ret; + *s->gen_opparam_ptr++ = ret + 1; + *s->gen_opparam_ptr++ = ret; #else - *gen_opparam_ptr++ = ret; - *gen_opparam_ptr++ = ret + 1; + *s->gen_opparam_ptr++ = ret; + *s->gen_opparam_ptr++ = ret + 1; #endif nb_rets = 2; } else #endif { - *gen_opparam_ptr++ = ret; + *s->gen_opparam_ptr++ = ret; nb_rets = 1; } } else { @@ -671,7 +667,7 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, #ifdef TCG_TARGET_CALL_ALIGN_ARGS /* some targets want aligned 64 bit args */ if (real_args & 1) { - *gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG; + *s->gen_opparam_ptr++ = TCG_CALL_DUMMY_ARG; real_args++; } #endif @@ -686,28 +682,28 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, have to get more complicated to differentiate between stack arguments and register arguments. */ #if defined(TCG_TARGET_WORDS_BIGENDIAN) != defined(TCG_TARGET_STACK_GROWSUP) - *gen_opparam_ptr++ = args[i] + 1; - *gen_opparam_ptr++ = args[i]; + *s->gen_opparam_ptr++ = args[i] + 1; + *s->gen_opparam_ptr++ = args[i]; #else - *gen_opparam_ptr++ = args[i]; - *gen_opparam_ptr++ = args[i] + 1; + *s->gen_opparam_ptr++ = args[i]; + *s->gen_opparam_ptr++ = args[i] + 1; #endif real_args += 2; continue; } #endif /* TCG_TARGET_REG_BITS < 64 */ - *gen_opparam_ptr++ = args[i]; + *s->gen_opparam_ptr++ = args[i]; real_args++; } - *gen_opparam_ptr++ = GET_TCGV_PTR(func); + *s->gen_opparam_ptr++ = GET_TCGV_PTR(func); - *gen_opparam_ptr++ = flags; + *s->gen_opparam_ptr++ = flags; *nparam = (nb_rets << 16) | (real_args + 1); /* total parameters, needed to go backward in the instruction stream */ - *gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; + *s->gen_opparam_ptr++ = 1 + nb_rets + real_args + 3; #if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64 for (i = 0; i < nargs; ++i) { @@ -896,9 +892,9 @@ void tcg_dump_ops(TCGContext *s) char buf[128]; first_insn = 1; - opc_ptr = gen_opc_buf; - args = gen_opparam_buf; - while (opc_ptr < gen_opc_ptr) { + opc_ptr = s->gen_opc_buf; + args = s->gen_opparam_buf; + while (opc_ptr < s->gen_opc_ptr) { c = *opc_ptr++; def = &tcg_op_defs[c]; if (c == INDEX_op_debug_insn_start) { @@ -1229,9 +1225,9 @@ static void tcg_liveness_analysis(TCGContext *s) uint16_t dead_args; uint8_t sync_args; - gen_opc_ptr++; /* skip end */ + s->gen_opc_ptr++; /* skip end */ - nb_ops = gen_opc_ptr - gen_opc_buf; + nb_ops = s->gen_opc_ptr - s->gen_opc_buf; s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t)); s->op_sync_args = tcg_malloc(nb_ops * sizeof(uint8_t)); @@ -1240,10 +1236,10 @@ static void tcg_liveness_analysis(TCGContext *s) mem_temps = tcg_malloc(s->nb_temps); tcg_la_func_end(s, dead_temps, mem_temps); - args = gen_opparam_ptr; + args = s->gen_opparam_ptr; op_index = nb_ops - 1; while (op_index >= 0) { - op = gen_opc_buf[op_index]; + op = s->gen_opc_buf[op_index]; def = &tcg_op_defs[op]; switch(op) { case INDEX_op_call: @@ -1266,7 +1262,7 @@ static void tcg_liveness_analysis(TCGContext *s) goto do_not_remove_call; } } - tcg_set_nop(s, gen_opc_buf + op_index, + tcg_set_nop(s, s->gen_opc_buf + op_index, args - 1, nb_args); } else { do_not_remove_call: @@ -1347,11 +1343,11 @@ static void tcg_liveness_analysis(TCGContext *s) } else { op = INDEX_op_sub_i32; } - gen_opc_buf[op_index] = op; + s->gen_opc_buf[op_index] = op; args[1] = args[2]; args[2] = args[4]; - assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); - tcg_set_nop(s, gen_opc_buf + op_index + 1, args + 3, 3); + assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); + tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 3); /* Fall through and mark the single-word operation live. */ nb_iargs = 2; nb_oargs = 1; @@ -1367,11 +1363,11 @@ static void tcg_liveness_analysis(TCGContext *s) if (dead_temps[args[0]] && !mem_temps[args[0]]) { goto do_remove; } - gen_opc_buf[op_index] = op = INDEX_op_mul_i32; + s->gen_opc_buf[op_index] = op = INDEX_op_mul_i32; args[1] = args[2]; args[2] = args[3]; - assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); - tcg_set_nop(s, gen_opc_buf + op_index + 1, args + 3, 1); + assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); + tcg_set_nop(s, s->gen_opc_buf + op_index + 1, args + 3, 1); /* Fall through and mark the single-word operation live. */ nb_oargs = 1; } @@ -1394,7 +1390,7 @@ static void tcg_liveness_analysis(TCGContext *s) } } do_remove: - tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); + tcg_set_nop(s, s->gen_opc_buf + op_index, args, def->nb_args); #ifdef CONFIG_PROFILER s->del_op_count++; #endif @@ -1440,15 +1436,16 @@ static void tcg_liveness_analysis(TCGContext *s) op_index--; } - if (args != gen_opparam_buf) + if (args != s->gen_opparam_buf) { tcg_abort(); + } } #else /* dummy liveness analysis */ static void tcg_liveness_analysis(TCGContext *s) { int nb_ops; - nb_ops = gen_opc_ptr - gen_opc_buf; + nb_ops = s->gen_opc_ptr - s->gen_opc_buf; s->op_dead_args = tcg_malloc(nb_ops * sizeof(uint16_t)); memset(s->op_dead_args, 0, nb_ops * sizeof(uint16_t)); @@ -2221,8 +2218,8 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, #endif #ifdef USE_TCG_OPTIMIZATIONS - gen_opparam_ptr = - tcg_optimize(s, gen_opc_ptr, gen_opparam_buf, tcg_op_defs); + s->gen_opparam_ptr = + tcg_optimize(s, s->gen_opc_ptr, s->gen_opparam_buf, tcg_op_defs); #endif #ifdef CONFIG_PROFILER @@ -2249,11 +2246,11 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, s->code_buf = gen_code_buf; s->code_ptr = gen_code_buf; - args = gen_opparam_buf; + args = s->gen_opparam_buf; op_index = 0; for(;;) { - opc = gen_opc_buf[op_index]; + opc = s->gen_opc_buf[op_index]; #ifdef CONFIG_PROFILER tcg_table_op_count[opc]++; #endif @@ -2334,7 +2331,7 @@ int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) #ifdef CONFIG_PROFILER { int n; - n = (gen_opc_ptr - gen_opc_buf); + n = (s->gen_opc_ptr - s->gen_opc_buf); s->op_count += n; if (n > s->op_count_max) s->op_count_max = n; @@ -450,6 +450,12 @@ struct TCGContext { int goto_tb_issue_mask; #endif + uint16_t gen_opc_buf[OPC_BUF_SIZE]; + TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; + + uint16_t *gen_opc_ptr; + TCGArg *gen_opparam_ptr; + #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) /* labels info for qemu_ld/st IRs The labels help to generate TLB miss case codes at the end of TB */ @@ -459,10 +465,6 @@ struct TCGContext { }; extern TCGContext tcg_ctx; -extern uint16_t *gen_opc_ptr; -extern TCGArg *gen_opparam_ptr; -extern uint16_t gen_opc_buf[]; -extern TCGArg gen_opparam_buf[]; /* pool based memory allocation */ diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c index e930740835..1707169ea8 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.c @@ -122,6 +122,9 @@ static const TCGTargetOpDef tcg_target_op_defs[] = { { INDEX_op_rotl_i32, { R, RI, RI } }, { INDEX_op_rotr_i32, { R, RI, RI } }, #endif +#if TCG_TARGET_HAS_deposit_i32 + { INDEX_op_deposit_i32, { R, "0", R } }, +#endif { INDEX_op_brcond_i32, { R, RI } }, @@ -200,6 +203,9 @@ static const TCGTargetOpDef tcg_target_op_defs[] = { { INDEX_op_rotl_i64, { R, RI, RI } }, { INDEX_op_rotr_i64, { R, RI, RI } }, #endif +#if TCG_TARGET_HAS_deposit_i64 + { INDEX_op_deposit_i64, { R, "0", R } }, +#endif { INDEX_op_brcond_i64, { R, RI } }, #if TCG_TARGET_HAS_ext8s_i64 @@ -653,6 +659,15 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out_ri32(s, const_args[1], args[1]); tcg_out_ri32(s, const_args[2], args[2]); break; + case INDEX_op_deposit_i32: /* Optional (TCG_TARGET_HAS_deposit_i32). */ + tcg_out_r(s, args[0]); + tcg_out_r(s, args[1]); + tcg_out_r(s, args[2]); + assert(args[3] <= UINT8_MAX); + tcg_out8(s, args[3]); + assert(args[4] <= UINT8_MAX); + tcg_out8(s, args[4]); + break; #if TCG_TARGET_REG_BITS == 64 case INDEX_op_mov_i64: @@ -680,6 +695,15 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, tcg_out_ri64(s, const_args[1], args[1]); tcg_out_ri64(s, const_args[2], args[2]); break; + case INDEX_op_deposit_i64: /* Optional (TCG_TARGET_HAS_deposit_i64). */ + tcg_out_r(s, args[0]); + tcg_out_r(s, args[1]); + tcg_out_r(s, args[2]); + assert(args[3] <= UINT8_MAX); + tcg_out8(s, args[3]); + assert(args[4] <= UINT8_MAX); + tcg_out8(s, args[4]); + break; case INDEX_op_div_i64: /* Optional (TCG_TARGET_HAS_div_i64). */ case INDEX_op_divu_i64: /* Optional (TCG_TARGET_HAS_div_i64). */ case INDEX_op_rem_i64: /* Optional (TCG_TARGET_HAS_div_i64). */ diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 37f28c0522..a832f5cf52 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -67,7 +67,7 @@ #define TCG_TARGET_HAS_ext8u_i32 1 #define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_andc_i32 0 -#define TCG_TARGET_HAS_deposit_i32 0 +#define TCG_TARGET_HAS_deposit_i32 1 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 @@ -81,7 +81,7 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_deposit_i64 0 +#define TCG_TARGET_HAS_deposit_i64 1 /* Not more than one of the next two defines must be 1. */ #define TCG_TARGET_HAS_div_i64 0 #define TCG_TARGET_HAS_div2_i64 0 @@ -689,6 +689,17 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) tci_write_reg32(t0, (t1 >> t2) | (t1 << (32 - t2))); break; #endif +#if TCG_TARGET_HAS_deposit_i32 + case INDEX_op_deposit_i32: + t0 = *tb_ptr++; + t1 = tci_read_r32(&tb_ptr); + t2 = tci_read_r32(&tb_ptr); + tmp16 = *tb_ptr++; + tmp8 = *tb_ptr++; + tmp32 = (((1 << tmp8) - 1) << tmp16); + tci_write_reg32(t0, (t1 & ~tmp32) | ((t2 << tmp16) & tmp32)); + break; +#endif case INDEX_op_brcond_i32: t0 = tci_read_r32(&tb_ptr); t1 = tci_read_ri32(&tb_ptr); @@ -936,6 +947,17 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) TODO(); break; #endif +#if TCG_TARGET_HAS_deposit_i64 + case INDEX_op_deposit_i64: + t0 = *tb_ptr++; + t1 = tci_read_r64(&tb_ptr); + t2 = tci_read_r64(&tb_ptr); + tmp16 = *tb_ptr++; + tmp8 = *tb_ptr++; + tmp64 = (((1ULL << tmp8) - 1) << tmp16); + tci_write_reg64(t0, (t1 & ~tmp64) | ((t2 << tmp16) & tmp64)); + break; +#endif case INDEX_op_brcond_i64: t0 = tci_read_r64(&tb_ptr); t1 = tci_read_ri64(&tb_ptr); diff --git a/tests/Makefile b/tests/Makefile index 9bf0765de3..ca680e5644 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -48,7 +48,7 @@ tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring. tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) qemu-tool.o -tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) iov.o +tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) iov.o libqemustub.a tests/test-iov$(EXESUF): tests/test-iov.o iov.o tests/test-qapi-types.c tests/test-qapi-types.h :\ @@ -81,7 +81,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS))) QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),)) check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y)) -qtest-obj-y = tests/libqtest.o $(oslib-obj-y) +qtest-obj-y = tests/libqtest.o $(oslib-obj-y) libqemustub.a $(check-qtest-y): $(qtest-obj-y) .PHONY: check-help diff --git a/tests/fdc-test.c b/tests/fdc-test.c index fa7441110d..4b0301da46 100644 --- a/tests/fdc-test.c +++ b/tests/fdc-test.c @@ -48,13 +48,17 @@ enum { enum { CMD_SENSE_INT = 0x08, + CMD_READ_ID = 0x0a, CMD_SEEK = 0x0f, + CMD_VERIFY = 0x16, CMD_READ = 0xe6, CMD_RELATIVE_SEEK_OUT = 0x8f, CMD_RELATIVE_SEEK_IN = 0xcf, }; enum { + BUSY = 0x10, + NONDMA = 0x20, RQM = 0x80, DIO = 0x40, @@ -110,7 +114,7 @@ static void ack_irq(uint8_t *pcn) g_assert(!get_irq(FLOPPY_IRQ)); } -static uint8_t send_read_command(void) +static uint8_t send_read_command(uint8_t cmd) { uint8_t drive = 0; uint8_t head = 0; @@ -126,7 +130,7 @@ static uint8_t send_read_command(void) uint8_t ret = 0; - floppy_send(CMD_READ); + floppy_send(cmd); floppy_send(head << 2 | drive); g_assert(!get_irq(FLOPPY_IRQ)); floppy_send(cyl); @@ -152,7 +156,70 @@ static uint8_t send_read_command(void) } st0 = floppy_recv(); - if (st0 != 0x60) { + if (st0 != 0x40) { + ret = 1; + } + + floppy_recv(); + floppy_recv(); + floppy_recv(); + floppy_recv(); + floppy_recv(); + floppy_recv(); + + return ret; +} + +static uint8_t send_read_no_dma_command(int nb_sect, uint8_t expected_st0) +{ + uint8_t drive = 0; + uint8_t head = 0; + uint8_t cyl = 0; + uint8_t sect_addr = 1; + uint8_t sect_size = 2; + uint8_t eot = nb_sect; + uint8_t gap = 0x1b; + uint8_t gpl = 0xff; + + uint8_t msr = 0; + uint8_t st0; + + uint8_t ret = 0; + + floppy_send(CMD_READ); + floppy_send(head << 2 | drive); + g_assert(!get_irq(FLOPPY_IRQ)); + floppy_send(cyl); + floppy_send(head); + floppy_send(sect_addr); + floppy_send(sect_size); + floppy_send(eot); + floppy_send(gap); + floppy_send(gpl); + + uint16_t i = 0; + uint8_t n = 2; + for (; i < n; i++) { + msr = inb(FLOPPY_BASE + reg_msr); + if (msr == (BUSY | NONDMA | DIO | RQM)) { + break; + } + sleep(1); + } + + if (i >= n) { + return 1; + } + + /* Non-DMA mode */ + for (i = 0; i < 512 * 2 * nb_sect; i++) { + msr = inb(FLOPPY_BASE + reg_msr); + assert_bit_set(msr, BUSY | RQM | DIO); + inb(FLOPPY_BASE + reg_fifo); + } + + st0 = floppy_recv(); + if (st0 != expected_st0) { ret = 1; } @@ -213,11 +280,11 @@ static void test_read_without_media(void) { uint8_t ret; - ret = send_read_command(); + ret = send_read_command(CMD_READ); g_assert(ret == 0); } -static void test_media_change(void) +static void test_media_insert(void) { uint8_t dir; @@ -245,6 +312,13 @@ static void test_media_change(void) assert_bit_clear(dir, DSKCHG); dir = inb(FLOPPY_BASE + reg_dir); assert_bit_clear(dir, DSKCHG); +} + +static void test_media_change(void) +{ + uint8_t dir; + + test_media_insert(); /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't * reset the bit. */ @@ -320,6 +394,108 @@ static void test_relative_seek(void) g_assert(pcn == 0); } +static void test_read_id(void) +{ + uint8_t drive = 0; + uint8_t head = 0; + uint8_t cyl; + uint8_t st0; + + /* Seek to track 0 and check with READ ID */ + send_seek(0); + + floppy_send(CMD_READ_ID); + g_assert(!get_irq(FLOPPY_IRQ)); + floppy_send(head << 2 | drive); + + while (!get_irq(FLOPPY_IRQ)) { + /* qemu involves a timer with READ ID... */ + clock_step(1000000000LL / 50); + } + + st0 = floppy_recv(); + floppy_recv(); + floppy_recv(); + cyl = floppy_recv(); + head = floppy_recv(); + floppy_recv(); + floppy_recv(); + + g_assert_cmpint(cyl, ==, 0); + g_assert_cmpint(head, ==, 0); + g_assert_cmpint(st0, ==, head << 2); + + /* Seek to track 8 on head 1 and check with READ ID */ + head = 1; + cyl = 8; + + floppy_send(CMD_SEEK); + floppy_send(head << 2 | drive); + g_assert(!get_irq(FLOPPY_IRQ)); + floppy_send(cyl); + g_assert(get_irq(FLOPPY_IRQ)); + ack_irq(NULL); + + floppy_send(CMD_READ_ID); + g_assert(!get_irq(FLOPPY_IRQ)); + floppy_send(head << 2 | drive); + + while (!get_irq(FLOPPY_IRQ)) { + /* qemu involves a timer with READ ID... */ + clock_step(1000000000LL / 50); + } + + st0 = floppy_recv(); + floppy_recv(); + floppy_recv(); + cyl = floppy_recv(); + head = floppy_recv(); + floppy_recv(); + floppy_recv(); + + g_assert_cmpint(cyl, ==, 8); + g_assert_cmpint(head, ==, 1); + g_assert_cmpint(st0, ==, head << 2); +} + +static void test_read_no_dma_1(void) +{ + uint8_t ret; + + outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08); + send_seek(0); + ret = send_read_no_dma_command(1, 0x04); + g_assert(ret == 0); +} + +static void test_read_no_dma_18(void) +{ + uint8_t ret; + + outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08); + send_seek(0); + ret = send_read_no_dma_command(18, 0x04); + g_assert(ret == 0); +} + +static void test_read_no_dma_19(void) +{ + uint8_t ret; + + outb(FLOPPY_BASE + reg_dor, inb(FLOPPY_BASE + reg_dor) & ~0x08); + send_seek(0); + ret = send_read_no_dma_command(19, 0x20); + g_assert(ret == 0); +} + +static void test_verify(void) +{ + uint8_t ret; + + ret = send_read_command(CMD_VERIFY); + g_assert(ret == 0); +} + /* success if no crash or abort */ static void fuzz_registers(void) { @@ -369,6 +545,12 @@ int main(int argc, char **argv) qtest_add_func("/fdc/media_change", test_media_change); qtest_add_func("/fdc/sense_interrupt", test_sense_interrupt); qtest_add_func("/fdc/relative_seek", test_relative_seek); + qtest_add_func("/fdc/read_id", test_read_id); + qtest_add_func("/fdc/verify", test_verify); + qtest_add_func("/fdc/media_insert", test_media_insert); + qtest_add_func("/fdc/read_no_dma_1", test_read_no_dma_1); + qtest_add_func("/fdc/read_no_dma_18", test_read_no_dma_18); + qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19); qtest_add_func("/fdc/fuzz-registers", fuzz_registers); ret = g_test_run(); diff --git a/tests/qemu-iotests/044 b/tests/qemu-iotests/044 new file mode 100755 index 0000000000..11ea0f4d35 --- /dev/null +++ b/tests/qemu-iotests/044 @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# +# Tests growing a large refcount table. +# +# Copyright (C) 2012 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/>. +# + +import time +import os +import qcow2 +from qcow2 import QcowHeader +import iotests +from iotests import qemu_img, qemu_img_verbose, qemu_io +import struct +import subprocess + +test_img = os.path.join(iotests.test_dir, 'test.img') + +class TestRefcountTableGrowth(iotests.QMPTestCase): + '''Abstract base class for image mirroring test cases''' + + def preallocate(self, name): + fd = open(name, "r+b") + try: + off_reftable = 512 + off_refblock = off_reftable + (512 * 512) + off_l1 = off_refblock + (512 * 512 * 64) + off_l2 = off_l1 + (512 * 512 * 4 * 8) + off_data = off_l2 + (512 * 512 * 4 * 512) + + # Write a new header + h = QcowHeader(fd) + h.refcount_table_offset = off_reftable + h.refcount_table_clusters = 512 + h.l1_table_offset = off_l1 + h.l1_size = 512 * 512 * 4 + h.update(fd) + + # Write a refcount table + fd.seek(off_reftable) + + for i in xrange(0, h.refcount_table_clusters): + sector = ''.join(struct.pack('>Q', + off_refblock + i * 64 * 512 + j * 512) + for j in xrange(0, 64)) + fd.write(sector) + + # Write the refcount blocks + assert(fd.tell() == off_refblock) + sector = ''.join(struct.pack('>H', 1) for j in xrange(0, 64 * 256)) + for block in xrange(0, h.refcount_table_clusters): + fd.write(sector) + + # Write the L1 table + assert(fd.tell() == off_l1) + assert(off_l2 + 512 * h.l1_size == off_data) + table = ''.join(struct.pack('>Q', (1 << 63) | off_l2 + 512 * j) + for j in xrange(0, h.l1_size)) + fd.write(table) + + # Write the L2 tables + assert(fd.tell() == off_l2) + img_file_size = h.refcount_table_clusters * 64 * 256 * 512 + remaining = img_file_size - off_data + + off = off_data + while remaining > 1024 * 512: + pytable = list((1 << 63) | off + 512 * j + for j in xrange(0, 1024)) + table = struct.pack('>1024Q', *pytable) + fd.write(table) + remaining = remaining - 1024 * 512 + off = off + 1024 * 512 + + table = ''.join(struct.pack('>Q', (1 << 63) | off + 512 * j) + for j in xrange(0, remaining / 512)) + fd.write(table) + + + # Data + fd.truncate(img_file_size) + + + finally: + fd.close() + + + def setUp(self): + qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=512', test_img, '16G') + self.preallocate(test_img) + pass + + + def tearDown(self): + os.remove(test_img) + pass + + def test_grow_refcount_table(self): + qemu_io('-c', 'write 3800M 1M', test_img) + qemu_img_verbose('check' , test_img) + pass + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2']) diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out new file mode 100644 index 0000000000..7a4007137d --- /dev/null +++ b/tests/qemu-iotests/044.out @@ -0,0 +1,6 @@ +No errors were found on the image. +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common index 1f6fdf5c56..b3aad89e2c 100644 --- a/tests/qemu-iotests/common +++ b/tests/qemu-iotests/common @@ -136,6 +136,7 @@ check options -vmdk test vmdk -rbd test rbd -sheepdog test sheepdog + -nbd test nbd -xdiff graphical mode diff -nocache use O_DIRECT on backing file -misalign misalign memory allocations @@ -197,12 +198,14 @@ testlist options IMGPROTO=rbd xpand=false ;; - -sheepdog) IMGPROTO=sheepdog xpand=false ;; - + -nbd) + IMGPROTO=nbd + xpand=false + ;; -nocache) QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --nocache" xpand=false @@ -350,7 +353,11 @@ fi [ "$QEMU" = "" ] && _fatal "qemu not found" [ "$QEMU_IMG" = "" ] && _fatal "qemu-img not found" -[ "$QEMU_IO" = "" ] && _fatal "qemu-img not found" +[ "$QEMU_IO" = "" ] && _fatal "qemu-io not found" + +if [ "$IMGPROTO" = "nbd" ] ; then + [ "$QEMU_NBD" = "" ] && _fatal "qemu-nbd not found" +fi if $valgrind; then export REAL_QEMU_IO="$QEMU_IO_PROG" diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config index df082e750c..08a3f100b8 100644 --- a/tests/qemu-iotests/common.config +++ b/tests/qemu-iotests/common.config @@ -90,21 +90,23 @@ export PS_ALL_FLAGS="-ef" if [ -z "$QEMU_PROG" ]; then export QEMU_PROG="`set_prog_path qemu`" fi -[ "$QEMU_PROG" = "" ] && _fatal "qemu not found" if [ -z "$QEMU_IMG_PROG" ]; then export QEMU_IMG_PROG="`set_prog_path qemu-img`" fi -[ "$QEMU_IMG_PROG" = "" ] && _fatal "qemu-img not found" if [ -z "$QEMU_IO_PROG" ]; then export QEMU_IO_PROG="`set_prog_path qemu-io`" fi -[ "$QEMU_IO_PROG" = "" ] && _fatal "qemu-io not found" + +if [ -z "$QEMU_NBD_PROG" ]; then + export QEMU_NBD_PROG="`set_prog_path qemu-nbd`" +fi export QEMU=$QEMU_PROG -export QEMU_IMG=$QEMU_IMG_PROG +export QEMU_IMG=$QEMU_IMG_PROG export QEMU_IO="$QEMU_IO_PROG $QEMU_IO_OPTIONS" +export QEMU_NBD=$QEMU_NBD_PROG [ -f /etc/qemu-iotest.config ] && . /etc/qemu-iotest.config diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 334534f22c..aef5f52b4f 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -49,6 +49,9 @@ umask 022 if [ "$IMGPROTO" = "file" ]; then TEST_IMG=$TEST_DIR/t.$IMGFMT +elif [ "$IMGPROTO" = "nbd" ]; then + TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT + TEST_IMG="nbd:127.0.0.1:10810" else TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT fi @@ -86,6 +89,13 @@ _make_test_img() local extra_img_options="" local image_size=$* local optstr="" + local img_name="" + + if [ -n "$TEST_IMG_FILE" ]; then + img_name=$TEST_IMG_FILE + else + img_name=$TEST_IMG + fi if [ -n "$IMGOPTS" ]; then optstr=$(_optstr_add "$optstr" "$IMGOPTS") @@ -104,7 +114,7 @@ _make_test_img() fi # XXX(hch): have global image options? - $QEMU_IMG create -f $IMGFMT $extra_img_options $TEST_IMG $image_size | \ + $QEMU_IMG create -f $IMGFMT $extra_img_options $img_name $image_size | \ sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ -e "s#$TEST_DIR#TEST_DIR#g" \ -e "s#$IMGFMT#IMGFMT#g" \ @@ -115,12 +125,23 @@ _make_test_img() -e "s# compat6=\\(on\\|off\\)##g" \ -e "s# static=\\(on\\|off\\)##g" \ -e "s# lazy_refcounts=\\(on\\|off\\)##g" + + # Start an NBD server on the image file, which is what we'll be talking to + if [ $IMGPROTO = "nbd" ]; then + eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 $TEST_IMG_FILE &" + QEMU_NBD_PID=$! + sleep 1 # FIXME: qemu-nbd needs to be listening before we continue + fi } _cleanup_test_img() { case "$IMGPROTO" in + nbd) + kill $QEMU_NBD_PID + rm -f $TEST_IMG_FILE + ;; file) rm -f $TEST_DIR/t.$IMGFMT rm -f $TEST_DIR/t.$IMGFMT.orig diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index ac86f54ae3..a4a9044f24 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -50,3 +50,4 @@ 041 rw auto backing 042 rw auto quick 043 rw auto backing +044 rw auto diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 735c6745d7..b2eaf20f0b 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -42,6 +42,10 @@ def qemu_img(*args): devnull = open('/dev/null', 'r+') return subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull) +def qemu_img_verbose(*args): + '''Run qemu-img without supressing its output and return the exit code''' + return subprocess.call(qemu_img_args + list(args)) + def qemu_io(*args): '''Run qemu-io and return the stdout data''' args = qemu_io_args + list(args) @@ -182,4 +186,4 @@ def main(supported_fmts=[]): try: unittest.main(testRunner=MyTestRunner) finally: - sys.stderr.write(re.sub(r'Ran (\d+) test[s] in [\d.]+s', r'Ran \1 tests', output.getvalue())) + sys.stderr.write(re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', output.getvalue())) diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index 97f37707bc..fecf5b9a59 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -233,8 +233,9 @@ def usage(): for name, handler, num_args, desc in cmds: print " %-20s - %s" % (name, desc) -if len(sys.argv) < 3: - usage() - sys.exit(1) +if __name__ == '__main__': + if len(sys.argv) < 3: + usage() + sys.exit(1) -main(sys.argv[1], sys.argv[2], sys.argv[3:]) + main(sys.argv[1], sys.argv[2], sys.argv[3:]) diff --git a/thread-pool.c b/thread-pool.c index 651b32419b..204f70b7b5 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -216,7 +216,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb) qemu_mutex_unlock(&lock); } -static AIOPool thread_pool_cb_pool = { +static const AIOCBInfo thread_pool_aiocb_info = { .aiocb_size = sizeof(ThreadPoolElement), .cancel = thread_pool_cancel, }; @@ -226,7 +226,7 @@ BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, { ThreadPoolElement *req; - req = qemu_aio_get(&thread_pool_cb_pool, NULL, cb, opaque); + req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque); req->func = func; req->arg = arg; req->state = THREAD_QUEUED; diff --git a/trace-events b/trace-events index e1a37cc26f..6c6cbf10fd 100644 --- a/trace-events +++ b/trace-events @@ -286,6 +286,7 @@ usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "lev usb_ehci_guest_bug(const char *reason) "%s" usb_ehci_doorbell_ring(void) "" usb_ehci_doorbell_ack(void) "" +usb_ehci_dma_error(void) "" # hw/usb/hcd-uhci.c usb_uhci_reset(void) "=== RESET ===" @@ -408,7 +409,7 @@ usb_host_claim_interfaces(int bus, int addr, int config, int nif) "dev %d:%d, co usb_host_release_interfaces(int bus, int addr) "dev %d:%d" usb_host_req_control(int bus, int addr, void *p, int req, int value, int index) "dev %d:%d, packet %p, req 0x%x, value %d, index %d" usb_host_req_data(int bus, int addr, void *p, int in, int ep, int size) "dev %d:%d, packet %p, in %d, ep %d, size %d" -usb_host_req_complete(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d" +usb_host_req_complete(int bus, int addr, void *p, int status, int length) "dev %d:%d, packet %p, status %d, length %d" usb_host_req_emulated(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d" usb_host_req_canceled(int bus, int addr, void *p) "dev %d:%d, packet %p" usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d" diff --git a/trace/control.c b/trace/control.c index 22d5863eeb..be05efb99b 100644 --- a/trace/control.c +++ b/trace/control.c @@ -12,6 +12,8 @@ void trace_backend_init_events(const char *fname) { + int ret; + if (fname == NULL) { return; } @@ -30,7 +32,12 @@ void trace_backend_init_events(const char *fname) if ('#' == line_buf[0]) { /* skip commented lines */ continue; } - if (!trace_event_set_state(line_buf, true)) { + if ('-' == line_buf[0]) { + ret = trace_event_set_state(line_buf+1, false); + } else { + ret = trace_event_set_state(line_buf, true); + } + if (!ret) { fprintf(stderr, "error: trace event '%s' does not exist\n", line_buf); exit(1); diff --git a/translate-all.c b/translate-all.c index 5bd2d3711a..d9c2e57861 100644 --- a/translate-all.c +++ b/translate-all.c @@ -33,9 +33,6 @@ /* code generation context */ TCGContext tcg_ctx; -uint16_t gen_opc_buf[OPC_BUF_SIZE]; -TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; - target_ulong gen_opc_pc[OPC_BUF_SIZE]; uint16_t gen_opc_icount[OPC_BUF_SIZE]; uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; diff --git a/ui/vnc-palette.h b/ui/vnc-palette.h index 3260885ff0..b82dc5db91 100644 --- a/ui/vnc-palette.h +++ b/ui/vnc-palette.h @@ -32,6 +32,7 @@ #include "qlist.h" #include "qemu-queue.h" #include <stdint.h> +#include <stdbool.h> #define VNC_PALETTE_HASH_SIZE 256 #define VNC_PALETTE_MAX_SIZE 256 @@ -168,6 +168,7 @@ int main(int argc, char **argv) #include "osdep.h" #include "ui/qemu-spice.h" +#include "qapi/string-input-visitor.h" //#define DEBUG_NET //#define DEBUG_SLIRP @@ -2476,6 +2477,53 @@ static void free_and_trace(gpointer mem) free(mem); } +static int object_set_property(const char *name, const char *value, void *opaque) +{ + Object *obj = OBJECT(opaque); + StringInputVisitor *siv; + Error *local_err = NULL; + + if (strcmp(name, "qom-type") == 0 || strcmp(name, "id") == 0) { + return 0; + } + + siv = string_input_visitor_new(value); + object_property_set(obj, string_input_get_visitor(siv), name, &local_err); + string_input_visitor_cleanup(siv); + + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return -1; + } + + return 0; +} + +static int object_create(QemuOpts *opts, void *opaque) +{ + const char *type = qemu_opt_get(opts, "qom-type"); + const char *id = qemu_opts_id(opts); + Object *obj; + + g_assert(type != NULL); + + if (id == NULL) { + qerror_report(QERR_MISSING_PARAMETER, "id"); + return -1; + } + + obj = object_new(type); + if (qemu_opt_foreach(opts, object_set_property, obj, 1) < 0) { + return -1; + } + + object_property_add_child(container_get(object_get_root(), "/objects"), + id, obj, NULL); + + return 0; +} + int main(int argc, char **argv, char **envp) { int i; @@ -3473,6 +3521,9 @@ int main(int argc, char **argv, char **envp) exit(1); #endif break; + case QEMU_OPTION_object: + opts = qemu_opts_parse(qemu_find_opts("object"), optarg, 1); + break; default: os_parse_cmd_args(popt->index, optarg); } @@ -3508,6 +3559,11 @@ int main(int argc, char **argv, char **envp) qemu_set_version(machine->hw_version); } + if (qemu_opts_foreach(qemu_find_opts("object"), + object_create, NULL, 0) != 0) { + exit(1); + } + /* Init CPU def lists, based on config * - Must be called after all the qemu_read_config_file() calls * - Must be called before list_cpus() |