From 48f4ba671bbb3dd212002d57b72a23375f51619b Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Mon, 15 Oct 2012 14:54:03 +0200 Subject: [PATCH 01/67] hw/qxl: guest bug on primary create with stride %4 != 0 Due to usage of pixman for rendering on all spice surfaces we have pixman's requirement that the stride be word aligned. A guest not honoring that can crash spice and qemu with it due to failure to create a surface (in spice-server). Avoid this early on in primary surface creation and offscreen surface creation. Recently windows guests got odd width support which triggers a non word aligned primary surface in 16bit color depth. Off screen surfaces have always been word aligned, but doesn't hurt to check them here too. Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/qxl.c b/hw/qxl.c index 1f56fcd169..cc16eaf2aa 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -447,6 +447,12 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) qxl->ssd.num_surfaces); return 1; } + if (cmd->type == QXL_SURFACE_CMD_CREATE && + (cmd->u.surface_create.stride & 0x03) != 0) { + qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n", + cmd->u.surface_create.stride); + return 1; + } qemu_mutex_lock(&qxl->track_lock); if (cmd->type == QXL_SURFACE_CMD_CREATE) { qxl->guest_surfaces.cmds[id] = ext->cmd.data; @@ -1357,6 +1363,12 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type, sc->flags); + if ((surface.stride & 0x3) != 0) { + qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0", + surface.stride); + return; + } + surface.mouse_mode = true; surface.group_id = MEMSLOT_GROUP_GUEST; if (loadvm) { From 511aefb0c60e3063ead76d4ba6aabf619eed18ef Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Thu, 1 Nov 2012 14:56:00 +0200 Subject: [PATCH 02/67] hw/qxl: qxl_send_events: nop if stopped Added a trace point for easy logging. RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=870972 Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 8 +++++++- trace-events | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/qxl.c b/hw/qxl.c index cc16eaf2aa..f19451bd6f 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1701,7 +1701,13 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) uint32_t le_events = cpu_to_le32(events); trace_qxl_send_events(d->id, events); - assert(qemu_spice_display_is_running(&d->ssd)); + if (!qemu_spice_display_is_running(&d->ssd)) { + /* spice-server tracks guest running state and should not do this */ + fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n", + __func__); + trace_qxl_send_events_vm_stopped(d->id, events); + return; + } old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); if ((old_pending & le_events) == le_events) { return; diff --git a/trace-events b/trace-events index b84d631dc7..e1a37cc26f 100644 --- a/trace-events +++ b/trace-events @@ -1001,6 +1001,7 @@ qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t righ qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" qxl_send_events(int qid, uint32_t events) "%d %d" +qxl_send_events_vm_stopped(int qid, uint32_t events) "%d %d" qxl_set_guest_bug(int qid) "%d" qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p" qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p" From 958c2bceba06696e9c223498aaf81d06ce95f608 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 14 Sep 2012 22:17:44 +0200 Subject: [PATCH 03/67] qxl: fix cursor reset When resetting the qxl cursor notify the qemu displaystate too. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/qxl.c b/hw/qxl.c index f19451bd6f..063970dc28 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -293,6 +293,10 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl) qemu_mutex_lock(&qxl->track_lock); qxl->guest_cursor = 0; qemu_mutex_unlock(&qxl->track_lock); + if (qxl->ssd.cursor) { + cursor_put(qxl->ssd.cursor); + } + qxl->ssd.cursor = cursor_builtin_hidden(); } From e32c25b5f2452c7fed4dbe8962f4a9f4831fbe24 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 30 Oct 2012 14:55:12 +0100 Subject: [PATCH 04/67] qxl: call dpy_gfx_resize when entering vga mode When entering vga mode the display size likely changes, notify all displaychangelisteners about this. Probably went unnoticed for a while as one if the first things the guest does after leaving qxl native mode and entering qxl vga mode is to set the vga video mode. But there is still a small window where qemu can operate on stale data, leading to crashes now and then. https://bugzilla.redhat.com/show_bug.cgi?id=865767 Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/qxl.c b/hw/qxl.c index 063970dc28..e7bf3a11a7 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1069,7 +1069,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) trace_qxl_enter_vga_mode(d->id); qemu_spice_create_host_primary(&d->ssd); d->mode = QXL_MODE_VGA; - memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); + dpy_gfx_resize(d->ssd.ds); vga_dirty_log_start(&d->vga); } From d9a86569ca3617a495ffb352e9a390747eaa6b24 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 2 Nov 2012 09:12:49 +0100 Subject: [PATCH 05/67] spice: switch to pixman Switch over spice-display.c to use the pixman library instead of the home-grown pflib bits. Signed-off-by: Gerd Hoffmann --- console.h | 5 +++++ qemu-pixman.c | 13 ++++++++++++ qemu-pixman.h | 2 ++ ui/spice-display.c | 51 ++++++++++++++++++++-------------------------- ui/spice-display.h | 7 +++---- 5 files changed, 45 insertions(+), 33 deletions(-) diff --git a/console.h b/console.h index 70c9a55942..50a0512f32 100644 --- a/console.h +++ b/console.h @@ -377,6 +377,11 @@ static inline pixman_format_code_t ds_get_format(DisplayState *ds) return ds->surface->format; } +static inline pixman_image_t *ds_get_image(DisplayState *ds) +{ + return ds->surface->image; +} + static inline int ds_get_depth(DisplayState *ds) { return ds->surface->pf.depth; diff --git a/qemu-pixman.c b/qemu-pixman.c index 7547ed74c1..71a9ea43a6 100644 --- a/qemu-pixman.c +++ b/qemu-pixman.c @@ -51,6 +51,19 @@ void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, 0, y, 0, 0, 0, 0, width, 1); } +pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format, + pixman_image_t *image) +{ + pixman_image_t *mirror; + + mirror = pixman_image_create_bits(format, + pixman_image_get_width(image), + pixman_image_get_height(image), + NULL, + pixman_image_get_stride(image)); + return mirror; +} + void qemu_pixman_image_unref(pixman_image_t *image) { if (image == NULL) { diff --git a/qemu-pixman.h b/qemu-pixman.h index 7652c41277..e267d73683 100644 --- a/qemu-pixman.h +++ b/qemu-pixman.h @@ -27,6 +27,8 @@ pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format, int width); void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, int width, int y); +pixman_image_t *qemu_pixman_mirror_create(pixman_format_code_t format, + pixman_image_t *image); void qemu_pixman_image_unref(pixman_image_t *image); #endif /* QEMU_PIXMAN_H */ diff --git a/ui/spice-display.c b/ui/spice-display.c index fb99148349..fe2fdfba68 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -150,9 +150,9 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, QXLDrawable *drawable; QXLImage *image; QXLCommand *cmd; - uint8_t *src, *mirror, *dst; - int by, bw, bh, offset, bytes; + int bw, bh; struct timespec time_space; + pixman_image_t *dest; trace_qemu_spice_create_update( rect->left, rect->right, @@ -195,20 +195,15 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, image->bitmap.palette = 0; image->bitmap.format = SPICE_BITMAP_FMT_32BIT; - offset = - rect->top * ds_get_linesize(ssd->ds) + - rect->left * ds_get_bytes_per_pixel(ssd->ds); - bytes = ds_get_bytes_per_pixel(ssd->ds) * bw; - src = ds_get_data(ssd->ds) + offset; - mirror = ssd->ds_mirror + offset; - dst = update->bitmap; - for (by = 0; by < bh; by++) { - memcpy(mirror, src, bytes); - qemu_pf_conv_run(ssd->conv, dst, mirror, bw); - src += ds_get_linesize(ssd->ds); - mirror += ds_get_linesize(ssd->ds); - dst += image->bitmap.stride; - } + dest = pixman_image_create_bits(PIXMAN_x8r8g8b8, bw, bh, + (void *)update->bitmap, bw * 4); + pixman_image_composite(PIXMAN_OP_SRC, ssd->surface, NULL, ssd->mirror, + rect->left, rect->top, 0, 0, + rect->left, rect->top, bw, bh); + pixman_image_composite(PIXMAN_OP_SRC, ssd->mirror, NULL, dest, + rect->left, rect->top, 0, 0, + 0, 0, bw, bh); + pixman_image_unref(dest); cmd->type = QXL_CMD_DRAW; cmd->data = (uintptr_t)drawable; @@ -229,14 +224,10 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) return; }; - if (ssd->conv == NULL) { - PixelFormat dst = qemu_default_pixelformat(32); - ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); - assert(ssd->conv); - } - if (ssd->ds_mirror == NULL) { - int size = ds_get_height(ssd->ds) * ds_get_linesize(ssd->ds); - ssd->ds_mirror = g_malloc0(size); + if (ssd->surface == NULL) { + ssd->surface = pixman_image_ref(ds_get_image(ssd->ds)); + ssd->mirror = qemu_pixman_mirror_create(ds_get_format(ssd->ds), + ds_get_image(ssd->ds)); } for (blk = 0; blk < blocks; blk++) { @@ -244,7 +235,7 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) } guest = ds_get_data(ssd->ds); - mirror = ssd->ds_mirror; + mirror = (void *)pixman_image_get_data(ssd->mirror); for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { yoff = y * ds_get_linesize(ssd->ds); for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { @@ -383,10 +374,12 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) dprint(1, "%s:\n", __FUNCTION__); memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - qemu_pf_conv_put(ssd->conv); - ssd->conv = NULL; - g_free(ssd->ds_mirror); - ssd->ds_mirror = NULL; + if (ssd->surface) { + pixman_image_unref(ssd->surface); + ssd->surface = NULL; + pixman_image_unref(ssd->mirror); + ssd->mirror = NULL; + } qemu_mutex_lock(&ssd->lock); while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { diff --git a/ui/spice-display.h b/ui/spice-display.h index d7669277fd..38b6ea98b3 100644 --- a/ui/spice-display.h +++ b/ui/spice-display.h @@ -20,8 +20,7 @@ #include #include "qemu-thread.h" -#include "console.h" -#include "pflib.h" +#include "qemu-pixman.h" #include "sysemu.h" #define NUM_MEMSLOTS 8 @@ -72,13 +71,13 @@ typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; struct SimpleSpiceDisplay { DisplayState *ds; - uint8_t *ds_mirror; void *buf; int bufsize; QXLWorker *worker; QXLInstance qxl; uint32_t unique; - QemuPfConv *conv; + pixman_image_t *surface; + pixman_image_t *mirror; int32_t num_surfaces; QXLRect dirty; From 365b1e9e3486aaa55f30df6f16ecafffaef6ec98 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 18 Sep 2012 08:52:26 +0200 Subject: [PATCH 06/67] pflib: unused, remove it. Replaced by pixman library. Signed-off-by: Gerd Hoffmann --- Makefile.objs | 1 - pflib.c | 215 -------------------------------------------------- pflib.h | 20 ----- 3 files changed, 236 deletions(-) delete mode 100644 pflib.c delete mode 100644 pflib.h diff --git a/Makefile.objs b/Makefile.objs index 593a59267c..37be7e26f7 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -78,7 +78,6 @@ common-obj-y += input.o common-obj-y += buffered_file.o migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o common-obj-y += block-migration.o iohandler.o -common-obj-y += pflib.o common-obj-y += bitmap.o bitops.o common-obj-y += page_cache.o diff --git a/pflib.c b/pflib.c deleted file mode 100644 index 987e11001a..0000000000 --- a/pflib.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * PixelFormat conversion library. - * - * Author: Gerd Hoffmann - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "qemu-common.h" -#include "console.h" -#include "pflib.h" - -typedef struct QemuPixel QemuPixel; - -typedef void (*pf_convert)(QemuPfConv *conv, - void *dst, void *src, uint32_t cnt); -typedef void (*pf_convert_from)(PixelFormat *pf, - QemuPixel *dst, void *src, uint32_t cnt); -typedef void (*pf_convert_to)(PixelFormat *pf, - void *dst, QemuPixel *src, uint32_t cnt); - -struct QemuPfConv { - pf_convert convert; - PixelFormat src; - PixelFormat dst; - - /* for copy_generic() */ - pf_convert_from conv_from; - pf_convert_to conv_to; - QemuPixel *conv_buf; - uint32_t conv_cnt; -}; - -struct QemuPixel { - uint8_t red; - uint8_t green; - uint8_t blue; - uint8_t alpha; -}; - -/* ----------------------------------------------------------------------- */ -/* PixelFormat -> QemuPixel conversions */ - -static void conv_16_to_pixel(PixelFormat *pf, - QemuPixel *dst, void *src, uint32_t cnt) -{ - uint16_t *src16 = src; - - while (cnt > 0) { - dst->red = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits); - dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits); - dst->blue = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits); - dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits); - dst++, src16++, cnt--; - } -} - -/* assumes pf->{r,g,b,a}bits == 8 */ -static void conv_32_to_pixel_fast(PixelFormat *pf, - QemuPixel *dst, void *src, uint32_t cnt) -{ - uint32_t *src32 = src; - - while (cnt > 0) { - dst->red = (*src32 & pf->rmask) >> pf->rshift; - dst->green = (*src32 & pf->gmask) >> pf->gshift; - dst->blue = (*src32 & pf->bmask) >> pf->bshift; - dst->alpha = (*src32 & pf->amask) >> pf->ashift; - dst++, src32++, cnt--; - } -} - -static void conv_32_to_pixel_generic(PixelFormat *pf, - QemuPixel *dst, void *src, uint32_t cnt) -{ - uint32_t *src32 = src; - - while (cnt > 0) { - if (pf->rbits < 8) { - dst->red = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits); - } else { - dst->red = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8); - } - if (pf->gbits < 8) { - dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits); - } else { - dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8); - } - if (pf->bbits < 8) { - dst->blue = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits); - } else { - dst->blue = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8); - } - if (pf->abits < 8) { - dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits); - } else { - dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8); - } - dst++, src32++, cnt--; - } -} - -/* ----------------------------------------------------------------------- */ -/* QemuPixel -> PixelFormat conversions */ - -static void conv_pixel_to_16(PixelFormat *pf, - void *dst, QemuPixel *src, uint32_t cnt) -{ - uint16_t *dst16 = dst; - - while (cnt > 0) { - *dst16 = ((uint16_t)src->red >> (8 - pf->rbits)) << pf->rshift; - *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift; - *dst16 |= ((uint16_t)src->blue >> (8 - pf->bbits)) << pf->bshift; - *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift; - dst16++, src++, cnt--; - } -} - -static void conv_pixel_to_32(PixelFormat *pf, - void *dst, QemuPixel *src, uint32_t cnt) -{ - uint32_t *dst32 = dst; - - while (cnt > 0) { - *dst32 = ((uint32_t)src->red >> (8 - pf->rbits)) << pf->rshift; - *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift; - *dst32 |= ((uint32_t)src->blue >> (8 - pf->bbits)) << pf->bshift; - *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift; - dst32++, src++, cnt--; - } -} - -/* ----------------------------------------------------------------------- */ -/* PixelFormat -> PixelFormat conversions */ - -static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) -{ - uint32_t bytes = cnt * conv->src.bytes_per_pixel; - memcpy(dst, src, bytes); -} - -static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) -{ - if (conv->conv_cnt < cnt) { - conv->conv_cnt = cnt; - conv->conv_buf = g_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt); - } - conv->conv_from(&conv->src, conv->conv_buf, src, cnt); - conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt); -} - -/* ----------------------------------------------------------------------- */ -/* public interface */ - -QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src) -{ - QemuPfConv *conv = g_malloc0(sizeof(QemuPfConv)); - - conv->src = *src; - conv->dst = *dst; - - if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) { - /* formats identical, can simply copy */ - conv->convert = convert_copy; - } else { - /* generic two-step conversion: src -> QemuPixel -> dst */ - switch (conv->src.bytes_per_pixel) { - case 2: - conv->conv_from = conv_16_to_pixel; - break; - case 4: - if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) { - conv->conv_from = conv_32_to_pixel_fast; - } else { - conv->conv_from = conv_32_to_pixel_generic; - } - break; - default: - goto err; - } - switch (conv->dst.bytes_per_pixel) { - case 2: - conv->conv_to = conv_pixel_to_16; - break; - case 4: - conv->conv_to = conv_pixel_to_32; - break; - default: - goto err; - } - conv->convert = convert_generic; - } - return conv; - -err: - g_free(conv); - return NULL; -} - -void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) -{ - conv->convert(conv, dst, src, cnt); -} - -void qemu_pf_conv_put(QemuPfConv *conv) -{ - if (conv) { - g_free(conv->conv_buf); - g_free(conv); - } -} diff --git a/pflib.h b/pflib.h deleted file mode 100644 index b70c313acf..0000000000 --- a/pflib.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __QEMU_PFLIB_H -#define __QEMU_PFLIB_H - -/* - * PixelFormat conversion library. - * - * Author: Gerd Hoffmann - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -typedef struct QemuPfConv QemuPfConv; - -QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src); -void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt); -void qemu_pf_conv_put(QemuPfConv *conv); - -#endif From bdd4df332a1bdb20b7fa39ea741f7830e41e1187 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 2 Nov 2012 09:37:27 +0100 Subject: [PATCH 07/67] spice: fix initialization order Register displaychangelistener last, after spice is fully initialized, otherwise we may hit NULL pointer dereferences when qemu starts calling our callbacks. Commit e250d949feb1334828f27f0d145c35f29c4b7639 triggers this bug. Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 10 ++++++++-- ui/spice-display.c | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index e7bf3a11a7..1bc2d32aa8 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -2049,6 +2049,7 @@ static int qxl_init_primary(PCIDevice *dev) PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; PortioList *qxl_vga_port_list = g_new(PortioList, 1); + int rc; qxl->id = 0; qxl_init_ramsize(qxl); @@ -2063,9 +2064,14 @@ static int qxl_init_primary(PCIDevice *dev) qemu_spice_display_init_common(&qxl->ssd, vga->ds); qxl0 = qxl; - register_displaychangelistener(vga->ds, &display_listener); - return qxl_init_common(qxl); + rc = qxl_init_common(qxl); + if (rc != 0) { + return rc; + } + + register_displaychangelistener(vga->ds, &display_listener); + return rc; } static int qxl_init_secondary(PCIDevice *dev) diff --git a/ui/spice-display.c b/ui/spice-display.c index fe2fdfba68..0cc0116a5d 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -573,7 +573,6 @@ void qemu_spice_display_init(DisplayState *ds) { assert(sdpy.ds == NULL); qemu_spice_display_init_common(&sdpy, ds); - register_displaychangelistener(ds, &display_listener); sdpy.qxl.base.sif = &dpy_interface.base; qemu_spice_add_interface(&sdpy.qxl.base); @@ -581,4 +580,5 @@ void qemu_spice_display_init(DisplayState *ds) qemu_spice_create_host_memslot(&sdpy); qemu_spice_create_host_primary(&sdpy); + register_displaychangelistener(ds, &display_listener); } From 9a77a0f58923443913e1071ffb47b74c54566e70 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Nov 2012 17:15:01 +0100 Subject: [PATCH 08/67] usb: split packet result into actual_length + status Since with the ehci and xhci controllers a single packet can be larger then maxpacketsize, it is possible for the result of a single packet to be both having transferred some data as well as the transfer to have an error. An example would be an input transfer from a bulk endpoint successfully receiving 1 or more maxpacketsize packets from the device, followed by a packet signalling halt. While already touching all the devices and controllers handle_packet / handle_data / handle_control code, also change the return type of these functions to void, solely storing the status in the packet. To make the code paths for regular versus async packet handling more uniform. This patch unfortunately is somewhat invasive, since makeing the qemu usb core deal with this requires changes everywhere. This patch only prepares the usb core for this, all the hcd / device changes are done in such a way that there are no functional changes. This patch has been tested with uhci and ehci hcds, together with usb-audio, usb-hid and usb-storage devices, as well as with usb-redir redirection with a wide variety of real devices. Note that there is usually no need to directly set packet->actual_length form devices handle_data callback, as that is done by usb_packet_copy() Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb.h | 24 ++-- hw/usb/bus.c | 13 +-- hw/usb/combined-packet.c | 29 +++-- hw/usb/core.c | 209 ++++++++++++++++++---------------- hw/usb/desc.c | 16 ++- hw/usb/desc.h | 3 +- hw/usb/dev-audio.c | 49 +++----- hw/usb/dev-bluetooth.c | 33 +++--- hw/usb/dev-hid.c | 42 ++++--- hw/usb/dev-hub.c | 34 +++--- hw/usb/dev-network.c | 101 ++++++++-------- hw/usb/dev-serial.c | 29 ++--- hw/usb/dev-smartcard-reader.c | 69 +++++------ hw/usb/dev-storage.c | 51 ++++----- hw/usb/dev-uas.c | 36 +++--- hw/usb/dev-wacom.c | 38 +++---- hw/usb/hcd-ehci.c | 26 +++-- hw/usb/hcd-musb.c | 16 +-- hw/usb/hcd-ohci.c | 26 +++-- hw/usb/hcd-uhci.c | 34 +++--- hw/usb/hcd-xhci.c | 46 ++++---- hw/usb/host-bsd.c | 27 ++--- hw/usb/host-linux.c | 128 +++++++++++---------- hw/usb/redirect.c | 157 ++++++++++++++----------- 24 files changed, 610 insertions(+), 626 deletions(-) diff --git a/hw/usb.h b/hw/usb.h index aef07f4a07..7d6de69ec4 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -38,6 +38,7 @@ #define USB_TOKEN_IN 0x69 /* device -> host */ #define USB_TOKEN_OUT 0xe1 /* host -> device */ +#define USB_RET_SUCCESS (0) #define USB_RET_NODEV (-1) #define USB_RET_NAK (-2) #define USB_RET_STALL (-3) @@ -280,18 +281,20 @@ typedef struct USBDeviceClass { * Process control request. * Called from handle_packet(). * - * Returns length or one of the USB_RET_ codes. + * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS + * then the number of bytes transfered is stored in p->actual_length */ - int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value, - int index, int length, uint8_t *data); + void (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value, + int index, int length, uint8_t *data); /* * Process data transfers (both BULK and ISOC). * Called from handle_packet(). * - * Returns length or one of the USB_RET_ codes. + * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS + * then the number of bytes transfered is stored in p->actual_length */ - int (*handle_data)(USBDevice *dev, USBPacket *p); + void (*handle_data)(USBDevice *dev, USBPacket *p); void (*set_interface)(USBDevice *dev, int interface, int alt_old, int alt_new); @@ -354,7 +357,8 @@ struct USBPacket { uint64_t parameter; /* control transfers */ bool short_not_ok; bool int_req; - int result; /* transfer length or USB_RET_* status code */ + int status; /* USB_RET_* status code */ + int actual_length; /* Number of bytes actually transfered */ /* Internal use by the USB layer. */ USBPacketState state; USBCombinedPacket *combined; @@ -388,7 +392,7 @@ static inline bool usb_packet_is_inflight(USBPacket *p) USBDevice *usb_find_device(USBPort *port, uint8_t addr); -int usb_handle_packet(USBDevice *dev, USBPacket *p); +void usb_handle_packet(USBDevice *dev, USBPacket *p); void usb_packet_complete(USBDevice *dev, USBPacket *p); void usb_packet_complete_one(USBDevice *dev, USBPacket *p); void usb_cancel_packet(USBPacket * p); @@ -523,10 +527,10 @@ void usb_device_handle_attach(USBDevice *dev); void usb_device_handle_reset(USBDevice *dev); -int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value, - int index, int length, uint8_t *data); +void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, + int val, int index, int length, uint8_t *data); -int usb_device_handle_data(USBDevice *dev, USBPacket *p); +void usb_device_handle_data(USBDevice *dev, USBPacket *p); void usb_device_set_interface(USBDevice *dev, int interface, int alt_old, int alt_new); diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 8066291b34..99aac7a2c0 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -140,24 +140,21 @@ void usb_device_handle_reset(USBDevice *dev) } } -int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, - int value, int index, int length, uint8_t *data) +void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, + int value, int index, int length, uint8_t *data) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); if (klass->handle_control) { - return klass->handle_control(dev, p, request, value, index, length, - data); + klass->handle_control(dev, p, request, value, index, length, data); } - return -ENOSYS; } -int usb_device_handle_data(USBDevice *dev, USBPacket *p) +void usb_device_handle_data(USBDevice *dev, USBPacket *p) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); if (klass->handle_data) { - return klass->handle_data(dev, p); + klass->handle_data(dev, p); } - return -ENOSYS; } const char *usb_device_get_product_desc(USBDevice *dev) diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c index 3904e71634..e72219894b 100644 --- a/hw/usb/combined-packet.c +++ b/hw/usb/combined-packet.c @@ -46,7 +46,7 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p) USBEndpoint *ep = p->ep; USBPacket *next; enum { completing, complete, leftover }; - int result, state = completing; + int status, actual_length, state = completing; bool short_not_ok; if (combined == NULL) { @@ -56,27 +56,34 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p) assert(combined->first == p && p == QTAILQ_FIRST(&combined->packets)); - result = combined->first->result; + status = combined->first->status; + actual_length = combined->first->actual_length; short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok; QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) { if (state == completing) { /* Distribute data over uncombined packets */ - if (result >= p->iov.size) { - p->result = p->iov.size; + if (actual_length >= p->iov.size) { + p->actual_length = p->iov.size; } else { /* Send short or error packet to complete the transfer */ - p->result = result; + p->actual_length = actual_length; state = complete; } + /* Report status on the last packet */ + if (state == complete || next == NULL) { + p->status = status; + } else { + p->status = USB_RET_SUCCESS; + } p->short_not_ok = short_not_ok; usb_combined_packet_remove(combined, p); usb_packet_complete_one(dev, p); - result -= p->result; + actual_length -= p->actual_length; } else { /* Remove any leftover packets from the queue */ state = leftover; - p->result = USB_RET_REMOVE_FROM_QUEUE; + p->status = USB_RET_REMOVE_FROM_QUEUE; dev->port->ops->complete(dev->port, p); } } @@ -117,7 +124,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep) { USBPacket *p, *u, *next, *prev = NULL, *first = NULL; USBPort *port = ep->dev->port; - int ret, totalsize; + int totalsize; assert(ep->pipeline); assert(ep->pid == USB_TOKEN_IN); @@ -125,7 +132,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep) QTAILQ_FOREACH_SAFE(p, &ep->queue, queue, next) { /* Empty the queue on a halt */ if (ep->halted) { - p->result = USB_RET_REMOVE_FROM_QUEUE; + p->status = USB_RET_REMOVE_FROM_QUEUE; port->ops->complete(port, p); continue; } @@ -166,8 +173,8 @@ void usb_ep_combine_input_packets(USBEndpoint *ep) next == NULL || /* Work around for Linux usbfs bulk splitting + migration */ (totalsize == 16348 && p->int_req)) { - ret = usb_device_handle_data(ep->dev, first); - assert(ret == USB_RET_ASYNC); + usb_device_handle_data(ep->dev, first); + assert(first->status == USB_RET_ASYNC); if (first->combined) { QTAILQ_FOREACH(u, &first->combined->packets, combined_entry) { usb_packet_set_state(u, USB_PACKET_ASYNC); diff --git a/hw/usb/core.c b/hw/usb/core.c index ab37f6f7b8..52b53108cd 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -97,17 +97,17 @@ void usb_wakeup(USBEndpoint *ep) #define SETUP_STATE_ACK 3 #define SETUP_STATE_PARAM 4 -static int do_token_setup(USBDevice *s, USBPacket *p) +static void do_token_setup(USBDevice *s, USBPacket *p) { int request, value, index; - int ret = 0; if (p->iov.size != 8) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } usb_packet_copy(p, s->setup_buf, p->iov.size); - p->result = 0; + p->actual_length = 0; s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; s->setup_index = 0; @@ -116,24 +116,26 @@ static int do_token_setup(USBDevice *s, USBPacket *p) index = (s->setup_buf[5] << 8) | s->setup_buf[4]; if (s->setup_buf[0] & USB_DIR_IN) { - ret = usb_device_handle_control(s, p, request, value, index, - s->setup_len, s->data_buf); - if (ret == USB_RET_ASYNC) { - s->setup_state = SETUP_STATE_SETUP; - return USB_RET_ASYNC; + usb_device_handle_control(s, p, request, value, index, + s->setup_len, s->data_buf); + if (p->status == USB_RET_ASYNC) { + s->setup_state = SETUP_STATE_SETUP; + } + if (p->status != USB_RET_SUCCESS) { + return; } - if (ret < 0) - return ret; - if (ret < s->setup_len) - s->setup_len = ret; + if (p->actual_length < s->setup_len) { + s->setup_len = p->actual_length; + } s->setup_state = SETUP_STATE_DATA; } else { if (s->setup_len > sizeof(s->data_buf)) { fprintf(stderr, "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", s->setup_len, sizeof(s->data_buf)); - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } if (s->setup_len == 0) s->setup_state = SETUP_STATE_ACK; @@ -141,13 +143,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p) s->setup_state = SETUP_STATE_DATA; } - return ret; + p->actual_length = 8; } -static int do_token_in(USBDevice *s, USBPacket *p) +static void do_token_in(USBDevice *s, USBPacket *p) { int request, value, index; - int ret = 0; assert(p->ep->nr == 0); @@ -158,19 +159,15 @@ static int do_token_in(USBDevice *s, USBPacket *p) switch(s->setup_state) { case SETUP_STATE_ACK: if (!(s->setup_buf[0] & USB_DIR_IN)) { - ret = usb_device_handle_control(s, p, request, value, index, - s->setup_len, s->data_buf); - if (ret == USB_RET_ASYNC) { - return USB_RET_ASYNC; + usb_device_handle_control(s, p, request, value, index, + s->setup_len, s->data_buf); + if (p->status == USB_RET_ASYNC) { + return; } s->setup_state = SETUP_STATE_IDLE; - if (ret > 0) - return 0; - return ret; + p->actual_length = 0; } - - /* return 0 byte */ - return 0; + break; case SETUP_STATE_DATA: if (s->setup_buf[0] & USB_DIR_IN) { @@ -180,20 +177,21 @@ static int do_token_in(USBDevice *s, USBPacket *p) } usb_packet_copy(p, s->data_buf + s->setup_index, len); s->setup_index += len; - if (s->setup_index >= s->setup_len) + if (s->setup_index >= s->setup_len) { s->setup_state = SETUP_STATE_ACK; - return len; + } + return; } - s->setup_state = SETUP_STATE_IDLE; - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; default: - return USB_RET_STALL; + p->status = USB_RET_STALL; } } -static int do_token_out(USBDevice *s, USBPacket *p) +static void do_token_out(USBDevice *s, USBPacket *p) { assert(p->ep->nr == 0); @@ -205,7 +203,7 @@ static int do_token_out(USBDevice *s, USBPacket *p) } else { /* ignore additional output */ } - return 0; + break; case SETUP_STATE_DATA: if (!(s->setup_buf[0] & USB_DIR_IN)) { @@ -215,23 +213,23 @@ static int do_token_out(USBDevice *s, USBPacket *p) } usb_packet_copy(p, s->data_buf + s->setup_index, len); s->setup_index += len; - if (s->setup_index >= s->setup_len) + if (s->setup_index >= s->setup_len) { s->setup_state = SETUP_STATE_ACK; - return len; + } + return; } - s->setup_state = SETUP_STATE_IDLE; - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; default: - return USB_RET_STALL; + p->status = USB_RET_STALL; } } -static int do_parameter(USBDevice *s, USBPacket *p) +static void do_parameter(USBDevice *s, USBPacket *p) { - int request, value, index; - int i, ret = 0; + int i, request, value, index; for (i = 0; i < 8; i++) { s->setup_buf[i] = p->parameter >> (i*8); @@ -249,27 +247,27 @@ static int do_parameter(USBDevice *s, USBPacket *p) fprintf(stderr, "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", s->setup_len, sizeof(s->data_buf)); - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } if (p->pid == USB_TOKEN_OUT) { usb_packet_copy(p, s->data_buf, s->setup_len); } - ret = usb_device_handle_control(s, p, request, value, index, - s->setup_len, s->data_buf); - if (ret < 0) { - return ret; + usb_device_handle_control(s, p, request, value, index, + s->setup_len, s->data_buf); + if (p->status == USB_RET_ASYNC) { + return; } - if (ret < s->setup_len) { - s->setup_len = ret; + if (p->actual_length < s->setup_len) { + s->setup_len = p->actual_length; } if (p->pid == USB_TOKEN_IN) { + p->actual_length = 0; usb_packet_copy(p, s->data_buf, s->setup_len); } - - return ret; } /* ctrl complete function for devices which use usb_generic_handle_packet and @@ -278,30 +276,30 @@ static int do_parameter(USBDevice *s, USBPacket *p) usb_packet_complete to complete their async control packets. */ void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p) { - if (p->result < 0) { + if (p->status < 0) { s->setup_state = SETUP_STATE_IDLE; } switch (s->setup_state) { case SETUP_STATE_SETUP: - if (p->result < s->setup_len) { - s->setup_len = p->result; + if (p->actual_length < s->setup_len) { + s->setup_len = p->actual_length; } s->setup_state = SETUP_STATE_DATA; - p->result = 8; + p->actual_length = 8; break; case SETUP_STATE_ACK: s->setup_state = SETUP_STATE_IDLE; - p->result = 0; + p->actual_length = 0; break; case SETUP_STATE_PARAM: - if (p->result < s->setup_len) { - s->setup_len = p->result; + if (p->actual_length < s->setup_len) { + s->setup_len = p->actual_length; } if (p->pid == USB_TOKEN_IN) { - p->result = 0; + p->actual_length = 0; usb_packet_copy(p, s->data_buf, s->setup_len); } break; @@ -342,40 +340,57 @@ USBDevice *usb_find_device(USBPort *port, uint8_t addr) return usb_device_find_device(dev, addr); } -static int usb_process_one(USBPacket *p) +static void usb_process_one(USBPacket *p) { USBDevice *dev = p->ep->dev; + /* + * Handlers expect status to be initialized to USB_RET_SUCCESS, but it + * can be USB_RET_NAK here from a previous usb_process_one() call, + * or USB_RET_ASYNC from going through usb_queue_one(). + */ + p->status = USB_RET_SUCCESS; + if (p->ep->nr == 0) { /* control pipe */ if (p->parameter) { - return do_parameter(dev, p); + do_parameter(dev, p); + return; } switch (p->pid) { case USB_TOKEN_SETUP: - return do_token_setup(dev, p); + do_token_setup(dev, p); + break; case USB_TOKEN_IN: - return do_token_in(dev, p); + do_token_in(dev, p); + break; case USB_TOKEN_OUT: - return do_token_out(dev, p); + do_token_out(dev, p); + break; default: - return USB_RET_STALL; + p->status = USB_RET_STALL; } } else { /* data pipe */ - return usb_device_handle_data(dev, p); + usb_device_handle_data(dev, p); } } -/* Hand over a packet to a device for processing. Return value +static void usb_queue_one(USBPacket *p) +{ + usb_packet_set_state(p, USB_PACKET_QUEUED); + QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); + p->status = USB_RET_ASYNC; +} + +/* Hand over a packet to a device for processing. p->status == USB_RET_ASYNC indicates the processing isn't finished yet, the driver will call usb_packet_complete() when done processing it. */ -int usb_handle_packet(USBDevice *dev, USBPacket *p) +void usb_handle_packet(USBDevice *dev, USBPacket *p) { - int ret; - if (dev == NULL) { - return USB_RET_NODEV; + p->status = USB_RET_NODEV; + return; } assert(dev == p->ep->dev); assert(dev->state == USB_STATE_DEFAULT); @@ -389,32 +404,26 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) } if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) { - ret = usb_process_one(p); - if (ret == USB_RET_ASYNC) { + usb_process_one(p); + if (p->status == USB_RET_ASYNC) { assert(p->ep->type != USB_ENDPOINT_XFER_ISOC); usb_packet_set_state(p, USB_PACKET_ASYNC); QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); - } else if (ret == USB_RET_ADD_TO_QUEUE) { - usb_packet_set_state(p, USB_PACKET_QUEUED); - QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); - ret = USB_RET_ASYNC; + } else if (p->status == USB_RET_ADD_TO_QUEUE) { + usb_queue_one(p); } else { /* * When pipelining is enabled usb-devices must always return async, * otherwise packets can complete out of order! */ assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue)); - if (ret != USB_RET_NAK) { - p->result = ret; + if (p->status != USB_RET_NAK) { usb_packet_set_state(p, USB_PACKET_COMPLETE); } } } else { - ret = USB_RET_ASYNC; - usb_packet_set_state(p, USB_PACKET_QUEUED); - QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); + usb_queue_one(p); } - return ret; } void usb_packet_complete_one(USBDevice *dev, USBPacket *p) @@ -422,9 +431,10 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p) USBEndpoint *ep = p->ep; assert(QTAILQ_FIRST(&ep->queue) == p); - assert(p->result != USB_RET_ASYNC && p->result != USB_RET_NAK); + assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK); - if (p->result < 0 || (p->short_not_ok && (p->result < p->iov.size))) { + if (p->status != USB_RET_SUCCESS || + (p->short_not_ok && (p->actual_length < p->iov.size))) { ep->halted = true; } usb_packet_set_state(p, USB_PACKET_COMPLETE); @@ -438,7 +448,6 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p) void usb_packet_complete(USBDevice *dev, USBPacket *p) { USBEndpoint *ep = p->ep; - int ret; usb_packet_check_state(p, USB_PACKET_ASYNC); usb_packet_complete_one(dev, p); @@ -447,7 +456,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p) p = QTAILQ_FIRST(&ep->queue); if (ep->halted) { /* Empty the queue on a halt */ - p->result = USB_RET_REMOVE_FROM_QUEUE; + p->status = USB_RET_REMOVE_FROM_QUEUE; dev->port->ops->complete(dev->port, p); continue; } @@ -455,12 +464,11 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p) break; } usb_packet_check_state(p, USB_PACKET_QUEUED); - ret = usb_process_one(p); - if (ret == USB_RET_ASYNC) { + usb_process_one(p); + if (p->status == USB_RET_ASYNC) { usb_packet_set_state(p, USB_PACKET_ASYNC); break; } - p->result = ret; usb_packet_complete_one(ep->dev, p); } } @@ -541,7 +549,8 @@ void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id, p->id = id; p->pid = pid; p->ep = ep; - p->result = 0; + p->status = USB_RET_SUCCESS; + p->actual_length = 0; p->parameter = 0; p->short_not_ok = short_not_ok; p->int_req = int_req; @@ -557,31 +566,31 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len) void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes) { - assert(p->result >= 0); - assert(p->result + bytes <= p->iov.size); + assert(p->actual_length >= 0); + assert(p->actual_length + bytes <= p->iov.size); switch (p->pid) { case USB_TOKEN_SETUP: case USB_TOKEN_OUT: - iov_to_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes); + iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes); break; case USB_TOKEN_IN: - iov_from_buf(p->iov.iov, p->iov.niov, p->result, ptr, bytes); + iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes); break; default: fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid); abort(); } - p->result += bytes; + p->actual_length += bytes; } void usb_packet_skip(USBPacket *p, size_t bytes) { - assert(p->result >= 0); - assert(p->result + bytes <= p->iov.size); + assert(p->actual_length >= 0); + assert(p->actual_length + bytes <= p->iov.size); if (p->pid == USB_TOKEN_IN) { - iov_memset(p->iov.iov, p->iov.niov, p->result, 0, bytes); + iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes); } - p->result += bytes; + p->actual_length += bytes; } void usb_packet_cleanup(USBPacket *p) diff --git a/hw/usb/desc.c b/hw/usb/desc.c index 1f12eaecbf..b7c32333d7 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -626,7 +626,8 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) return pos; } -int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) +int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, + int value, uint8_t *dest, size_t len) { const USBDesc *desc = usb_device_get_usb_desc(dev); const USBDescDevice *other_dev; @@ -696,6 +697,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len ret = len; } memcpy(dest, buf, ret); + p->actual_length = ret; + ret = 0; } return ret; } @@ -715,7 +718,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - ret = usb_desc_get_descriptor(dev, value, data, length); + ret = usb_desc_get_descriptor(dev, p, value, data, length); break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: @@ -724,7 +727,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, * the non zero value of bConfigurationValue. */ data[0] = dev->config ? dev->config->bConfigurationValue : 0; - ret = 1; + p->actual_length = 1; + ret = 0; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ret = usb_desc_set_config(dev, value); @@ -749,7 +753,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; } data[1] = 0x00; - ret = 2; + p->actual_length = 2; + ret = 0; break; } case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: @@ -772,7 +777,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, break; } data[0] = dev->altsetting[index]; - ret = 1; + p->actual_length = 1; + ret = 0; break; case InterfaceOutRequest | USB_REQ_SET_INTERFACE: ret = usb_desc_set_interface(dev, index, value); diff --git a/hw/usb/desc.h b/hw/usb/desc.h index 68bb570679..ddd3e7485c 100644 --- a/hw/usb/desc.h +++ b/hw/usb/desc.h @@ -216,7 +216,8 @@ void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str); void usb_desc_create_serial(USBDevice *dev); const char *usb_desc_get_string(USBDevice *dev, uint8_t index); int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len); -int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len); +int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p, + int value, uint8_t *dest, size_t len); int usb_desc_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data); diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 2594c78104..b669601c92 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -503,7 +503,7 @@ static int usb_audio_set_control(USBAudioState *s, uint8_t attrib, return ret; } -static int usb_audio_handle_control(USBDevice *dev, USBPacket *p, +static void usb_audio_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { @@ -518,7 +518,7 @@ static int usb_audio_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } switch (request) { @@ -534,6 +534,7 @@ static int usb_audio_handle_control(USBDevice *dev, USBPacket *p, } goto fail; } + p->actual_length = ret; break; case ClassInterfaceOutRequest | CR_SET_CUR: @@ -557,10 +558,9 @@ fail: "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n", request, value, index, length); } - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_audio_set_interface(USBDevice *dev, int iface, @@ -583,50 +583,35 @@ static void usb_audio_handle_reset(USBDevice *dev) usb_audio_set_output_altset(s, ALTSET_OFF); } -static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p) +static void usb_audio_handle_dataout(USBAudioState *s, USBPacket *p) { - int rc; - if (s->out.altset == ALTSET_OFF) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } - rc = streambuf_put(&s->out.buf, p); - if (rc < p->iov.size && s->debug > 1) { + streambuf_put(&s->out.buf, p); + if (p->actual_length < p->iov.size && s->debug > 1) { fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n", - p->iov.size - rc); + p->iov.size - p->actual_length); } - - return 0; } -static int usb_audio_handle_data(USBDevice *dev, USBPacket *p) +static void usb_audio_handle_data(USBDevice *dev, USBPacket *p) { USBAudioState *s = (USBAudioState *) dev; - int ret = 0; - switch (p->pid) { - case USB_TOKEN_OUT: - switch (p->ep->nr) { - case 1: - ret = usb_audio_handle_dataout(s, p); - break; - default: - goto fail; - } - break; - - default: -fail: - ret = USB_RET_STALL; - break; + if (p->pid == USB_TOKEN_OUT && p->ep->nr == 1) { + usb_audio_handle_dataout(s, p); + return; } - if (ret == USB_RET_STALL && s->debug) { + + p->status = USB_RET_STALL; + if (s->debug) { fprintf(stderr, "usb-audio: failed data transaction: " "pid 0x%x ep 0x%x len 0x%zx\n", p->pid, p->ep->nr, p->iov.size); } - return ret; } static void usb_audio_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index 55bc19184b..bfb96bf9f0 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -285,13 +285,15 @@ static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo, fifo->fifo[off].len = len; } -static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, +static inline void usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, USBPacket *p) { int len; - if (likely(!fifo->len)) - return USB_RET_STALL; + if (likely(!fifo->len)) { + p->status = USB_RET_STALL; + return; + } len = MIN(p->iov.size, fifo->fifo[fifo->start].len); usb_packet_copy(p, fifo->fifo[fifo->start].data, len); @@ -310,8 +312,6 @@ static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, fifo->dstart = 0; fifo->dsize = DFIFO_LEN_MASK + 1; } - - return len; } static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s, @@ -363,7 +363,7 @@ static void usb_bt_handle_reset(USBDevice *dev) s->outsco.len = 0; } -static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, +static void usb_bt_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { struct USBBtState *s = (struct USBBtState *) dev->opaque; @@ -382,16 +382,15 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, usb_bt_fifo_reset(&s->sco); break; } - return ret; + return; } - ret = 0; switch (request) { case InterfaceRequest | USB_REQ_GET_STATUS: case EndpointRequest | USB_REQ_GET_STATUS: data[0] = 0x00; data[1] = 0x00; - ret = 2; + p->actual_length = 2; break; case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE: case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: @@ -407,16 +406,14 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, break; default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) +static void usb_bt_handle_data(USBDevice *dev, USBPacket *p) { struct USBBtState *s = (struct USBBtState *) dev->opaque; - int ret = 0; if (!s->config) goto fail; @@ -425,15 +422,15 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_IN: switch (p->ep->nr) { case USB_EVT_EP: - ret = usb_bt_fifo_dequeue(&s->evt, p); + usb_bt_fifo_dequeue(&s->evt, p); break; case USB_ACL_EP: - ret = usb_bt_fifo_dequeue(&s->acl, p); + usb_bt_fifo_dequeue(&s->acl, p); break; case USB_SCO_EP: - ret = usb_bt_fifo_dequeue(&s->sco, p); + usb_bt_fifo_dequeue(&s->sco, p); break; default: @@ -460,11 +457,9 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - - return ret; } static void usb_bt_out_hci_packet_event(void *opaque, diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index b3dcd23109..55266b18ef 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -371,7 +371,7 @@ static void usb_hid_handle_reset(USBDevice *dev) hid_reset(&us->hid); } -static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, +static void usb_hid_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); @@ -380,10 +380,9 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch (request) { /* hid specific requests */ case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: @@ -392,15 +391,15 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, if (hs->kind == HID_MOUSE) { memcpy(data, qemu_mouse_hid_report_descriptor, sizeof(qemu_mouse_hid_report_descriptor)); - ret = sizeof(qemu_mouse_hid_report_descriptor); + p->actual_length = sizeof(qemu_mouse_hid_report_descriptor); } else if (hs->kind == HID_TABLET) { memcpy(data, qemu_tablet_hid_report_descriptor, sizeof(qemu_tablet_hid_report_descriptor)); - ret = sizeof(qemu_tablet_hid_report_descriptor); + p->actual_length = sizeof(qemu_tablet_hid_report_descriptor); } else if (hs->kind == HID_KEYBOARD) { memcpy(data, qemu_keyboard_hid_report_descriptor, sizeof(qemu_keyboard_hid_report_descriptor)); - ret = sizeof(qemu_keyboard_hid_report_descriptor); + p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor); } break; default: @@ -409,14 +408,14 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, break; case GET_REPORT: if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { - ret = hid_pointer_poll(hs, data, length); + p->actual_length = hid_pointer_poll(hs, data, length); } else if (hs->kind == HID_KEYBOARD) { - ret = hid_keyboard_poll(hs, data, length); + p->actual_length = hid_keyboard_poll(hs, data, length); } break; case SET_REPORT: if (hs->kind == HID_KEYBOARD) { - ret = hid_keyboard_write(hs, data, length); + p->actual_length = hid_keyboard_write(hs, data, length); } else { goto fail; } @@ -425,19 +424,18 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) { goto fail; } - ret = 1; data[0] = hs->protocol; + p->actual_length = 1; break; case SET_PROTOCOL: if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) { goto fail; } - ret = 0; hs->protocol = value; break; case GET_IDLE: - ret = 1; data[0] = hs->idle; + p->actual_length = 1; break; case SET_IDLE: hs->idle = (uint8_t) (value >> 8); @@ -445,22 +443,20 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } - ret = 0; break; default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) +static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) { USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); HIDState *hs = &us->hid; uint8_t buf[p->iov.size]; - int ret = 0; + int len = 0; switch (p->pid) { case USB_TOKEN_IN: @@ -471,15 +467,16 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) } if (!hid_has_events(hs) && (!hs->idle || hs->next_idle_clock - curtime > 0)) { - return USB_RET_NAK; + p->status = USB_RET_NAK; + return; } hid_set_next_idle(hs, curtime); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { - ret = hid_pointer_poll(hs, buf, p->iov.size); + len = hid_pointer_poll(hs, buf, p->iov.size); } else if (hs->kind == HID_KEYBOARD) { - ret = hid_keyboard_poll(hs, buf, p->iov.size); + len = hid_keyboard_poll(hs, buf, p->iov.size); } - usb_packet_copy(p, buf, ret); + usb_packet_copy(p, buf, len); } else { goto fail; } @@ -487,10 +484,9 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_OUT: default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_hid_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 8fd30df0e6..9ee60dd412 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -288,7 +288,7 @@ static const char *feature_name(int feature) return name[feature] ?: "?"; } -static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, +static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBHubState *s = (USBHubState *)dev; @@ -298,7 +298,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } switch(request) { @@ -306,7 +306,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, if (value == 0 && index != 0x81) { /* clear ep halt */ goto fail; } - ret = 0; break; /* usb specific requests */ case GetHubStatus: @@ -314,7 +313,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, data[1] = 0; data[2] = 0; data[3] = 0; - ret = 4; + p->actual_length = 4; break; case GetPortStatus: { @@ -331,16 +330,14 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, data[1] = port->wPortStatus >> 8; data[2] = port->wPortChange; data[3] = port->wPortChange >> 8; - ret = 4; + p->actual_length = 4; } break; case SetHubFeature: case ClearHubFeature: - if (value == 0 || value == 1) { - } else { + if (value != 0 && value != 1) { goto fail; } - ret = 0; break; case SetPortFeature: { @@ -373,7 +370,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, default: goto fail; } - ret = 0; } break; case ClearPortFeature: @@ -413,7 +409,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, default: goto fail; } - ret = 0; } break; case GetHubDescriptor: @@ -437,22 +432,20 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, var_hub_size++; } - ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; - data[0] = ret; + p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size; + data[0] = p->actual_length; break; } default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) +static void usb_hub_handle_data(USBDevice *dev, USBPacket *p) { USBHubState *s = (USBHubState *)dev; - int ret; switch(p->pid) { case USB_TOKEN_IN: @@ -465,7 +458,8 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) if (p->iov.size == 1) { /* FreeBSD workaround */ n = 1; } else if (n > p->iov.size) { - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + return; } status = 0; for(i = 0; i < NUM_PORTS; i++) { @@ -478,9 +472,8 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) buf[i] = status >> (8 * i); } usb_packet_copy(p, buf, n); - ret = n; } else { - ret = USB_RET_NAK; /* usb11 11.13.1 */ + p->status = USB_RET_NAK; /* usb11 11.13.1 */ } } else { goto fail; @@ -489,10 +482,9 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_OUT: default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_hub_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index e4a43599b5..14d9e5aa5b 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1048,7 +1048,7 @@ static void usb_net_handle_reset(USBDevice *dev) { } -static int usb_net_handle_control(USBDevice *dev, USBPacket *p, +static void usb_net_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBNetState *s = (USBNetState *) dev; @@ -1056,10 +1056,9 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch(request) { case ClassInterfaceOutRequest | USB_CDC_SEND_ENCAPSULATED_COMMAND: if (!is_rndis(s) || value || index != 0) { @@ -1078,22 +1077,25 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p, } #endif ret = rndis_parse(s, data, length); + if (ret < 0) { + p->status = ret; + } break; case ClassInterfaceRequest | USB_CDC_GET_ENCAPSULATED_RESPONSE: if (!is_rndis(s) || value || index != 0) { goto fail; } - ret = rndis_get_response(s, data); - if (!ret) { + p->actual_length = rndis_get_response(s, data); + if (p->actual_length == 0) { data[0] = 0; - ret = 1; + p->actual_length = 1; } #ifdef TRAFFIC_DEBUG { unsigned int i; fprintf(stderr, "GET_ENCAPSULATED_RESPONSE:"); - for (i = 0; i < ret; i++) { + for (i = 0; i < p->actual_length; i++) { if (!(i & 15)) fprintf(stderr, "\n%04x:", i); fprintf(stderr, " %02x", data[i]); @@ -1108,72 +1110,67 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p, fprintf(stderr, "usbnet: failed control transaction: " "request 0x%x value 0x%x index 0x%x length 0x%x\n", request, value, index, length); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_net_handle_statusin(USBNetState *s, USBPacket *p) +static void usb_net_handle_statusin(USBNetState *s, USBPacket *p) { le32 buf[2]; - int ret = 8; if (p->iov.size < 8) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } buf[0] = cpu_to_le32(1); buf[1] = cpu_to_le32(0); usb_packet_copy(p, buf, 8); - if (!s->rndis_resp.tqh_first) - ret = USB_RET_NAK; + if (!s->rndis_resp.tqh_first) { + p->status = USB_RET_NAK; + } #ifdef TRAFFIC_DEBUG fprintf(stderr, "usbnet: interrupt poll len %zu return %d", - p->iov.size, ret); - iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret); + p->iov.size, p->status); + iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->status); #endif - - return ret; } -static int usb_net_handle_datain(USBNetState *s, USBPacket *p) +static void usb_net_handle_datain(USBNetState *s, USBPacket *p) { - int ret = USB_RET_NAK; + int len; if (s->in_ptr > s->in_len) { usb_net_reset_in_buf(s); - ret = USB_RET_NAK; - return ret; + p->status = USB_RET_NAK; + return; } if (!s->in_len) { - ret = USB_RET_NAK; - return ret; + p->status = USB_RET_NAK; + return; } - ret = s->in_len - s->in_ptr; - if (ret > p->iov.size) { - ret = p->iov.size; + len = s->in_len - s->in_ptr; + if (len > p->iov.size) { + len = p->iov.size; } - usb_packet_copy(p, &s->in_buf[s->in_ptr], ret); - s->in_ptr += ret; + usb_packet_copy(p, &s->in_buf[s->in_ptr], len); + s->in_ptr += len; if (s->in_ptr >= s->in_len && - (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) { + (is_rndis(s) || (s->in_len & (64 - 1)) || !len)) { /* no short packet necessary */ usb_net_reset_in_buf(s); } #ifdef TRAFFIC_DEBUG - fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret); - iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret); + fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, len); + iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", len); #endif - - return ret; } -static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) +static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) { - int ret = p->iov.size; int sz = sizeof(s->out_buf) - s->out_ptr; struct rndis_packet_msg_type *msg = (struct rndis_packet_msg_type *) s->out_buf; @@ -1184,21 +1181,23 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size); #endif - if (sz > ret) - sz = ret; + if (sz > p->iov.size) { + sz = p->iov.size; + } usb_packet_copy(p, &s->out_buf[s->out_ptr], sz); s->out_ptr += sz; if (!is_rndis(s)) { - if (ret < 64) { + if (p->iov.size < 64) { qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr); s->out_ptr = 0; } - return ret; + return; } len = le32_to_cpu(msg->MessageLength); - if (s->out_ptr < 8 || s->out_ptr < len) - return ret; + if (s->out_ptr < 8 || s->out_ptr < len) { + return; + } if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) { uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); uint32_t size = le32_to_cpu(msg->DataLength); @@ -1207,24 +1206,21 @@ static int usb_net_handle_dataout(USBNetState *s, USBPacket *p) } s->out_ptr -= len; memmove(s->out_buf, &s->out_buf[len], s->out_ptr); - - return ret; } -static int usb_net_handle_data(USBDevice *dev, USBPacket *p) +static void usb_net_handle_data(USBDevice *dev, USBPacket *p) { USBNetState *s = (USBNetState *) dev; - int ret = 0; switch(p->pid) { case USB_TOKEN_IN: switch (p->ep->nr) { case 1: - ret = usb_net_handle_statusin(s, p); + usb_net_handle_statusin(s, p); break; case 2: - ret = usb_net_handle_datain(s, p); + usb_net_handle_datain(s, p); break; default: @@ -1235,7 +1231,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_OUT: switch (p->ep->nr) { case 2: - ret = usb_net_handle_dataout(s, p); + usb_net_handle_dataout(s, p); break; default: @@ -1245,14 +1241,15 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) default: fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - if (ret == USB_RET_STALL) + + if (p->status == USB_RET_STALL) { fprintf(stderr, "usbnet: failed data transaction: " "pid 0x%x ep 0x%x len 0x%zx\n", p->pid, p->ep->nr, p->iov.size); - return ret; + } } static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size) diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index a466f9929c..99b19df1d1 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -219,7 +219,7 @@ static uint8_t usb_get_modem_lines(USBSerialState *s) return ret; } -static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, +static void usb_serial_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBSerialState *s = (USBSerialState *)dev; @@ -228,13 +228,11 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, DPRINTF("got control %x, value %x\n",request, value); ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch (request) { case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - ret = 0; break; /* Class specific requests. */ @@ -323,7 +321,7 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, case DeviceInVendor | FTDI_GET_MDM_ST: data[0] = usb_get_modem_lines(s) | 1; data[1] = 0; - ret = 2; + p->actual_length = 2; break; case DeviceOutVendor | FTDI_SET_EVENT_CHR: /* TODO: handle it */ @@ -338,25 +336,23 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, break; case DeviceInVendor | FTDI_GET_LATENCY: data[0] = s->latency; - ret = 1; + p->actual_length = 1; break; default: fail: DPRINTF("got unsupported/bogus control %x, value %x\n", request, value); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) +static void usb_serial_handle_data(USBDevice *dev, USBPacket *p) { USBSerialState *s = (USBSerialState *)dev; - int i, ret = 0; uint8_t devep = p->ep->nr; struct iovec *iov; uint8_t header[2]; - int first_len, len; + int i, first_len, len; switch (p->pid) { case USB_TOKEN_OUT: @@ -366,6 +362,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) iov = p->iov.iov + i; qemu_chr_fe_write(s->cs, iov->iov_base, iov->iov_len); } + p->actual_length = p->iov.size; break; case USB_TOKEN_IN: @@ -374,7 +371,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) first_len = RECV_BUF - s->recv_ptr; len = p->iov.size; if (len <= 2) { - ret = USB_RET_NAK; + p->status = USB_RET_NAK; break; } header[0] = usb_get_modem_lines(s) | 1; @@ -384,7 +381,6 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) s->event_trigger &= ~FTDI_BI; header[1] = FTDI_BI; usb_packet_copy(p, header, 2); - ret = 2; break; } else { header[1] = 0; @@ -393,7 +389,7 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) if (len > s->recv_used) len = s->recv_used; if (!len) { - ret = USB_RET_NAK; + p->status = USB_RET_NAK; break; } if (first_len > len) @@ -404,17 +400,14 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p) usb_packet_copy(p, s->recv_buf, len - first_len); s->recv_used -= len; s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; - ret = len + 2; break; default: DPRINTF("Bad token\n"); fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - - return ret; } static void usb_serial_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 1ea079176a..190fcd62d4 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -635,39 +635,38 @@ static void ccid_handle_reset(USBDevice *dev) ccid_reset(s); } -static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, +static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); - int ret = 0; + int ret; DPRINTF(s, 1, "got control %x, value %x\n", request, value); ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } switch (request) { /* Class specific requests. */ case InterfaceOutClass | CCID_CONTROL_ABORT: DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES: DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES: DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; default: DPRINTF(s, 1, "got unsupported/bogus control %x, value %x\n", request, value); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static bool ccid_card_inserted(USBCCIDState *s) @@ -870,18 +869,13 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv) } } -/* - * Handle a single USB_TOKEN_OUT, return value returned to guest. - * Return value: - * 0 - all ok - * USB_RET_STALL - failed to handle packet - */ -static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) +static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) { CCID_Header *ccid_header; if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } ccid_header = (CCID_Header *)s->bulk_out_data; usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size); @@ -890,7 +884,7 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) DPRINTF(s, D_VERBOSE, "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n", p->iov.size, ccid_header->dwLength); - return 0; + return; } if (s->bulk_out_pos < 10) { DPRINTF(s, 1, @@ -949,60 +943,52 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) } } s->bulk_out_pos = 0; - return 0; } -static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p) +static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p) { - int ret = 0; + int len = 0; - assert(p->iov.size > 0); ccid_bulk_in_get(s); if (s->current_bulk_in != NULL) { - ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, + len = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, p->iov.size); usb_packet_copy(p, s->current_bulk_in->data + - s->current_bulk_in->pos, ret); - s->current_bulk_in->pos += ret; + s->current_bulk_in->pos, len); + s->current_bulk_in->pos += len; if (s->current_bulk_in->pos == s->current_bulk_in->len) { ccid_bulk_in_release(s); } } else { /* return when device has no data - usb 2.0 spec Table 8-4 */ - ret = USB_RET_NAK; + p->status = USB_RET_NAK; } - if (ret > 0) { + if (len) { DPRINTF(s, D_MORE_INFO, "%s: %zd/%d req/act to guest (BULK_IN)\n", - __func__, p->iov.size, ret); + __func__, p->iov.size, len); } - if (ret != USB_RET_NAK && ret < p->iov.size) { + if (len < p->iov.size) { DPRINTF(s, 1, "%s: returning short (EREMOTEIO) %d < %zd\n", - __func__, ret, p->iov.size); + __func__, len, p->iov.size); } - return ret; } -static int ccid_handle_data(USBDevice *dev, USBPacket *p) +static void ccid_handle_data(USBDevice *dev, USBPacket *p) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); - int ret = 0; uint8_t buf[2]; switch (p->pid) { case USB_TOKEN_OUT: - ret = ccid_handle_bulk_out(s, p); + ccid_handle_bulk_out(s, p); break; case USB_TOKEN_IN: switch (p->ep->nr) { case CCID_BULK_IN_EP: - if (!p->iov.size) { - ret = USB_RET_NAK; - } else { - ret = ccid_bulk_in_copy_to_guest(s, p); - } + ccid_bulk_in_copy_to_guest(s, p); break; case CCID_INT_IN_EP: if (s->notify_slot_change) { @@ -1010,7 +996,6 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p) buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange; buf[1] = s->bmSlotICCState; usb_packet_copy(p, buf, 2); - ret = 2; s->notify_slot_change = false; s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK; DPRINTF(s, D_INFO, @@ -1021,17 +1006,15 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p) break; default: DPRINTF(s, 1, "Bad endpoint\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } break; default: DPRINTF(s, 1, "Bad token\n"); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - - return ret; } static void ccid_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index e732191a26..50af97109b 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -215,7 +215,7 @@ static const USBDesc desc = { static void usb_msd_copy_data(MSDState *s, USBPacket *p) { uint32_t len; - len = p->iov.size - p->result; + len = p->iov.size - p->actual_length; if (len > s->scsi_len) len = s->scsi_len; usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len); @@ -263,7 +263,8 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) if (p) { usb_msd_copy_data(s, p); p = s->packet; - if (p && p->result == p->iov.size) { + if (p && p->actual_length == p->iov.size) { + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ usb_msd_packet_complete(s); } } @@ -292,7 +293,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r s->mode = USB_MSDM_CBW; } else { if (s->data_len) { - int len = (p->iov.size - p->result); + int len = (p->iov.size - p->actual_length); usb_packet_skip(p, len); s->data_len -= len; } @@ -300,6 +301,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r s->mode = USB_MSDM_CSW; } } + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ usb_msd_packet_complete(s); } else if (s->data_len == 0) { s->mode = USB_MSDM_CSW; @@ -330,14 +332,14 @@ static void usb_msd_handle_reset(USBDevice *dev) assert(s->req == NULL); if (s->packet) { - s->packet->result = USB_RET_STALL; + s->packet->status = USB_RET_STALL; usb_msd_packet_complete(s); } s->mode = USB_MSDM_CBW; } -static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, +static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { MSDState *s = (MSDState *)dev; @@ -345,29 +347,25 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch (request) { case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - ret = 0; break; /* Class specific requests. */ case ClassInterfaceOutRequest | MassStorageReset: /* Reset state ready for the next CBW. */ s->mode = USB_MSDM_CBW; - ret = 0; break; case ClassInterfaceRequest | GetMaxLun: data[0] = 0; - ret = 1; + p->actual_length = 1; break; default: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p) @@ -382,11 +380,10 @@ static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p) } } -static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) +static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) { MSDState *s = (MSDState *)dev; uint32_t tag; - int ret = 0; struct usb_msd_cbw cbw; uint8_t devep = p->ep->nr; @@ -433,7 +430,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) { scsi_req_continue(s->req); } - ret = p->result; break; case USB_MSDM_DATAOUT: @@ -446,7 +442,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) usb_msd_copy_data(s, p); } if (le32_to_cpu(s->csw.residue)) { - int len = p->iov.size - p->result; + int len = p->iov.size - p->actual_length; if (len) { usb_packet_skip(p, len); s->data_len -= len; @@ -455,12 +451,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } } } - if (p->result < p->iov.size) { + if (p->actual_length < p->iov.size) { DPRINTF("Deferring packet %p [wait data-out]\n", p); s->packet = p; - ret = USB_RET_ASYNC; - } else { - ret = p->result; + p->status = USB_RET_ASYNC; } break; @@ -481,7 +475,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } /* Waiting for SCSI write to complete. */ s->packet = p; - ret = USB_RET_ASYNC; + p->status = USB_RET_ASYNC; break; case USB_MSDM_CSW: @@ -493,11 +487,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) /* still in flight */ DPRINTF("Deferring packet %p [wait status]\n", p); s->packet = p; - ret = USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } else { usb_msd_send_status(s, p); s->mode = USB_MSDM_CBW; - ret = 13; } break; @@ -508,7 +501,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) usb_msd_copy_data(s, p); } if (le32_to_cpu(s->csw.residue)) { - int len = p->iov.size - p->result; + int len = p->iov.size - p->actual_length; if (len) { usb_packet_skip(p, len); s->data_len -= len; @@ -517,12 +510,10 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) } } } - if (p->result < p->iov.size) { + if (p->actual_length < p->iov.size) { DPRINTF("Deferring packet %p [wait data-in]\n", p); s->packet = p; - ret = USB_RET_ASYNC; - } else { - ret = p->result; + p->status = USB_RET_ASYNC; } break; @@ -535,11 +526,9 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) default: DPRINTF("Bad token\n"); fail: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - - return ret; } static void usb_msd_password_cb(void *opaque, int err) diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 4389380e95..a21b2ba627 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -256,10 +256,10 @@ static void usb_uas_send_status_bh(void *opaque) uas->status = NULL; usb_packet_copy(p, &st->status, st->length); - p->result = st->length; QTAILQ_REMOVE(&uas->results, st, next); g_free(st); + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ usb_packet_complete(&uas->dev, p); } @@ -349,6 +349,7 @@ static void usb_uas_complete_data_packet(UASRequest *req) p = req->data; req->data = NULL; req->data_async = false; + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ usb_packet_complete(&req->uas->dev, p); } @@ -357,16 +358,16 @@ static void usb_uas_copy_data(UASRequest *req) uint32_t length; length = MIN(req->buf_size - req->buf_off, - req->data->iov.size - req->data->result); + req->data->iov.size - req->data->actual_length); trace_usb_uas_xfer_data(req->uas->dev.addr, req->tag, length, - req->data->result, req->data->iov.size, + req->data->actual_length, req->data->iov.size, req->buf_off, req->buf_size); usb_packet_copy(req->data, scsi_req_get_buf(req->req) + req->buf_off, length); req->buf_off += length; req->data_off += length; - if (req->data->result == req->data->iov.size) { + if (req->data->actual_length == req->data->iov.size) { usb_uas_complete_data_packet(req); } if (req->buf_size && req->buf_off == req->buf_size) { @@ -504,17 +505,17 @@ static void usb_uas_handle_reset(USBDevice *dev) } } -static int usb_uas_handle_control(USBDevice *dev, USBPacket *p, +static void usb_uas_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { int ret; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } fprintf(stderr, "%s: unhandled control request\n", __func__); - return USB_RET_STALL; + p->status = USB_RET_STALL; } static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p) @@ -641,13 +642,13 @@ incorrect_lun: usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0); } -static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) +static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) { UASDevice *uas = DO_UPCAST(UASDevice, dev, dev); uas_ui ui; UASStatus *st; UASRequest *req; - int length, ret = 0; + int length; switch (p->ep->nr) { case UAS_PIPE_ID_COMMAND: @@ -656,16 +657,14 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) switch (ui.hdr.id) { case UAS_UI_COMMAND: usb_uas_command(uas, &ui); - ret = length; break; case UAS_UI_TASK_MGMT: usb_uas_task(uas, &ui); - ret = length; break; default: fprintf(stderr, "%s: unknown command ui: id 0x%x\n", __func__, ui.hdr.id); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } break; @@ -674,11 +673,10 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) if (st == NULL) { assert(uas->status == NULL); uas->status = p; - ret = USB_RET_ASYNC; + p->status = USB_RET_ASYNC; break; } usb_packet_copy(p, &st->status, st->length); - ret = st->length; QTAILQ_REMOVE(&uas->results, st, next); g_free(st); break; @@ -687,28 +685,26 @@ static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout; if (req == NULL) { fprintf(stderr, "%s: no inflight request\n", __func__); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } scsi_req_ref(req->req); req->data = p; usb_uas_copy_data(req); - if (p->result == p->iov.size || req->complete) { + if (p->actual_length == p->iov.size || req->complete) { req->data = NULL; - ret = p->result; } else { req->data_async = true; - ret = USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } scsi_req_unref(req->req); usb_uas_start_next_transfer(uas); break; default: fprintf(stderr, "%s: invalid endpoint %d\n", __func__, p->ep->nr); - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } static void usb_uas_handle_destroy(USBDevice *dev) diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index ed9a5ee358..08b416daa6 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -250,7 +250,7 @@ static void usb_wacom_handle_reset(USBDevice *dev) s->mode = WACOM_MODE_HID; } -static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p, +static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBWacomState *s = (USBWacomState *) dev; @@ -258,10 +258,9 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p, ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { - return ret; + return; } - ret = 0; switch (request) { case WACOM_SET_REPORT: if (s->mouse_grabbed) { @@ -269,61 +268,58 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p, s->mouse_grabbed = 0; } s->mode = data[0]; - ret = 0; break; case WACOM_GET_REPORT: data[0] = 0; data[1] = s->mode; - ret = 2; + p->actual_length = 2; break; /* USB HID requests */ case HID_GET_REPORT: if (s->mode == WACOM_MODE_HID) - ret = usb_mouse_poll(s, data, length); + p->actual_length = usb_mouse_poll(s, data, length); else if (s->mode == WACOM_MODE_WACOM) - ret = usb_wacom_poll(s, data, length); + p->actual_length = usb_wacom_poll(s, data, length); break; case HID_GET_IDLE: - ret = 1; data[0] = s->idle; + p->actual_length = 1; break; case HID_SET_IDLE: s->idle = (uint8_t) (value >> 8); - ret = 0; break; default: - ret = USB_RET_STALL; + p->status = USB_RET_STALL; break; } - return ret; } -static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p) +static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p) { USBWacomState *s = (USBWacomState *) dev; uint8_t buf[p->iov.size]; - int ret = 0; + int len = 0; switch (p->pid) { case USB_TOKEN_IN: if (p->ep->nr == 1) { - if (!(s->changed || s->idle)) - return USB_RET_NAK; + if (!(s->changed || s->idle)) { + p->status = USB_RET_NAK; + return; + } s->changed = 0; if (s->mode == WACOM_MODE_HID) - ret = usb_mouse_poll(s, buf, p->iov.size); + len = usb_mouse_poll(s, buf, p->iov.size); else if (s->mode == WACOM_MODE_WACOM) - ret = usb_wacom_poll(s, buf, p->iov.size); - usb_packet_copy(p, buf, ret); + len = usb_wacom_poll(s, buf, p->iov.size); + usb_packet_copy(p, buf, len); break; } /* Fall through. */ case USB_TOKEN_OUT: default: - ret = USB_RET_STALL; - break; + p->status = USB_RET_STALL; } - return ret; } static void usb_wacom_handle_destroy(USBDevice *dev) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index d9dc576e7c..3a1f5134ea 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1163,7 +1163,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) p = container_of(packet, EHCIPacket, packet); assert(p->async == EHCI_ASYNC_INFLIGHT); - if (packet->result == USB_RET_REMOVE_FROM_QUEUE) { + if (packet->status == USB_RET_REMOVE_FROM_QUEUE) { trace_usb_ehci_packet_action(p->queue, p, "remove"); ehci_free_packet(p); return; @@ -1171,7 +1171,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) trace_usb_ehci_packet_action(p->queue, p, "wakeup"); p->async = EHCI_ASYNC_FINISHED; - p->usb_status = packet->result; + p->usb_status = packet->status ? packet->status : packet->actual_length; if (p->queue->async) { qemu_bh_schedule(p->queue->ehci->async_bh); @@ -1253,7 +1253,6 @@ static void ehci_execute_complete(EHCIQueue *q) static int ehci_execute(EHCIPacket *p, const char *action) { USBEndpoint *ep; - int ret; int endp; bool spd; @@ -1303,17 +1302,22 @@ static int ehci_execute(EHCIPacket *p, const char *action) } trace_usb_ehci_packet_action(p->queue, p, action); - ret = usb_handle_packet(p->queue->dev, &p->packet); - DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd endp %x ret %d\n", - q->qhaddr, q->qh.next, q->qtdaddr, q->pid, - q->packet.iov.size, endp, ret); + usb_handle_packet(p->queue->dev, &p->packet); + DPRINTF("submit: qh 0x%x next 0x%x qtd 0x%x pid 0x%x len %zd endp 0x%x " + "status %d actual_length %d\n", p->queue->qhaddr, p->qtd.next, + p->qtdaddr, p->pid, p->packet.iov.size, endp, p->packet.status, + p->packet.actual_length); - if (ret > BUFF_SIZE) { + if (p->packet.actual_length > BUFF_SIZE) { fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n"); return USB_RET_PROCERR; } - return ret; + if (p->packet.status == USB_RET_SUCCESS) { + return p->packet.actual_length; + } else { + return p->packet.status; + } } /* 4.7.2 @@ -1370,8 +1374,10 @@ static int ehci_process_itd(EHCIState *ehci, usb_packet_setup(&ehci->ipacket, pid, ep, addr, false, (itd->transact[i] & ITD_XACT_IOC) != 0); usb_packet_map(&ehci->ipacket, &ehci->isgl); - ret = usb_handle_packet(dev, &ehci->ipacket); + usb_handle_packet(dev, &ehci->ipacket); usb_packet_unmap(&ehci->ipacket, &ehci->isgl); + ret = (ehci->ipacket.status == USB_RET_SUCCESS) ? + ehci->ipacket.actual_length : ehci->ipacket.status; } else { DPRINTF("ISOCH: attempt to addess non-iso endpoint\n"); ret = USB_RET_NAK; diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c index 4f5539020b..c707f7a2bb 100644 --- a/hw/usb/hcd-musb.c +++ b/hw/usb/hcd-musb.c @@ -607,7 +607,6 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, { USBDevice *dev; USBEndpoint *uep; - int ret; int idx = epnum && dir; int ttype; @@ -632,15 +631,19 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, ep->packey[dir].ep = ep; ep->packey[dir].dir = dir; - ret = usb_handle_packet(dev, &ep->packey[dir].p); + usb_handle_packet(dev, &ep->packey[dir].p); - if (ret == USB_RET_ASYNC) { + if (ep->packey[dir].p.status == USB_RET_ASYNC) { usb_device_flush_ep_queue(dev, uep); ep->status[dir] = len; return; } - ep->status[dir] = ret; + if (ep->packey[dir].p.status == USB_RET_SUCCESS) { + ep->status[dir] = ep->packey[dir].p.actual_length; + } else { + ep->status[dir] = ep->packey[dir].p.status; + } musb_schedule_cb(&s->port, &ep->packey[dir].p); } @@ -754,7 +757,6 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque) if (ep->status[1] == USB_RET_STALL) { ep->status[1] = 0; - packey->result = 0; ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL; if (!epnum) @@ -793,14 +795,12 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque) /* TODO: check len for over/underruns of an OUT packet? */ /* TODO: perhaps make use of e->ext_size[1] here. */ - packey->result = ep->status[1]; - if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) { ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY; if (!epnum) ep->csr[0] |= MGC_M_CSR0_RXPKTRDY; - ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */ + ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */ /* In DMA mode: assert DMA request for this EP */ } diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 7571e9e44a..6a39e9697b 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -807,21 +807,24 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, DMA_DIRECTION_TO_DEVICE); } - if (completion) { - ret = ohci->usb_packet.result; - } else { + if (!completion) { bool int_req = relative_frame_number == frame_count && OHCI_BM(iso_td.flags, TD_DI) == 0; dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); usb_packet_setup(&ohci->usb_packet, pid, ep, addr, false, int_req); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); - ret = usb_handle_packet(dev, &ohci->usb_packet); - if (ret == USB_RET_ASYNC) { + usb_handle_packet(dev, &ohci->usb_packet); + if (ohci->usb_packet.status == USB_RET_ASYNC) { usb_device_flush_ep_queue(dev, ep); return 1; } } + if (ohci->usb_packet.status == USB_RET_SUCCESS) { + ret = ohci->usb_packet.actual_length; + } else { + ret = ohci->usb_packet.status; + } #ifdef DEBUG_ISOCH printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n", @@ -997,7 +1000,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) } #endif if (completion) { - ret = ohci->usb_packet.result; ohci->async_td = 0; ohci->async_complete = 0; } else { @@ -1017,16 +1019,22 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) usb_packet_setup(&ohci->usb_packet, pid, ep, addr, !flag_r, OHCI_BM(td.flags, TD_DI) == 0); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); - ret = usb_handle_packet(dev, &ohci->usb_packet); + usb_handle_packet(dev, &ohci->usb_packet); #ifdef DEBUG_PACKET - DPRINTF("ret=%d\n", ret); + DPRINTF("status=%d\n", ohci->usb_packet.status); #endif - if (ret == USB_RET_ASYNC) { + if (ohci->usb_packet.status == USB_RET_ASYNC) { usb_device_flush_ep_queue(dev, ep); ohci->async_td = addr; return 1; } } + if (ohci->usb_packet.status == USB_RET_SUCCESS) { + ret = ohci->usb_packet.actual_length; + } else { + ret = ohci->usb_packet.status; + } + if (ret >= 0) { if (dir == OHCI_TD_DIR_IN) { ohci_copy_td(ohci, &td, ohci->usb_buf, ret, diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index f4b555addc..2838d21644 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -780,22 +780,21 @@ static int uhci_handle_td_error(UHCIState *s, UHCI_TD *td, uint32_t td_addr, static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask) { - int len = 0, max_len, ret; + int len = 0, max_len; uint8_t pid; max_len = ((td->token >> 21) + 1) & 0x7ff; pid = td->token & 0xff; - ret = async->packet.result; - if (td->ctrl & TD_CTRL_IOS) td->ctrl &= ~TD_CTRL_ACTIVE; - if (ret < 0) { - return uhci_handle_td_error(s, td, async->td_addr, ret, int_mask); + if (async->packet.status != USB_RET_SUCCESS) { + return uhci_handle_td_error(s, td, async->td_addr, + async->packet.status, int_mask); } - len = async->packet.result; + len = async->packet.actual_length; td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); /* The NAK bit may have been set by a previous frame, so clear it @@ -824,7 +823,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask) { - int len = 0, max_len; + int ret, max_len; bool spd; bool queuing = (q != NULL); uint8_t pid = td->token & 0xff; @@ -915,13 +914,14 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, switch(pid) { case USB_TOKEN_OUT: case USB_TOKEN_SETUP: - len = usb_handle_packet(q->ep->dev, &async->packet); - if (len >= 0) - len = max_len; + usb_handle_packet(q->ep->dev, &async->packet); + if (async->packet.status == USB_RET_SUCCESS) { + async->packet.actual_length = max_len; + } break; case USB_TOKEN_IN: - len = usb_handle_packet(q->ep->dev, &async->packet); + usb_handle_packet(q->ep->dev, &async->packet); break; default: @@ -932,8 +932,8 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, uhci_update_irq(s); return TD_RESULT_STOP_FRAME; } - - if (len == USB_RET_ASYNC) { + + if (async->packet.status == USB_RET_ASYNC) { uhci_async_link(async); if (!queuing) { uhci_queue_fill(q, td); @@ -941,13 +941,11 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, return TD_RESULT_ASYNC_START; } - async->packet.result = len; - done: - len = uhci_complete_td(s, td, async, int_mask); + ret = uhci_complete_td(s, td, async, int_mask); usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); - return len; + return ret; } static void uhci_async_complete(USBPort *port, USBPacket *packet) @@ -955,7 +953,7 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet) UHCIAsync *async = container_of(packet, UHCIAsync, packet); UHCIState *s = async->queue->uhci; - if (packet->result == USB_RET_REMOVE_FROM_QUEUE) { + if (packet->status == USB_RET_REMOVE_FROM_QUEUE) { uhci_async_unlink(async); uhci_async_cancel(async); return; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 900abf5566..d4a2e0c3ec 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1388,7 +1388,7 @@ static void xhci_xfer_report(XHCITransfer *xfer) XHCIState *xhci = xfer->xhci; int i; - left = xfer->packet.result < 0 ? 0 : xfer->packet.result; + left = xfer->packet.status ? 0 : xfer->packet.actual_length; for (i = 0; i < xfer->trb_count; i++) { XHCITRB *trb = &xfer->trbs[i]; @@ -1490,16 +1490,16 @@ static int xhci_setup_packet(XHCITransfer *xfer) return 0; } -static int xhci_complete_packet(XHCITransfer *xfer, int ret) +static int xhci_complete_packet(XHCITransfer *xfer) { - if (ret == USB_RET_ASYNC) { + if (xfer->packet.status == USB_RET_ASYNC) { trace_usb_xhci_xfer_async(xfer); xfer->running_async = 1; xfer->running_retry = 0; xfer->complete = 0; xfer->cancelled = 0; return 0; - } else if (ret == USB_RET_NAK) { + } else if (xfer->packet.status == USB_RET_NAK) { trace_usb_xhci_xfer_nak(xfer); xfer->running_async = 0; xfer->running_retry = 1; @@ -1513,16 +1513,16 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) xhci_xfer_unmap(xfer); } - if (ret >= 0) { - trace_usb_xhci_xfer_success(xfer, ret); + if (xfer->packet.status == USB_RET_SUCCESS) { + trace_usb_xhci_xfer_success(xfer, xfer->packet.actual_length); xfer->status = CC_SUCCESS; xhci_xfer_report(xfer); return 0; } /* error */ - trace_usb_xhci_xfer_error(xfer, ret); - switch (ret) { + trace_usb_xhci_xfer_error(xfer, xfer->packet.status); + switch (xfer->packet.status) { case USB_RET_NODEV: xfer->status = CC_USB_TRANSACTION_ERROR; xhci_xfer_report(xfer); @@ -1534,7 +1534,8 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) xhci_stall_ep(xfer); break; default: - fprintf(stderr, "%s: FIXME: ret = %d\n", __FUNCTION__, ret); + fprintf(stderr, "%s: FIXME: status = %d\n", __func__, + xfer->packet.status); FIXME(); } return 0; @@ -1544,7 +1545,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) { XHCITRB *trb_setup, *trb_status; uint8_t bmRequestType; - int ret; trb_setup = &xfer->trbs[0]; trb_status = &xfer->trbs[xfer->trb_count-1]; @@ -1587,9 +1587,9 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) } xfer->packet.parameter = trb_setup->parameter; - ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - xhci_complete_packet(xfer, ret); + xhci_complete_packet(xfer); if (!xfer->running_async && !xfer->running_retry) { xhci_kick_ep(xhci, xfer->slotid, xfer->epid); } @@ -1636,7 +1636,6 @@ static void xhci_check_iso_kick(XHCIState *xhci, XHCITransfer *xfer, static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) { uint64_t mfindex; - int ret; DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); @@ -1671,9 +1670,9 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx if (xhci_setup_packet(xfer) < 0) { return -1; } - ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - xhci_complete_packet(xfer, ret); + xhci_complete_packet(xfer); if (!xfer->running_async && !xfer->running_retry) { xhci_kick_ep(xhci, xfer->slotid, xfer->epid); } @@ -1711,7 +1710,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid if (epctx->retry) { XHCITransfer *xfer = epctx->retry; - int result; trace_usb_xhci_xfer_retry(xfer); assert(xfer->running_retry); @@ -1725,19 +1723,19 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid if (xhci_setup_packet(xfer) < 0) { return; } - result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - assert(result != USB_RET_NAK); - xhci_complete_packet(xfer, result); + usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + assert(xfer->packet.status != USB_RET_NAK); + xhci_complete_packet(xfer); } else { /* retry nak'ed transfer */ if (xhci_setup_packet(xfer) < 0) { return; } - result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - if (result == USB_RET_NAK) { + usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + if (xfer->packet.status == USB_RET_NAK) { return; } - xhci_complete_packet(xfer, result); + xhci_complete_packet(xfer); } assert(!xfer->running_retry); epctx->retry = NULL; @@ -2922,11 +2920,11 @@ static void xhci_complete(USBPort *port, USBPacket *packet) { XHCITransfer *xfer = container_of(packet, XHCITransfer, packet); - if (packet->result == USB_RET_REMOVE_FROM_QUEUE) { + if (packet->status == USB_RET_REMOVE_FROM_QUEUE) { xhci_ep_nuke_one_xfer(xfer); return; } - xhci_complete_packet(xfer, packet->result); + xhci_complete_packet(xfer); xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid); } diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c index ec26266620..6473e8b747 100644 --- a/hw/usb/host-bsd.c +++ b/hw/usb/host-bsd.c @@ -121,7 +121,7 @@ static void usb_host_handle_reset(USBDevice *dev) * -check device states against transfer requests * and return appropriate response */ -static int usb_host_handle_control(USBDevice *dev, +static void usb_host_handle_control(USBDevice *dev, USBPacket *p, int request, int value, @@ -139,7 +139,6 @@ static int usb_host_handle_control(USBDevice *dev, /* specific SET_ADDRESS support */ dev->addr = value; - return 0; } else if ((request >> 8) == UT_WRITE_DEVICE && (request & 0xff) == UR_SET_CONFIG) { @@ -151,10 +150,8 @@ static int usb_host_handle_control(USBDevice *dev, printf("handle_control: failed to set configuration - %s\n", strerror(errno)); #endif - return USB_RET_STALL; + p->status = USB_RET_STALL; } - - return 0; } else if ((request >> 8) == UT_WRITE_INTERFACE && (request & 0xff) == UR_SET_INTERFACE) { @@ -168,10 +165,8 @@ static int usb_host_handle_control(USBDevice *dev, printf("handle_control: failed to set alternate interface - %s\n", strerror(errno)); #endif - return USB_RET_STALL; + p->status = USB_RET_STALL; } - - return 0; } else { req.ucr_request.bmRequestType = request >> 8; req.ucr_request.bRequest = request & 0xff; @@ -201,14 +196,14 @@ static int usb_host_handle_control(USBDevice *dev, printf("handle_control: error after request - %s\n", strerror(errno)); #endif - return USB_RET_NAK; // STALL + p->status = USB_RET_NAK; /* STALL */ } else { - return req.ucr_actlen; + p->actual_length = req.ucr_actlen; } } } -static int usb_host_handle_data(USBDevice *dev, USBPacket *p) +static void usb_host_handle_data(USBDevice *dev, USBPacket *p) { USBHostDevice *s = (USBHostDevice *)dev; int ret, fd, mode; @@ -232,7 +227,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) fd = ensure_ep_open(s, devep, mode); if (fd < 0) { sigprocmask(SIG_SETMASK, &old_mask, NULL); - return USB_RET_NODEV; + p->status = USB_RET_NODEV; + return; } if (ioctl(fd, USB_SET_TIMEOUT, &timeout) < 0) { @@ -267,12 +263,13 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) switch(errno) { case ETIMEDOUT: case EINTR: - return USB_RET_NAK; + p->status = USB_RET_NAK; + break; default: - return USB_RET_STALL; + p->status = USB_RET_STALL; } } else { - return ret; + p->actual_length = ret; } } diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 3a258b4bd4..ca3e24a850 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -366,28 +366,29 @@ static void async_complete(void *opaque) if (p) { switch (aurb->urb.status) { case 0: - p->result += aurb->urb.actual_length; + p->actual_length = aurb->urb.actual_length; + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ break; case -EPIPE: set_halt(s, p->pid, p->ep->nr); - p->result = USB_RET_STALL; + p->status = USB_RET_STALL; break; case -EOVERFLOW: - p->result = USB_RET_BABBLE; + p->status = USB_RET_BABBLE; break; default: - p->result = USB_RET_IOERROR; + p->status = USB_RET_IOERROR; break; } if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result); + trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status); usb_generic_async_ctrl_complete(&s->dev, p); } else if (!aurb->more) { - trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result); + trace_usb_host_req_complete(s->bus_num, s->addr, p, p->status); usb_packet_complete(&s->dev, p); } } @@ -733,27 +734,31 @@ static void usb_host_stop_n_free_iso(USBHostDevice *s, int pid, uint8_t ep) clear_iso_started(s, pid, ep); } -static int urb_status_to_usb_ret(int status) +static void urb_status_to_usb_ret(int status, USBPacket *p) { switch (status) { case -EPIPE: - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; case -EOVERFLOW: - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + break; default: - return USB_RET_IOERROR; + p->status = USB_RET_IOERROR; } } -static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) +static void usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) { AsyncURB *aurb; - int i, j, ret, max_packet_size, offset, len = 0; + int i, j, max_packet_size, offset, len; uint8_t *buf; max_packet_size = p->ep->max_packet_size; - if (max_packet_size == 0) - return USB_RET_NAK; + if (max_packet_size == 0) { + p->status = USB_RET_NAK; + return; + } aurb = get_iso_urb(s, p->pid, p->ep->nr); if (!aurb) { @@ -766,18 +771,17 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) if (in) { /* Check urb status */ if (aurb[i].urb.status) { - len = urb_status_to_usb_ret(aurb[i].urb.status); + urb_status_to_usb_ret(aurb[i].urb.status, p); /* Move to the next urb */ aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1; /* Check frame status */ } else if (aurb[i].urb.iso_frame_desc[j].status) { - len = urb_status_to_usb_ret( - aurb[i].urb.iso_frame_desc[j].status); + urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status, p); /* Check the frame fits */ } else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->iov.size) { printf("husb: received iso data is larger then packet\n"); - len = USB_RET_BABBLE; + p->status = USB_RET_BABBLE; /* All good copy data over */ } else { len = aurb[i].urb.iso_frame_desc[j].actual_length; @@ -792,7 +796,8 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) /* Check the frame fits */ if (len > max_packet_size) { printf("husb: send iso data is larger then max packet size\n"); - return USB_RET_NAK; + p->status = USB_RET_NAK; + return; } /* All good copy data over */ @@ -823,17 +828,16 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) /* (Re)-submit all fully consumed / filled urbs */ for (i = 0; i < s->iso_urb_count; i++) { if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) { - ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]); - if (ret < 0) { + if (ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]) < 0) { perror("USBDEVFS_SUBMITURB"); - if (!in || len == 0) { + if (!in || p->status == USB_RET_SUCCESS) { switch(errno) { case ETIMEDOUT: - len = USB_RET_NAK; + p->status = USB_RET_NAK; break; case EPIPE: default: - len = USB_RET_STALL; + p->status = USB_RET_STALL; } } break; @@ -843,11 +847,9 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) } } } - - return len; } -static int usb_host_handle_data(USBDevice *dev, USBPacket *p) +static void usb_host_handle_data(USBDevice *dev, USBPacket *p) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); struct usbdevfs_urb *urb; @@ -862,7 +864,8 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) if (!is_valid(s, p->pid, p->ep->nr)) { trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); - return USB_RET_NAK; + p->status = USB_RET_NAK; + return; } if (p->pid == USB_TOKEN_IN) { @@ -877,13 +880,15 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) if (ret < 0) { perror("USBDEVFS_CLEAR_HALT"); trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); - return USB_RET_NAK; + p->status = USB_RET_NAK; + return; } clear_halt(s, p->pid, p->ep->nr); } if (is_isoc(s, p->pid, p->ep->nr)) { - return usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN); + usb_host_handle_iso_data(s, p, p->pid == USB_TOKEN_IN); + return; } v = 0; @@ -933,17 +938,19 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p) case ETIMEDOUT: trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK); - return USB_RET_NAK; + p->status = USB_RET_NAK; + break; case EPIPE: default: trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_STALL); - return USB_RET_STALL; + p->status = USB_RET_STALL; } + return; } } while (rem > 0); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } static int ctrl_error(void) @@ -955,14 +962,13 @@ static int ctrl_error(void) } } -static int usb_host_set_address(USBHostDevice *s, int addr) +static void usb_host_set_address(USBHostDevice *s, int addr) { trace_usb_host_set_address(s->bus_num, s->addr, addr); s->dev.addr = addr; - return 0; } -static int usb_host_set_config(USBHostDevice *s, int config) +static void usb_host_set_config(USBHostDevice *s, int config, USBPacket *p) { int ret, first = 1; @@ -987,14 +993,15 @@ again: } if (ret < 0) { - return ctrl_error(); + p->status = ctrl_error(); + return; } usb_host_claim_interfaces(s, config); usb_linux_update_endp_table(s); - return 0; } -static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) +static void usb_host_set_interface(USBHostDevice *s, int iface, int alt, + USBPacket *p) { struct usbdevfs_setinterface si; int i, ret; @@ -1011,7 +1018,8 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) } if (iface >= USB_MAX_INTERFACES) { - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } si.interface = iface; @@ -1022,15 +1030,15 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) iface, alt, ret, errno); if (ret < 0) { - return ctrl_error(); + p->status = ctrl_error(); + return; } s->dev.altsetting[iface] = alt; usb_linux_update_endp_table(s); - return 0; } -static int usb_host_handle_control(USBDevice *dev, USBPacket *p, +static void usb_host_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); @@ -1048,19 +1056,19 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, switch (request) { case DeviceOutRequest | USB_REQ_SET_ADDRESS: - ret = usb_host_set_address(s, value); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_address(s, value); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - ret = usb_host_set_config(s, value & 0xff); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_config(s, value & 0xff, p); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - ret = usb_host_set_interface(s, index, value); - trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret); - return ret; + usb_host_set_interface(s, index, value, p); + trace_usb_host_req_emulated(s->bus_num, s->addr, p, p->status); + return; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: if (value == 0) { /* clear halt */ @@ -1068,17 +1076,16 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index); clear_halt(s, pid, index & 0x0f); trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0); - return 0; + return; } } /* The rest are asynchronous */ - assert(p && p->result == 0); - if (length > sizeof(dev->data_buf)) { fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", length, sizeof(dev->data_buf)); - return USB_RET_STALL; + p->status = USB_RET_STALL; + return; } aurb = async_alloc(s); @@ -1112,14 +1119,17 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, switch(errno) { case ETIMEDOUT: - return USB_RET_NAK; + p->status = USB_RET_NAK; + break; case EPIPE: default: - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; } + return; } - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } /* returns 1 on problem encountered or 0 for success */ diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index c5cfe0b313..cd4388e332 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -141,8 +141,8 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, struct usb_redir_interrupt_packet_header *interrupt_header, uint8_t *data, int data_len); -static int usbredir_handle_status(USBRedirDevice *dev, - int status, int actual_len); +static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p, + int status); #define VERSION "qemu usb-redir guest " QEMU_VERSION @@ -443,7 +443,7 @@ static void usbredir_handle_reset(USBDevice *udev) usbredirparser_do_write(dev->parser); } -static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, +static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { int status, len; @@ -500,7 +500,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, !dev->endpoint[EP2I(ep)].bufpq_prefilled) { if (dev->endpoint[EP2I(ep)].bufpq_size < dev->endpoint[EP2I(ep)].bufpq_target_size) { - return usbredir_handle_status(dev, 0, 0); + return; } dev->endpoint[EP2I(ep)].bufpq_prefilled = 1; } @@ -514,7 +514,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, /* Check iso_error for stream errors, otherwise its an underrun */ status = dev->endpoint[EP2I(ep)].iso_error; dev->endpoint[EP2I(ep)].iso_error = 0; - return status ? USB_RET_IOERROR : 0; + p->status = status ? USB_RET_IOERROR : USB_RET_SUCCESS; + return; } DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); @@ -522,7 +523,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, status = isop->status; if (status != usb_redir_success) { bufp_free(dev, isop, ep); - return USB_RET_IOERROR; + p->status = USB_RET_IOERROR; + return; } len = isop->len; @@ -530,11 +532,11 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, ERROR("received iso data is larger then packet ep %02X (%d > %d)\n", ep, len, (int)p->iov.size); bufp_free(dev, isop, ep); - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + return; } usb_packet_copy(p, isop->data, len); bufp_free(dev, isop, ep); - return len; } else { /* If the stream was not started because of a pending error don't send the packet to the usb-host */ @@ -554,7 +556,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, dev->endpoint[EP2I(ep)].iso_error = 0; DPRINTF2("iso-token-out ep %02X status %d len %zd\n", ep, status, p->iov.size); - return usbredir_handle_status(dev, status, p->iov.size); + usbredir_handle_status(dev, p, status); } } @@ -572,7 +574,7 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) usbredir_free_bufpq(dev, ep); } -static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, +static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { struct usb_redir_bulk_packet_header bulk_packet; @@ -581,7 +583,8 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id); if (usbredir_already_in_flight(dev, p->id)) { - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; + return; } bulk_packet.endpoint = ep; @@ -608,10 +611,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, &bulk_packet, buf, size); } usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_handle_interrupt_data(USBRedirDevice *dev, +static void usbredir_handle_interrupt_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { if (ep & USB_DIR_IN) { @@ -643,9 +646,11 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, status = dev->endpoint[EP2I(ep)].interrupt_error; dev->endpoint[EP2I(ep)].interrupt_error = 0; if (status) { - return usbredir_handle_status(dev, status, 0); + usbredir_handle_status(dev, p, status); + } else { + p->status = USB_RET_NAK; } - return USB_RET_NAK; + return; } DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep, intp->status, intp->len); @@ -653,18 +658,19 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, status = intp->status; if (status != usb_redir_success) { bufp_free(dev, intp, ep); - return usbredir_handle_status(dev, status, 0); + usbredir_handle_status(dev, p, status); + return; } len = intp->len; if (len > p->iov.size) { ERROR("received int data is larger then packet ep %02X\n", ep); bufp_free(dev, intp, ep); - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + return; } usb_packet_copy(p, intp->data, len); bufp_free(dev, intp, ep); - return len; } else { /* Output interrupt endpoint, normal async operation */ struct usb_redir_interrupt_packet_header interrupt_packet; @@ -674,7 +680,8 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, p->iov.size, p->id); if (usbredir_already_in_flight(dev, p->id)) { - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; + return; } interrupt_packet.endpoint = ep; @@ -685,7 +692,7 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, usbredirparser_send_interrupt_packet(dev->parser, p->id, &interrupt_packet, buf, p->iov.size); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } } @@ -705,7 +712,7 @@ static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev, usbredir_free_bufpq(dev, ep); } -static int usbredir_handle_data(USBDevice *udev, USBPacket *p) +static void usbredir_handle_data(USBDevice *udev, USBPacket *p) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); uint8_t ep; @@ -718,21 +725,26 @@ static int usbredir_handle_data(USBDevice *udev, USBPacket *p) switch (dev->endpoint[EP2I(ep)].type) { case USB_ENDPOINT_XFER_CONTROL: ERROR("handle_data called for control transfer on ep %02X\n", ep); - return USB_RET_NAK; + p->status = USB_RET_NAK; + break; case USB_ENDPOINT_XFER_ISOC: - return usbredir_handle_iso_data(dev, p, ep); + usbredir_handle_iso_data(dev, p, ep); + break; case USB_ENDPOINT_XFER_BULK: if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN && p->ep->pipeline) { - return USB_RET_ADD_TO_QUEUE; + p->status = USB_RET_ADD_TO_QUEUE; + break; } - return usbredir_handle_bulk_data(dev, p, ep); + usbredir_handle_bulk_data(dev, p, ep); + break; case USB_ENDPOINT_XFER_INT: - return usbredir_handle_interrupt_data(dev, p, ep); + usbredir_handle_interrupt_data(dev, p, ep); + break; default: ERROR("handle_data ep %02X has unknown type %d\n", ep, dev->endpoint[EP2I(ep)].type); - return USB_RET_NAK; + p->status = USB_RET_NAK; } } @@ -743,7 +755,7 @@ static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) } } -static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p, +static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p, int config) { struct usb_redir_set_configuration_header set_config; @@ -768,19 +780,19 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p, set_config.configuration = config; usbredirparser_send_set_configuration(dev->parser, p->id, &set_config); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p) +static void usbredir_get_config(USBRedirDevice *dev, USBPacket *p) { DPRINTF("get config id %"PRIu64"\n", p->id); usbredirparser_send_get_configuration(dev->parser, p->id); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, +static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, int interface, int alt) { struct usb_redir_set_alt_setting_header set_alt; @@ -808,10 +820,10 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, set_alt.alt = alt; usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, +static void usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, int interface) { struct usb_redir_get_alt_setting_header get_alt; @@ -821,17 +833,18 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, get_alt.interface = interface; usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt); usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } -static int usbredir_handle_control(USBDevice *udev, USBPacket *p, +static void usbredir_handle_control(USBDevice *udev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); struct usb_redir_control_packet_header control_packet; if (usbredir_already_in_flight(dev, p->id)) { - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; + return; } /* Special cases for certain standard device requests */ @@ -839,15 +852,19 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, case DeviceOutRequest | USB_REQ_SET_ADDRESS: DPRINTF("set address %d\n", value); dev->dev.addr = value; - return 0; + return; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - return usbredir_set_config(dev, p, value & 0xff); + usbredir_set_config(dev, p, value & 0xff); + return; case DeviceRequest | USB_REQ_GET_CONFIGURATION: - return usbredir_get_config(dev, p); + usbredir_get_config(dev, p); + return; case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - return usbredir_set_interface(dev, p, index, value); + usbredir_set_interface(dev, p, index, value); + return; case InterfaceRequest | USB_REQ_GET_INTERFACE: - return usbredir_get_interface(dev, p, index); + usbredir_get_interface(dev, p, index); + return; } /* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */ @@ -871,7 +888,7 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, &control_packet, data, length); } usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; + p->status = USB_RET_ASYNC; } /* @@ -1159,29 +1176,34 @@ error: * usbredirparser packet complete callbacks */ -static int usbredir_handle_status(USBRedirDevice *dev, - int status, int actual_len) +static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p, + int status) { switch (status) { case usb_redir_success: - return actual_len; + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ + break; case usb_redir_stall: - return USB_RET_STALL; + p->status = USB_RET_STALL; + break; case usb_redir_cancelled: /* * When the usbredir-host unredirects a device, it will report a status * of cancelled for all pending packets, followed by a disconnect msg. */ - return USB_RET_IOERROR; + p->status = USB_RET_IOERROR; + break; case usb_redir_inval: WARNING("got invalid param error from usb-host?\n"); - return USB_RET_IOERROR; + p->status = USB_RET_IOERROR; + break; case usb_redir_babble: - return USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + break; case usb_redir_ioerror: case usb_redir_timeout: default: - return USB_RET_IOERROR; + p->status = USB_RET_IOERROR; } } @@ -1412,7 +1434,6 @@ static void usbredir_configuration_status(void *priv, uint64_t id, { USBRedirDevice *dev = priv; USBPacket *p; - int len = 0; DPRINTF("set config status %d config %d id %"PRIu64"\n", config_status->status, config_status->configuration, id); @@ -1421,9 +1442,9 @@ static void usbredir_configuration_status(void *priv, uint64_t id, if (p) { if (dev->dev.setup_buf[0] & USB_DIR_IN) { dev->dev.data_buf[0] = config_status->configuration; - len = 1; + p->actual_length = 1; } - p->result = usbredir_handle_status(dev, config_status->status, len); + usbredir_handle_status(dev, p, config_status->status); usb_generic_async_ctrl_complete(&dev->dev, p); } } @@ -1433,7 +1454,6 @@ static void usbredir_alt_setting_status(void *priv, uint64_t id, { USBRedirDevice *dev = priv; USBPacket *p; - int len = 0; DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n", alt_setting_status->status, alt_setting_status->interface, @@ -1443,10 +1463,9 @@ static void usbredir_alt_setting_status(void *priv, uint64_t id, if (p) { if (dev->dev.setup_buf[0] & USB_DIR_IN) { dev->dev.data_buf[0] = alt_setting_status->alt; - len = 1; + p->actual_length = 1; } - p->result = - usbredir_handle_status(dev, alt_setting_status->status, len); + usbredir_handle_status(dev, p, alt_setting_status->status); usb_generic_async_ctrl_complete(&dev->dev, p); } } @@ -1522,18 +1541,19 @@ static void usbredir_control_packet(void *priv, uint64_t id, p = usbredir_find_packet_by_id(dev, 0, id); if (p) { - len = usbredir_handle_status(dev, control_packet->status, len); - if (len > 0) { + usbredir_handle_status(dev, p, control_packet->status); + if (p->status == USB_RET_SUCCESS) { usbredir_log_data(dev, "ctrl data in:", data, data_len); if (data_len <= sizeof(dev->dev.data_buf)) { memcpy(dev->dev.data_buf, data, data_len); } else { ERROR("ctrl buffer too small (%d > %zu)\n", data_len, sizeof(dev->dev.data_buf)); - len = USB_RET_STALL; + p->status = USB_RET_STALL; + len = 0; } } - p->result = len; + p->actual_length = len; usb_generic_async_ctrl_complete(&dev->dev, p); } free(data); @@ -1554,8 +1574,8 @@ static void usbredir_bulk_packet(void *priv, uint64_t id, p = usbredir_find_packet_by_id(dev, ep, id); if (p) { size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; - len = usbredir_handle_status(dev, bulk_packet->status, len); - if (len > 0) { + usbredir_handle_status(dev, p, bulk_packet->status); + if (p->status == USB_RET_SUCCESS) { usbredir_log_data(dev, "bulk data in:", data, data_len); if (data_len <= size) { if (p->combined) { @@ -1567,10 +1587,11 @@ static void usbredir_bulk_packet(void *priv, uint64_t id, } else { ERROR("bulk got more data then requested (%d > %zd)\n", data_len, p->iov.size); - len = USB_RET_BABBLE; + p->status = USB_RET_BABBLE; + len = 0; } } - p->result = len; + p->actual_length = len; if (p->pid == USB_TOKEN_IN && p->ep->pipeline) { usb_combined_input_packet_complete(&dev->dev, p); } else { @@ -1636,8 +1657,8 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, USBPacket *p = usbredir_find_packet_by_id(dev, ep, id); if (p) { - p->result = usbredir_handle_status(dev, - interrupt_packet->status, len); + usbredir_handle_status(dev, p, interrupt_packet->status); + p->actual_length = len; usb_packet_complete(&dev->dev, p); } } From e94ca437ba92f6e0aeeb0dbda75e158479d413b7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Nov 2012 17:15:02 +0100 Subject: [PATCH 09/67] usb-redir: Allow packets to have both data and an error-status Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 56 +++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index cd4388e332..be9a232059 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -521,22 +521,16 @@ static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); status = isop->status; - if (status != usb_redir_success) { - bufp_free(dev, isop, ep); - p->status = USB_RET_IOERROR; - return; - } - len = isop->len; if (len > p->iov.size) { ERROR("received iso data is larger then packet ep %02X (%d > %d)\n", ep, len, (int)p->iov.size); - bufp_free(dev, isop, ep); - p->status = USB_RET_BABBLE; - return; + len = p->iov.size; + status = usb_redir_babble; } usb_packet_copy(p, isop->data, len); bufp_free(dev, isop, ep); + usbredir_handle_status(dev, p, status); } else { /* If the stream was not started because of a pending error don't send the packet to the usb-host */ @@ -656,21 +650,15 @@ static void usbredir_handle_interrupt_data(USBRedirDevice *dev, intp->status, intp->len); status = intp->status; - if (status != usb_redir_success) { - bufp_free(dev, intp, ep); - usbredir_handle_status(dev, p, status); - return; - } - len = intp->len; if (len > p->iov.size) { ERROR("received int data is larger then packet ep %02X\n", ep); - bufp_free(dev, intp, ep); - p->status = USB_RET_BABBLE; - return; + len = p->iov.size; + status = usb_redir_babble; } usb_packet_copy(p, intp->data, len); bufp_free(dev, intp, ep); + usbredir_handle_status(dev, p, status); } else { /* Output interrupt endpoint, normal async operation */ struct usb_redir_interrupt_packet_header interrupt_packet; @@ -1542,16 +1530,15 @@ static void usbredir_control_packet(void *priv, uint64_t id, p = usbredir_find_packet_by_id(dev, 0, id); if (p) { usbredir_handle_status(dev, p, control_packet->status); - if (p->status == USB_RET_SUCCESS) { + if (data_len > 0) { usbredir_log_data(dev, "ctrl data in:", data, data_len); - if (data_len <= sizeof(dev->dev.data_buf)) { - memcpy(dev->dev.data_buf, data, data_len); - } else { + if (data_len > sizeof(dev->dev.data_buf)) { ERROR("ctrl buffer too small (%d > %zu)\n", data_len, sizeof(dev->dev.data_buf)); p->status = USB_RET_STALL; - len = 0; + data_len = len = sizeof(dev->dev.data_buf); } + memcpy(dev->dev.data_buf, data, data_len); } p->actual_length = len; usb_generic_async_ctrl_complete(&dev->dev, p); @@ -1575,20 +1562,19 @@ static void usbredir_bulk_packet(void *priv, uint64_t id, if (p) { size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; usbredir_handle_status(dev, p, bulk_packet->status); - if (p->status == USB_RET_SUCCESS) { + if (data_len > 0) { usbredir_log_data(dev, "bulk data in:", data, data_len); - if (data_len <= size) { - if (p->combined) { - iov_from_buf(p->combined->iov.iov, p->combined->iov.niov, - 0, data, data_len); - } else { - usb_packet_copy(p, data, data_len); - } - } else { + if (data_len > size) { ERROR("bulk got more data then requested (%d > %zd)\n", data_len, p->iov.size); p->status = USB_RET_BABBLE; - len = 0; + data_len = len = size; + } + if (p->combined) { + iov_from_buf(p->combined->iov.iov, p->combined->iov.niov, + 0, data, data_len); + } else { + usb_packet_copy(p, data, data_len); } } p->actual_length = len; @@ -1653,12 +1639,10 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, /* bufp_alloc also adds the packet to the ep queue */ bufp_alloc(dev, data, data_len, interrupt_packet->status, ep); } else { - int len = interrupt_packet->length; - USBPacket *p = usbredir_find_packet_by_id(dev, ep, id); if (p) { usbredir_handle_status(dev, p, interrupt_packet->status); - p->actual_length = len; + p->actual_length = interrupt_packet->length; usb_packet_complete(&dev->dev, p); } } From 01e26b0ea3c289efc58d31e28408e42c3fcded22 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Nov 2012 17:15:03 +0100 Subject: [PATCH 10/67] ehci: Get rid of the magical PROC_ERR status Instead make ehci_execute and ehci_fill_queue return the again value. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 55 +++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 3a1f5134ea..73be5757f8 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -29,9 +29,6 @@ #include "hw/usb/hcd-ehci.h" -/* internal processing - reset HC to try and recover */ -#define USB_RET_PROCERR (-99) - /* Capability Registers Base Address - section 2.2 */ #define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */ #define HCIVERSION 0x0002 /* 2-bytes, i/f version # */ @@ -1111,7 +1108,7 @@ static int ehci_init_transfer(EHCIPacket *p) while (bytes > 0) { if (cpage > 4) { fprintf(stderr, "cpage out of range (%d)\n", cpage); - return USB_RET_PROCERR; + return -1; } page = p->qtd.bufptr[cpage] & QTD_BUFPTR_MASK; @@ -1248,8 +1245,7 @@ static void ehci_execute_complete(EHCIQueue *q) } } -// 4.10.3 - +/* 4.10.3 returns "again" */ static int ehci_execute(EHCIPacket *p, const char *action) { USBEndpoint *ep; @@ -1261,13 +1257,13 @@ static int ehci_execute(EHCIPacket *p, const char *action) if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) { fprintf(stderr, "Attempting to execute inactive qtd\n"); - return USB_RET_PROCERR; + return -1; } if (get_field(p->qtd.token, QTD_TOKEN_TBYTES) > BUFF_SIZE) { ehci_trace_guest_bug(p->queue->ehci, "guest requested more bytes than allowed"); - return USB_RET_PROCERR; + return -1; } p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH; @@ -1291,7 +1287,7 @@ static int ehci_execute(EHCIPacket *p, const char *action) if (p->async == EHCI_ASYNC_NONE) { if (ehci_init_transfer(p) != 0) { - return USB_RET_PROCERR; + return -1; } spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0); @@ -1310,14 +1306,10 @@ static int ehci_execute(EHCIPacket *p, const char *action) if (p->packet.actual_length > BUFF_SIZE) { fprintf(stderr, "ret from usb_handle_packet > BUFF_SIZE\n"); - return USB_RET_PROCERR; + return -1; } - if (p->packet.status == USB_RET_SUCCESS) { - return p->packet.actual_length; - } else { - return p->packet.status; - } + return 1; } /* 4.7.2 @@ -1352,7 +1344,7 @@ static int ehci_process_itd(EHCIState *ehci, } if (len > BUFF_SIZE) { - return USB_RET_PROCERR; + return -1; } qemu_sglist_init(&ehci->isgl, 2, ehci->dma); @@ -1752,8 +1744,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q) break; case EHCI_ASYNC_INFLIGHT: /* Check if the guest has added new tds to the queue */ - again = (ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)) == - USB_RET_PROCERR) ? -1 : 1; + again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head)); /* Unfinished async handled packet, go horizontal */ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); break; @@ -1790,6 +1781,7 @@ static int ehci_state_horizqh(EHCIQueue *q) return again; } +/* Returns "again" */ static int ehci_fill_queue(EHCIPacket *p) { USBEndpoint *ep = p->packet.ep; @@ -1818,17 +1810,14 @@ static int ehci_fill_queue(EHCIPacket *p) p = ehci_alloc_packet(q); p->qtdaddr = qtdaddr; p->qtd = qtd; - p->usb_status = ehci_execute(p, "queue"); - if (p->usb_status == USB_RET_PROCERR) { - break; + if (ehci_execute(p, "queue") == -1) { + return -1; } - assert(p->usb_status == USB_RET_ASYNC); + assert(p->packet.status == USB_RET_ASYNC); p->async = EHCI_ASYNC_INFLIGHT; } - if (p->usb_status != USB_RET_PROCERR) { - usb_device_flush_ep_queue(ep->dev, ep); - } - return p->usb_status; + usb_device_flush_ep_queue(ep->dev, ep); + return 1; } static int ehci_state_execute(EHCIQueue *q) @@ -1857,23 +1846,27 @@ static int ehci_state_execute(EHCIQueue *q) ehci_set_usbsts(q->ehci, USBSTS_REC); } - p->usb_status = ehci_execute(p, "process"); - if (p->usb_status == USB_RET_PROCERR) { - again = -1; + again = ehci_execute(p, "process"); + if (again == -1) { goto out; } - if (p->usb_status == USB_RET_ASYNC) { + if (p->packet.status == USB_RET_ASYNC) { ehci_flush_qh(q); trace_usb_ehci_packet_action(p->queue, p, "async"); p->async = EHCI_ASYNC_INFLIGHT; ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); if (q->async) { - again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; + again = ehci_fill_queue(p); } else { again = 1; } goto out; } + if (p->packet.status == USB_RET_SUCCESS) { + p->usb_status = p->packet.actual_length; + } else { + p->usb_status = p->packet.status; + } ehci_set_state(q->ehci, q->async, EST_EXECUTING); again = 1; From e696b1da42cd80787d45f6e9a6329d9ef3c8acb2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Nov 2012 17:15:04 +0100 Subject: [PATCH 11/67] ehci: Add support for packets with both data and an error status Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 161 ++++++++++++++++++++++------------------------ hw/usb/hcd-ehci.h | 1 - 2 files changed, 77 insertions(+), 85 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 73be5757f8..ee6c9ae302 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1126,16 +1126,16 @@ static int ehci_init_transfer(EHCIPacket *p) return 0; } -static void ehci_finish_transfer(EHCIQueue *q, int status) +static void ehci_finish_transfer(EHCIQueue *q, int len) { uint32_t cpage, offset; - if (status > 0) { + if (len > 0) { /* update cpage & offset */ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE); offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK; - offset += status; + offset += len; cpage += offset >> QTD_BUFPTR_SH; offset &= ~QTD_BUFPTR_MASK; @@ -1168,7 +1168,6 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) trace_usb_ehci_packet_action(p->queue, p, "wakeup"); p->async = EHCI_ASYNC_FINISHED; - p->usb_status = packet->status ? packet->status : packet->actual_length; if (p->queue->async) { qemu_bh_schedule(p->queue->ehci->async_bh); @@ -1178,58 +1177,60 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) static void ehci_execute_complete(EHCIQueue *q) { EHCIPacket *p = QTAILQ_FIRST(&q->packets); + uint32_t tbytes; assert(p != NULL); assert(p->qtdaddr == q->qtdaddr); assert(p->async == EHCI_ASYNC_INITIALIZED || p->async == EHCI_ASYNC_FINISHED); - DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n", - q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); + DPRINTF("execute_complete: qhaddr 0x%x, next 0x%x, qtdaddr 0x%x, " + "status %d, actual_length %d\n", + q->qhaddr, q->qh.next, q->qtdaddr, + p->packet.status, p->packet.actual_length); - if (p->usb_status < 0) { - switch (p->usb_status) { - case USB_RET_IOERROR: - case USB_RET_NODEV: - q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); - set_field(&q->qh.token, 0, QTD_TOKEN_CERR); - ehci_raise_irq(q->ehci, USBSTS_ERRINT); - break; - case USB_RET_STALL: - q->qh.token |= QTD_TOKEN_HALT; - ehci_raise_irq(q->ehci, USBSTS_ERRINT); - break; - case USB_RET_NAK: - set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT); - return; /* We're not done yet with this transaction */ - case USB_RET_BABBLE: - q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); - ehci_raise_irq(q->ehci, USBSTS_ERRINT); - break; - default: - /* should not be triggerable */ - fprintf(stderr, "USB invalid response %d\n", p->usb_status); - assert(0); - break; + switch (p->packet.status) { + case USB_RET_SUCCESS: + break; + case USB_RET_IOERROR: + case USB_RET_NODEV: + q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); + set_field(&q->qh.token, 0, QTD_TOKEN_CERR); + ehci_raise_irq(q->ehci, USBSTS_ERRINT); + break; + case USB_RET_STALL: + q->qh.token |= QTD_TOKEN_HALT; + ehci_raise_irq(q->ehci, USBSTS_ERRINT); + break; + case USB_RET_NAK: + set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT); + return; /* We're not done yet with this transaction */ + case USB_RET_BABBLE: + q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); + ehci_raise_irq(q->ehci, USBSTS_ERRINT); + break; + default: + /* should not be triggerable */ + fprintf(stderr, "USB invalid response %d\n", p->packet.status); + assert(0); + break; + } + + /* TODO check 4.12 for splits */ + tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES); + if (tbytes && p->pid == USB_TOKEN_IN) { + tbytes -= p->packet.actual_length; + if (tbytes) { + /* 4.15.1.2 must raise int on a short input packet */ + ehci_raise_irq(q->ehci, USBSTS_INT); } } else { - // TODO check 4.12 for splits - uint32_t tbytes = get_field(q->qh.token, QTD_TOKEN_TBYTES); - - if (tbytes && p->pid == USB_TOKEN_IN) { - tbytes -= p->usb_status; - if (tbytes) { - /* 4.15.1.2 must raise int on a short input packet */ - ehci_raise_irq(q->ehci, USBSTS_INT); - } - } else { - tbytes = 0; - } - - DPRINTF("updating tbytes to %d\n", tbytes); - set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES); + tbytes = 0; } - ehci_finish_transfer(q, p->usb_status); + DPRINTF("updating tbytes to %d\n", tbytes); + set_field(&q->qh.token, tbytes, QTD_TOKEN_TBYTES); + + ehci_finish_transfer(q, p->packet.actual_length); usb_packet_unmap(&p->packet, &p->sgl); qemu_sglist_destroy(&p->sgl); p->async = EHCI_ASYNC_NONE; @@ -1321,7 +1322,6 @@ static int ehci_process_itd(EHCIState *ehci, { USBDevice *dev; USBEndpoint *ep; - int ret; uint32_t i, len, pid, dir, devaddr, endp; uint32_t pg, off, ptr1, ptr2, max, mult; @@ -1368,45 +1368,43 @@ static int ehci_process_itd(EHCIState *ehci, usb_packet_map(&ehci->ipacket, &ehci->isgl); usb_handle_packet(dev, &ehci->ipacket); usb_packet_unmap(&ehci->ipacket, &ehci->isgl); - ret = (ehci->ipacket.status == USB_RET_SUCCESS) ? - ehci->ipacket.actual_length : ehci->ipacket.status; } else { DPRINTF("ISOCH: attempt to addess non-iso endpoint\n"); - ret = USB_RET_NAK; + ehci->ipacket.status = USB_RET_NAK; + ehci->ipacket.actual_length = 0; } qemu_sglist_destroy(&ehci->isgl); - if (ret < 0) { - switch (ret) { - default: - fprintf(stderr, "Unexpected iso usb result: %d\n", ret); - /* Fall through */ - case USB_RET_IOERROR: - case USB_RET_NODEV: - /* 3.3.2: XACTERR is only allowed on IN transactions */ - if (dir) { - itd->transact[i] |= ITD_XACT_XACTERR; - ehci_raise_irq(ehci, USBSTS_ERRINT); - } - break; - case USB_RET_BABBLE: - itd->transact[i] |= ITD_XACT_BABBLE; + switch (ehci->ipacket.status) { + case USB_RET_SUCCESS: + break; + default: + fprintf(stderr, "Unexpected iso usb result: %d\n", + ehci->ipacket.status); + /* Fall through */ + case USB_RET_IOERROR: + case USB_RET_NODEV: + /* 3.3.2: XACTERR is only allowed on IN transactions */ + if (dir) { + itd->transact[i] |= ITD_XACT_XACTERR; ehci_raise_irq(ehci, USBSTS_ERRINT); - break; - case USB_RET_NAK: - /* no data for us, so do a zero-length transfer */ - ret = 0; - break; } + break; + case USB_RET_BABBLE: + itd->transact[i] |= ITD_XACT_BABBLE; + ehci_raise_irq(ehci, USBSTS_ERRINT); + break; + case USB_RET_NAK: + /* no data for us, so do a zero-length transfer */ + ehci->ipacket.actual_length = 0; + break; } - if (ret >= 0) { - if (!dir) { - /* OUT */ - set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH); - } else { - /* IN */ - set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); - } + if (!dir) { + set_field(&itd->transact[i], len - ehci->ipacket.actual_length, + ITD_XACT_LENGTH); /* OUT */ + } else { + set_field(&itd->transact[i], ehci->ipacket.actual_length, + ITD_XACT_LENGTH); /* IN */ } if (itd->transact[i] & ITD_XACT_IOC) { ehci_raise_irq(ehci, USBSTS_INT); @@ -1862,11 +1860,6 @@ static int ehci_state_execute(EHCIQueue *q) } goto out; } - if (p->packet.status == USB_RET_SUCCESS) { - p->usb_status = p->packet.actual_length; - } else { - p->usb_status = p->packet.status; - } ehci_set_state(q->ehci, q->async, EST_EXECUTING); again = 1; @@ -1890,7 +1883,7 @@ static int ehci_state_executing(EHCIQueue *q) } /* 4.10.5 */ - if (p->usb_status == USB_RET_NAK) { + if (p->packet.status == USB_RET_NAK) { ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); } else { ehci_set_state(q->ehci, q->async, EST_WRITEBACK); diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 0ec675c352..d8078f4555 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -230,7 +230,6 @@ struct EHCIPacket { QEMUSGList sgl; int pid; enum async_state async; - int usb_status; }; struct EHCIQueue { From 9b8251c5c44a70a63c642e4e345fa8c12ed022ed Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Nov 2012 17:15:05 +0100 Subject: [PATCH 12/67] xhci: Add support for packets with both data and an error status Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-xhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index d4a2e0c3ec..a181d45910 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1388,7 +1388,7 @@ static void xhci_xfer_report(XHCITransfer *xfer) XHCIState *xhci = xfer->xhci; int i; - left = xfer->packet.status ? 0 : xfer->packet.actual_length; + left = xfer->packet.actual_length; for (i = 0; i < xfer->trb_count; i++) { XHCITRB *trb = &xfer->trbs[i]; @@ -1416,7 +1416,7 @@ static void xhci_xfer_report(XHCITransfer *xfer) if (!reported && ((trb->control & TRB_TR_IOC) || (shortpkt && (trb->control & TRB_TR_ISP)) || - (xfer->status != CC_SUCCESS))) { + (xfer->status != CC_SUCCESS && left == 0))) { event.slotid = xfer->slotid; event.epid = xfer->epid; event.length = (trb->status & 0x1ffff) - chunk; From ffd8a97fb33d3b036d61c508bd73ee7fa4051c6b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Nov 2012 17:15:06 +0100 Subject: [PATCH 13/67] usb/combined-packet: Move freeing of combined to usb_combined_packet_remove() Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/combined-packet.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c index e72219894b..4a0c299457 100644 --- a/hw/usb/combined-packet.c +++ b/hw/usb/combined-packet.c @@ -31,12 +31,16 @@ static void usb_combined_packet_add(USBCombinedPacket *combined, USBPacket *p) p->combined = combined; } +/* Note will free combined when the last packet gets removed */ static void usb_combined_packet_remove(USBCombinedPacket *combined, USBPacket *p) { assert(p->combined == combined); p->combined = NULL; QTAILQ_REMOVE(&combined->packets, p, combined_entry); + if (QTAILQ_EMPTY(&combined->packets)) { + g_free(combined); + } } /* Also handles completion of non combined packets for pipelined input eps */ @@ -45,9 +49,8 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p) USBCombinedPacket *combined = p->combined; USBEndpoint *ep = p->ep; USBPacket *next; - enum { completing, complete, leftover }; - int status, actual_length, state = completing; - bool short_not_ok; + int status, actual_length; + bool short_not_ok, done = false; if (combined == NULL) { usb_packet_complete_one(dev, p); @@ -61,39 +64,34 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p) short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok; QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) { - if (state == completing) { + if (!done) { /* Distribute data over uncombined packets */ if (actual_length >= p->iov.size) { p->actual_length = p->iov.size; } else { /* Send short or error packet to complete the transfer */ p->actual_length = actual_length; - state = complete; + done = true; } /* Report status on the last packet */ - if (state == complete || next == NULL) { + if (done || next == NULL) { p->status = status; } else { p->status = USB_RET_SUCCESS; } p->short_not_ok = short_not_ok; + /* Note will free combined when the last packet gets removed! */ usb_combined_packet_remove(combined, p); usb_packet_complete_one(dev, p); actual_length -= p->actual_length; } else { /* Remove any leftover packets from the queue */ - state = leftover; p->status = USB_RET_REMOVE_FROM_QUEUE; + /* Note will free combined on the last packet! */ dev->port->ops->complete(dev->port, p); } } - /* - * If we had leftover packets the hcd driver will have cancelled them - * and usb_combined_packet_cancel has already freed combined! - */ - if (state != leftover) { - g_free(combined); - } + /* Do not use combined here, it has been freed! */ leave: /* Check if there are packets in the queue waiting for our completion */ usb_ep_combine_input_packets(ep); @@ -104,14 +102,13 @@ void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p) { USBCombinedPacket *combined = p->combined; assert(combined != NULL); + USBPacket *first = p->combined->first; + /* Note will free combined on the last packet! */ usb_combined_packet_remove(combined, p); - if (p == combined->first) { + if (p == first) { usb_device_cancel_packet(dev, p); } - if (QTAILQ_EMPTY(&combined->packets)) { - g_free(combined); - } } /* From 616b5d53ae81a94a4aabe8a87a5d950e9d349bc5 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 5 Nov 2012 14:29:01 +1100 Subject: [PATCH 14/67] xhci: Fix some DMA host endian bugs The xhci device does correct endian switches on the results of some DMAs but not all. In particular, there are many DMAs of what are essentially arrays of 32-bit integers which never get byteswapped. This causes them to be interpreted incorrectly on big-endian hosts, since (as per the xhci spec) these arrays are always little-endian in guest memory. This patch adds some helper functions to fix these bugs. This may not be all the endian bugs in the xhci code, but it's certainly some of them and the Linux guest xhci driver certainly gets further with these fixes. Signed-off-by: David Gibson Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-xhci.c | 81 +++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index a181d45910..8ef4b0730e 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -634,6 +634,34 @@ static inline dma_addr_t xhci_mask64(uint64_t addr) } } +static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr, + uint32_t *buf, size_t len) +{ + int i; + + assert((len % sizeof(uint32_t)) == 0); + + pci_dma_read(&xhci->pci_dev, addr, buf, len); + + for (i = 0; i < (len / sizeof(uint32_t)); i++) { + buf[i] = le32_to_cpu(buf[i]); + } +} + +static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr, + uint32_t *buf, size_t len) +{ + int i; + uint32_t tmp[len / sizeof(uint32_t)]; + + assert((len % sizeof(uint32_t)) == 0); + + for (i = 0; i < (len / sizeof(uint32_t)); i++) { + tmp[i] = cpu_to_le32(buf[i]); + } + pci_dma_write(&xhci->pci_dev, addr, tmp, len); +} + static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) { int index; @@ -1045,14 +1073,14 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, { uint32_t ctx[5]; - pci_dma_read(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx)); + xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx)); ctx[0] &= ~EP_STATE_MASK; ctx[0] |= state; ctx[2] = epctx->ring.dequeue | epctx->ring.ccs; ctx[3] = (epctx->ring.dequeue >> 16) >> 16; DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n", epctx->pctx, state, ctx[3], ctx[2]); - pci_dma_write(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx)); + xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx)); epctx->state = state; } @@ -1881,14 +1909,14 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, assert(slotid >= 1 && slotid <= xhci->numslots); dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); - pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx)); + poctx = ldq_le_pci_dma(&xhci->pci_dev, dcbaap + 8*slotid); ictx = xhci_mask64(pictx); - octx = xhci_mask64(le64_to_cpu(poctx)); + octx = xhci_mask64(poctx); DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx); DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx); - pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx)); + xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx)); if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) { fprintf(stderr, "xhci: invalid input context control %08x %08x\n", @@ -1896,8 +1924,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, return CC_TRB_ERROR; } - pci_dma_read(&xhci->pci_dev, ictx+32, slot_ctx, sizeof(slot_ctx)); - pci_dma_read(&xhci->pci_dev, ictx+64, ep0_ctx, sizeof(ep0_ctx)); + xhci_dma_read_u32s(xhci, ictx+32, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, ictx+64, ep0_ctx, sizeof(ep0_ctx)); DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); @@ -1951,8 +1979,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n", ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); - pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx)); return res; } @@ -1985,17 +2013,17 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, } } - pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT); slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT; DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); return CC_SUCCESS; } - pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx)); + xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx)); if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) { fprintf(stderr, "xhci: invalid input context control %08x %08x\n", @@ -2003,8 +2031,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, return CC_TRB_ERROR; } - pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx)); - pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx)); + xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) { fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]); @@ -2016,8 +2044,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, xhci_disable_ep(xhci, slotid, i); } if (ictl_ctx[1] & (1<pci_dev, ictx+32+(32*i), ep_ctx, - sizeof(ep_ctx)); + xhci_dma_read_u32s(xhci, ictx+32+(32*i), ep_ctx, sizeof(ep_ctx)); DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n", i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2], ep_ctx[3], ep_ctx[4]); @@ -2029,7 +2056,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n", i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2], ep_ctx[3], ep_ctx[4]); - pci_dma_write(&xhci->pci_dev, octx+(32*i), ep_ctx, sizeof(ep_ctx)); + xhci_dma_write_u32s(xhci, octx+(32*i), ep_ctx, sizeof(ep_ctx)); } } @@ -2041,7 +2068,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); return CC_SUCCESS; } @@ -2066,7 +2093,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx); DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx); - pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx)); + xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx)); if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) { fprintf(stderr, "xhci: invalid input context control %08x %08x\n", @@ -2075,12 +2102,12 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, } if (ictl_ctx[1] & 0x1) { - pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx)); + xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx)); DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n", islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]); - pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); slot_ctx[1] &= ~0xFFFF; /* max exit latency */ slot_ctx[1] |= islot_ctx[1] & 0xFFFF; @@ -2090,17 +2117,17 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); } if (ictl_ctx[1] & 0x2) { - pci_dma_read(&xhci->pci_dev, ictx+64, iep0_ctx, sizeof(iep0_ctx)); + xhci_dma_read_u32s(xhci, ictx+64, iep0_ctx, sizeof(iep0_ctx)); DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n", iep0_ctx[0], iep0_ctx[1], iep0_ctx[2], iep0_ctx[3], iep0_ctx[4]); - pci_dma_read(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx)); + xhci_dma_read_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx)); ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/ ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000; @@ -2108,7 +2135,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n", ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); - pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx)); + xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx)); } return CC_SUCCESS; @@ -2133,12 +2160,12 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid) } } - pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT); slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT; DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); - pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx)); + xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); return CC_SUCCESS; } From 9d1530470bba5d8bec4796c0b43b874d5f9ef017 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 8 Nov 2012 10:14:46 +0100 Subject: [PATCH 15/67] ehci: fix migration Commit 5010d4dc618b6b8e7c21129c487c06f6493f71fc reorganized vmstate to split core + pci, but got two little details wrong. Fix them. Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci-pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index d5c7d462d0..fe45a1fbba 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -91,6 +91,7 @@ static const VMStateDescription vmstate_ehci_pci = { .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState), VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState), + VMSTATE_END_OF_LIST() } }; @@ -105,7 +106,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; - dc->vmsd = &vmstate_ehci; + dc->vmsd = &vmstate_ehci_pci; dc->props = ehci_pci_properties; } From 7e7f4a0efc81258213dc34aeeaade36b0f59d076 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 3 Nov 2012 18:06:26 +0100 Subject: [PATCH 16/67] qemu-nbd: initialize main loop before block layer qemu-nbd was broken because they initialized the block layer while qemu_aio_context was still NULL. Signed-off-by: Paolo Bonzini --- qemu-nbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index 15bcd08123..80f08d8464 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -539,6 +539,7 @@ int main(int argc, char **argv) snprintf(sockpath, 128, SOCKET_PATH, basename(device)); } + qemu_init_main_loop(); bdrv_init(); atexit(bdrv_close_all); @@ -584,7 +585,6 @@ int main(int argc, char **argv) memset(&client_thread, 0, sizeof(client_thread)); } - qemu_init_main_loop(); qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL, (void *)(uintptr_t)fd); From d04b0bbbc9cf61446e5c2e159eef50891009fd9c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 4 Nov 2012 12:56:39 +0100 Subject: [PATCH 17/67] nbd: accept relative path to Unix socket Adding the "is_unix" member now will simplify the parsing of NBD URIs. Signed-off-by: Paolo Bonzini --- block/nbd.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 2bce47bf7a..48bbecacaf 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -55,7 +55,6 @@ typedef struct BDRVNBDState { uint32_t nbdflags; off_t size; size_t blocksize; - char *export_name; /* An NBD server may export several devices */ CoMutex send_mutex; CoMutex free_sema; @@ -65,13 +64,12 @@ typedef struct BDRVNBDState { Coroutine *recv_coroutine[MAX_NBD_REQUESTS]; struct nbd_reply reply; - /* If it begins with '/', this is a UNIX domain socket. Otherwise, - * it's a string of the form :port - */ + int is_unix; char *host_spec; + char *export_name; /* An NBD server may export several devices */ } BDRVNBDState; -static int nbd_config(BDRVNBDState *s, const char *filename, int flags) +static int nbd_config(BDRVNBDState *s, const char *filename) { char *file; char *export_name; @@ -98,11 +96,10 @@ static int nbd_config(BDRVNBDState *s, const char *filename, int flags) /* are we a UNIX or TCP socket? */ if (strstart(host_spec, "unix:", &unixpath)) { - if (unixpath[0] != '/') { /* We demand an absolute path*/ - goto out; - } + s->is_unix = true; s->host_spec = g_strdup(unixpath); } else { + s->is_unix = false; s->host_spec = g_strdup(host_spec); } @@ -262,7 +259,7 @@ static int nbd_establish_connection(BlockDriverState *bs) off_t size; size_t blocksize; - if (s->host_spec[0] == '/') { + if (s->is_unix) { sock = unix_socket_outgoing(s->host_spec); } else { sock = tcp_socket_outgoing_spec(s->host_spec); @@ -320,7 +317,7 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags) qemu_co_mutex_init(&s->free_sema); /* Pop the config into our state object. Exit if invalid. */ - result = nbd_config(s, filename, flags); + result = nbd_config(s, filename); if (result != 0) { return result; } From 1d7d2a9d2191c34bd1ad69b420db9b47faa3fb8c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 4 Nov 2012 13:04:24 +0100 Subject: [PATCH 18/67] nbd: accept URIs The URI syntax is consistent with the Gluster syntax. Export names are specified in the path, preceded by one or more (otherwise unused) slashes. Signed-off-by: Paolo Bonzini --- block/nbd.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++- qemu-doc.texi | 25 ++++++++----- 2 files changed, 114 insertions(+), 9 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 48bbecacaf..e87c248175 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -28,6 +28,7 @@ #include "qemu-common.h" #include "nbd.h" +#include "uri.h" #include "block_int.h" #include "module.h" #include "qemu_socket.h" @@ -69,6 +70,69 @@ typedef struct BDRVNBDState { char *export_name; /* An NBD server may export several devices */ } BDRVNBDState; +static int nbd_parse_uri(BDRVNBDState *s, const char *filename) +{ + URI *uri; + const char *p; + QueryParams *qp = NULL; + int ret = 0; + + uri = uri_parse(filename); + if (!uri) { + return -EINVAL; + } + + /* transport */ + if (!strcmp(uri->scheme, "nbd")) { + s->is_unix = false; + } else if (!strcmp(uri->scheme, "nbd+tcp")) { + s->is_unix = false; + } else if (!strcmp(uri->scheme, "nbd+unix")) { + s->is_unix = true; + } else { + ret = -EINVAL; + goto out; + } + + p = uri->path ? uri->path : "/"; + p += strspn(p, "/"); + if (p[0]) { + s->export_name = g_strdup(p); + } + + qp = query_params_parse(uri->query); + if (qp->n > 1 || (s->is_unix && !qp->n) || (!s->is_unix && qp->n)) { + ret = -EINVAL; + goto out; + } + + if (s->is_unix) { + /* nbd+unix:///export?socket=path */ + if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) { + ret = -EINVAL; + goto out; + } + s->host_spec = g_strdup(qp->p[0].value); + } else { + /* nbd[+tcp]://host:port/export */ + if (!uri->server) { + ret = -EINVAL; + goto out; + } + if (!uri->port) { + uri->port = NBD_DEFAULT_PORT; + } + s->host_spec = g_strdup_printf("%s:%d", uri->server, uri->port); + } + +out: + if (qp) { + query_params_free(qp); + } + uri_free(uri); + return ret; +} + static int nbd_config(BDRVNBDState *s, const char *filename) { char *file; @@ -77,6 +141,10 @@ static int nbd_config(BDRVNBDState *s, const char *filename) const char *unixpath; int err = -EINVAL; + if (strstr(filename, "://")) { + return nbd_parse_uri(s, filename); + } + file = g_strdup(filename); export_name = strstr(file, EN_OPTSTR); @@ -495,6 +563,33 @@ static int64_t nbd_getlength(BlockDriverState *bs) static BlockDriver bdrv_nbd = { .format_name = "nbd", + .protocol_name = "nbd", + .instance_size = sizeof(BDRVNBDState), + .bdrv_file_open = nbd_open, + .bdrv_co_readv = nbd_co_readv, + .bdrv_co_writev = nbd_co_writev, + .bdrv_close = nbd_close, + .bdrv_co_flush_to_os = nbd_co_flush, + .bdrv_co_discard = nbd_co_discard, + .bdrv_getlength = nbd_getlength, +}; + +static BlockDriver bdrv_nbd_tcp = { + .format_name = "nbd", + .protocol_name = "nbd+tcp", + .instance_size = sizeof(BDRVNBDState), + .bdrv_file_open = nbd_open, + .bdrv_co_readv = nbd_co_readv, + .bdrv_co_writev = nbd_co_writev, + .bdrv_close = nbd_close, + .bdrv_co_flush_to_os = nbd_co_flush, + .bdrv_co_discard = nbd_co_discard, + .bdrv_getlength = nbd_getlength, +}; + +static BlockDriver bdrv_nbd_unix = { + .format_name = "nbd", + .protocol_name = "nbd+unix", .instance_size = sizeof(BDRVNBDState), .bdrv_file_open = nbd_open, .bdrv_co_readv = nbd_co_readv, @@ -503,12 +598,13 @@ static BlockDriver bdrv_nbd = { .bdrv_co_flush_to_os = nbd_co_flush, .bdrv_co_discard = nbd_co_discard, .bdrv_getlength = nbd_getlength, - .protocol_name = "nbd", }; static void bdrv_nbd_init(void) { bdrv_register(&bdrv_nbd); + bdrv_register(&bdrv_nbd_tcp); + bdrv_register(&bdrv_nbd_unix); } block_init(bdrv_nbd_init); diff --git a/qemu-doc.texi b/qemu-doc.texi index 35cabbcb9e..d8fb2de10e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -610,14 +610,14 @@ QEMU can access directly to block device exported using the Network Block Device protocol. @example -qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 +qemu-system-i386 linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/ @end example If the NBD server is located on the same host, you can use an unix socket instead of an inet socket: @example -qemu-system-i386 linux.img -hdb nbd:unix:/tmp/my_socket +qemu-system-i386 linux.img -hdb nbd+unix://?socket=/tmp/my_socket @end example In this case, the block device must be exported using qemu-nbd: @@ -631,17 +631,26 @@ The use of qemu-nbd allows to share a disk between several guests: qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2 @end example +@noindent and then you can use it with two guests: @example -qemu-system-i386 linux1.img -hdb nbd:unix:/tmp/my_socket -qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket +qemu-system-i386 linux1.img -hdb nbd+unix://?socket=/tmp/my_socket +qemu-system-i386 linux2.img -hdb nbd+unix://?socket=/tmp/my_socket @end example -If the nbd-server uses named exports (since NBD 2.9.18), you must use the -"exportname" option: +If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's +own embedded NBD server), you must specify an export name in the URI: @example -qemu-system-i386 -cdrom nbd:localhost:exportname=debian-500-ppc-netinst -qemu-system-i386 -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst +qemu-system-i386 -cdrom nbd://localhost/debian-500-ppc-netinst +qemu-system-i386 -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst +@end example + +The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is +also available. Here are some example of the older syntax: +@example +qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024 +qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket +qemu-system-i386 -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst @end example @node disk_images_sheepdog From fc6467eaf22f974620b5dd046afca04e619f9be9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 12 Nov 2012 14:12:54 +0100 Subject: [PATCH 19/67] nbd: fix nbd_server_stop crash when no server was running This failed on the new assertion of qemu_set_fd_handler2: qemu-system-x86_64: /home/pbonzini/work/upstream/qemu/iohandler.c:60: qemu_set_fd_handler2: Assertion `fd >= 0' failed. Signed-off-by: Paolo Bonzini --- blockdev-nbd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 8031813071..274fba6e46 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -113,7 +113,9 @@ void qmp_nbd_server_stop(Error **errp) nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp)); } - qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL); - close(server_fd); - server_fd = -1; + if (server_fd != -1) { + qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL); + close(server_fd); + server_fd = -1; + } } From e644473445177671ec408dfdec705cf931657998 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 4 Nov 2012 12:43:37 +0100 Subject: [PATCH 20/67] nbd: force read-only export for read-only devices This is the desired behavior for HMP, but it is a better choice for QMP as well. Signed-off-by: Paolo Bonzini --- blockdev-nbd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 274fba6e46..e362572279 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -93,6 +93,13 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, return; } + if (!has_writable) { + writable = true; + } + if (bdrv_is_read_only(bs)) { + writable = false; + } + exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, nbd_server_put_ref); From 17b6be4a7fc9db4f4c56908bab137d4c491471f1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 12 Nov 2012 14:25:17 +0100 Subject: [PATCH 21/67] nbd: disallow nbd-server-add before nbd-server-start It works nicely with the QMP commands, but it adds useless complication with HMP. In particular, see the following: (qemu) nbd_server_add -w scsi0-hd0 (qemu) nbd_server_start -a localhost:10809 NBD server already exporting device scsi0-hd0 Signed-off-by: Paolo Bonzini --- blockdev-nbd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/blockdev-nbd.c b/blockdev-nbd.c index e362572279..d1721a3e26 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -82,6 +82,11 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, NBDExport *exp; NBDCloseNotifier *n; + if (server_fd == -1) { + error_setg(errp, "NBD server not running"); + return; + } + if (nbd_export_find(device)) { error_setg(errp, "NBD server already exporting device '%s'", device); return; From 4057725f35abe00ea371f85c6e27dd25eafd9ddf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 23 Aug 2012 11:53:04 +0200 Subject: [PATCH 22/67] hmp: add NBD server commands Signed-off-by: Paolo Bonzini --- hmp-commands.hx | 45 +++++++++++++++++++++++++++++ hmp.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ hmp.h | 3 ++ 3 files changed, 124 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index f916385c0a..b74ef75c39 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1310,6 +1310,51 @@ Remove all matches from the access control list, and set the default policy back to @code{deny}. ETEXI + { + .name = "nbd_server_start", + .args_type = "all:-a,writable:-w,uri:s", + .params = "nbd_server_start [-a] [-w] host:port", + .help = "serve block devices on the given host and port", + .mhandler.cmd = hmp_nbd_server_start, + }, +STEXI +@item nbd_server_start @var{host}:@var{port} +@findex nbd_server_start +Start an NBD server on the given host and/or port. If the @option{-a} +option is included, all of the virtual machine's block devices that +have an inserted media on them are automatically exported; in this case, +the @option{-w} option makes the devices writable too. +ETEXI + + { + .name = "nbd_server_add", + .args_type = "writable:-w,device:B", + .params = "nbd_server_add [-w] device", + .help = "export a block device via NBD", + .mhandler.cmd = hmp_nbd_server_add, + }, +STEXI +@item nbd_server_add @var{device} +@findex nbd_server_add +Export a block device through QEMU's NBD server, which must be started +beforehand with @command{nbd_server_start}. The @option{-w} option makes the +exported device writable too. +ETEXI + + { + .name = "nbd_server_stop", + .args_type = "", + .params = "nbd_server_stop", + .help = "stop serving block devices using the NBD protocol", + .mhandler.cmd = hmp_nbd_server_stop, + }, +STEXI +@item nbd_server_stop +@findex nbd_server_stop +Stop the QEMU embedded NBD server. +ETEXI + + #if defined(TARGET_I386) { diff --git a/hmp.c b/hmp.c index 895a343dc3..180ba2bfd9 100644 --- a/hmp.c +++ b/hmp.c @@ -18,6 +18,7 @@ #include "qemu-option.h" #include "qemu-timer.h" #include "qmp-commands.h" +#include "qemu_socket.h" #include "monitor.h" #include "console.h" @@ -1259,3 +1260,78 @@ void hmp_screen_dump(Monitor *mon, const QDict *qdict) qmp_screendump(filename, &err); hmp_handle_error(mon, &err); } + +void hmp_nbd_server_start(Monitor *mon, const QDict *qdict) +{ + const char *uri = qdict_get_str(qdict, "uri"); + int writable = qdict_get_try_bool(qdict, "writable", 0); + int all = qdict_get_try_bool(qdict, "all", 0); + Error *local_err = NULL; + BlockInfoList *block_list, *info; + SocketAddress *addr; + + if (writable && !all) { + error_setg(&local_err, "-w only valid together with -a"); + goto exit; + } + + /* First check if the address is valid and start the server. */ + addr = socket_parse(uri, &local_err); + if (local_err != NULL) { + goto exit; + } + + qmp_nbd_server_start(addr, &local_err); + qapi_free_SocketAddress(addr); + if (local_err != NULL) { + goto exit; + } + + if (!all) { + return; + } + + /* Then try adding all block devices. If one fails, close all and + * exit. + */ + block_list = qmp_query_block(NULL); + + for (info = block_list; info; info = info->next) { + if (!info->value->has_inserted) { + continue; + } + + qmp_nbd_server_add(info->value->device, true, writable, &local_err); + + if (local_err != NULL) { + qmp_nbd_server_stop(NULL); + break; + } + } + + qapi_free_BlockInfoList(block_list); + +exit: + hmp_handle_error(mon, &local_err); +} + +void hmp_nbd_server_add(Monitor *mon, const QDict *qdict) +{ + const char *device = qdict_get_str(qdict, "device"); + int writable = qdict_get_try_bool(qdict, "writable", 0); + Error *local_err = NULL; + + qmp_nbd_server_add(device, true, writable, &local_err); + + if (local_err != NULL) { + hmp_handle_error(mon, &local_err); + } +} + +void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict) +{ + Error *errp = NULL; + + qmp_nbd_server_stop(&errp); + hmp_handle_error(mon, &errp); +} diff --git a/hmp.h b/hmp.h index 34eb2b36f3..0ab03be982 100644 --- a/hmp.h +++ b/hmp.h @@ -77,5 +77,8 @@ void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict); void hmp_send_key(Monitor *mon, const QDict *qdict); void hmp_screen_dump(Monitor *mon, const QDict *qdict); +void hmp_nbd_server_start(Monitor *mon, const QDict *qdict); +void hmp_nbd_server_add(Monitor *mon, const QDict *qdict); +void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); #endif From c8dcb531bcd37a4a81d2cc08a89fcd19c34348f9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 10 Oct 2012 12:18:03 +0200 Subject: [PATCH 23/67] scsi: do not return short responses for emulated commands The inquiry command, for the case of VPD=1, was returning short responses; the number of returned bytes was just the number of bytes in the request, without padding to the specified allocation length with zero bytes. This is usually harmless, but it is a violation of the SCSI specification. To fix this, always pad with zero bytes to r->cmd.xfer in scsi_disk_emulate_command, and return at most r->buflen bytes (the size of the buffer for command data) rather than at most buflen bytes (the number of bytes that was filled in). Before this patch, "strace sg_inq -p0x83 /dev/sda" would report a non-zero resid value. After this patch, it reports resid=0. Signed-off-by: Paolo Bonzini --- hw/scsi-disk.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 1b0afa6352..098558d372 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -652,7 +652,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) if (buflen > SCSI_MAX_INQUIRY_LEN) { buflen = SCSI_MAX_INQUIRY_LEN; } - memset(outbuf, 0, buflen); outbuf[0] = s->qdev.type & 0x1f; outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0; @@ -1596,24 +1595,26 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) break; } + /* + * FIXME: we shouldn't return anything bigger than 4k, but the code + * requires the buffer to be as big as req->cmd.xfer in several + * places. So, do not allow CDBs with a very large ALLOCATION + * LENGTH. The real fix would be to modify scsi_read_data and + * dma_buf_read, so that they return data beyond the buflen + * as all zeros. + */ + if (req->cmd.xfer > 65536) { + goto illegal_request; + } + r->buflen = MAX(4096, req->cmd.xfer); + if (!r->iov.iov_base) { - /* - * FIXME: we shouldn't return anything bigger than 4k, but the code - * requires the buffer to be as big as req->cmd.xfer in several - * places. So, do not allow CDBs with a very large ALLOCATION - * LENGTH. The real fix would be to modify scsi_read_data and - * dma_buf_read, so that they return data beyond the buflen - * as all zeros. - */ - if (req->cmd.xfer > 65536) { - goto illegal_request; - } - r->buflen = MAX(4096, req->cmd.xfer); r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen); } buflen = req->cmd.xfer; outbuf = r->iov.iov_base; + memset(outbuf, 0, r->buflen); switch (req->cmd.buf[0]) { case TEST_UNIT_READY: assert(!s->tray_open && bdrv_is_inserted(s->qdev.conf.bs)); @@ -1694,12 +1695,14 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) outbuf[5] = 0; outbuf[6] = s->qdev.blocksize >> 8; outbuf[7] = 0; - buflen = 8; break; case REQUEST_SENSE: /* Just return "NO SENSE". */ buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen, (req->cmd.buf[1] & 1) == 0); + if (buflen < 0) { + goto illegal_request; + } break; case MECHANISM_STATUS: buflen = scsi_emulate_mechanism_status(s, outbuf); @@ -1770,7 +1773,6 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) } /* Protection, exponent and lowest lba field left blank. */ - buflen = req->cmd.xfer; break; } DPRINTF("Unsupported Service Action In\n"); @@ -1827,7 +1829,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) return 0; } assert(!r->req.aiocb); - r->iov.iov_len = MIN(buflen, req->cmd.xfer); + r->iov.iov_len = MIN(r->buflen, req->cmd.xfer); if (r->iov.iov_len == 0) { scsi_req_complete(&r->req, GOOD); } From cd41a671b370a3dd603963432d2b02f1e5990fb7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 8 Oct 2012 16:50:51 +0200 Subject: [PATCH 24/67] virtio-scsi: factor checks for VIRTIO_SCSI_S_DRIVER_OK when reporting events Suggested by Laszlo Ersek. Signed-off-by: Paolo Bonzini --- hw/virtio-scsi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index b54c7895fc..30d3f8aca7 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -596,6 +596,10 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, VirtIOSCSIEvent *evt; int in_size; + if (!(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { + return; + } + if (!req) { s->events_dropped = true; return; @@ -648,7 +652,6 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense) VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); if (((s->vdev.guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) && - (s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) && dev->type != TYPE_ROM) { virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE, sense.asc | (sense.ascq << 8)); @@ -659,8 +662,7 @@ static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev) { VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); - if (((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) && - (s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { + if ((s->vdev.guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) { virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN); } From b5232e904fadac8af239306719be4a554f9e9263 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 8 Oct 2012 16:46:54 +0200 Subject: [PATCH 25/67] scsi: remove superfluous call to scsi_device_set_ua Suggested by Laszlo Ersek. Signed-off-by: Paolo Bonzini --- hw/scsi-disk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 098558d372..d15f891974 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1964,7 +1964,6 @@ static void scsi_disk_resize_cb(void *opaque) * direct-access devices. */ if (s->qdev.type == TYPE_DISK) { - scsi_device_set_ua(&s->qdev, SENSE_CODE(CAPACITY_CHANGED)); scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED)); } } From 346a3017ec8d5ac4a6961d823f1e576867dc35ef Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 28 Sep 2012 16:43:41 +0200 Subject: [PATCH 26/67] megasas: do not include block_int.h Signed-off-by: Paolo Bonzini --- hw/megasas.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/megasas.c b/hw/megasas.c index 7a2036eb76..b845ea7b48 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -25,7 +25,6 @@ #include "iov.h" #include "scsi.h" #include "scsi-defs.h" -#include "block_int.h" #include "trace.h" #include "mfi.h" From accfeb2dd32ece73350b06cee1b2403f47e86fe3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 31 Oct 2012 17:14:41 +0100 Subject: [PATCH 27/67] scsi-disk: flush cache after disabling it SBC says that "if an application client changes the WCE bit from one to zero via a MODE SELECT command, then the device server shall write any data in volatile cache to non-volatile medium before completing the command". Signed-off-by: Paolo Bonzini --- hw/scsi-disk.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index d15f891974..49b5686a92 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1387,6 +1387,7 @@ invalid_param_len: static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint8_t *p = inbuf; int cmd = r->req.cmd.buf[0]; int len = r->req.cmd.xfer; @@ -1423,6 +1424,14 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) return; } } + if (!bdrv_enable_write_cache(s->qdev.conf.bs)) { + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH); + r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r); + return; + } + scsi_req_complete(&r->req, GOOD); return; From 4003e24fce1df84a2e8c992376ed2c294816c33c Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 12 Nov 2012 15:42:42 +0100 Subject: [PATCH 28/67] megasas: Correct target/lun mapping The structure to reference a logical drive has an unused field, which can be used to carry the lun ID. This enabled seabios to establish the proper target/LUN mapping. Cc: Paolo Bonzini Cc: Gerd Hoffmann Signed-off-by: Hannes Reinecke Signed-off-by: Paolo Bonzini --- hw/megasas.c | 1 + hw/mfi.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/megasas.c b/hw/megasas.c index b845ea7b48..291ff40403 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -1079,6 +1079,7 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) /* Logical device size is in blocks */ bdrv_get_geometry(conf->bs, &ld_size); info.ld_list[num_ld_disks].ld.v.target_id = sdev->id; + info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun; info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL; info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size); num_ld_disks++; diff --git a/hw/mfi.h b/hw/mfi.h index 436b6906b1..cd8355badf 100644 --- a/hw/mfi.h +++ b/hw/mfi.h @@ -1085,7 +1085,7 @@ struct mfi_pd_list { union mfi_ld_ref { struct { uint8_t target_id; - uint8_t reserved; + uint8_t lun_id; uint16_t seq; } v; uint32_t ref; From 9e11908f12f92e31ea94dc2a4c962c836cba9f2a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 29 Oct 2012 11:34:32 +1000 Subject: [PATCH 29/67] dma: Define dma_context_memory and use in sysbus-ohci Define a new global dma_context_memory which is a DMAContext corresponding to the global address_space_memory AddressSpace. This can be used by sysbus peripherals like sysbus-ohci which need to do DMA. In particular, use it in the sysbus-ohci device, which fixes a segfault when attempting to use that device. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite --- dma.h | 5 +++++ exec.c | 5 +++++ hw/usb/hcd-ohci.c | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dma.h b/dma.h index 91ccdb5eac..eedf878383 100644 --- a/dma.h +++ b/dma.h @@ -68,6 +68,11 @@ struct DMAContext { DMAUnmapFunc *unmap; }; +/* A global DMA context corresponding to the address_space_memory + * AddressSpace, for sysbus devices which do DMA. + */ +extern DMAContext dma_context_memory; + static inline void dma_barrier(DMAContext *dma, DMADirection dir) { /* diff --git a/exec.c b/exec.c index af94f9cd86..8435de0bd2 100644 --- a/exec.c +++ b/exec.c @@ -34,6 +34,7 @@ #include "hw/xen.h" #include "qemu-timer.h" #include "memory.h" +#include "dma.h" #include "exec-memory.h" #if defined(CONFIG_USER_ONLY) #include @@ -103,6 +104,7 @@ static MemoryRegion *system_io; AddressSpace address_space_io; AddressSpace address_space_memory; +DMAContext dma_context_memory; MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty; static MemoryRegion io_mem_subpage_ram; @@ -3294,6 +3296,9 @@ static void memory_map_init(void) memory_listener_register(&core_memory_listener, &address_space_memory); memory_listener_register(&io_memory_listener, &address_space_io); memory_listener_register(&tcg_memory_listener, &address_space_memory); + + dma_context_init(&dma_context_memory, &address_space_memory, + NULL, NULL, NULL); } MemoryRegion *get_system_memory(void) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 7571e9e44a..efae0322ee 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1851,7 +1851,7 @@ static int ohci_init_pxa(SysBusDevice *dev) /* Cannot fail as we pass NULL for masterbus */ usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0, - NULL); + &dma_context_memory); sysbus_init_irq(dev, &s->ohci.irq); sysbus_init_mmio(dev, &s->ohci.mem); From dd72fdd06268860a24f9f3828efade547ee2e2a9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 30 Oct 2012 17:31:43 +0100 Subject: [PATCH 30/67] virtio-scsi: use dma_context_memory Until address_space_rw was introduced, NULL was accepted as a placeholder for DMA with no IOMMU (to address_space_memory). This does not work anymore, and dma_context_memory needs to be specified explicitly. Signed-off-by: Paolo Bonzini --- hw/virtio-scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index 30d3f8aca7..7d546f6ca7 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -204,7 +204,7 @@ static void virtio_scsi_bad_req(void) static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg, hwaddr *addr, int num) { - memset(qsgl, 0, sizeof(*qsgl)); + qemu_sglist_init(qsgl, num, &dma_context_memory); while (num--) { qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len); } From f5022a135e4309a54d433c69b2a056756b2d0d6b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 12 Nov 2012 13:30:10 +0100 Subject: [PATCH 31/67] aio: fix aio_ctx_prepare with idle bottom halves Commit ed2aec4867f0d5f5de496bb765347b5d0cfe113d changed the return value of aio_ctx_prepare from false to true when only idle bottom halves are available. This broke PC old-style DMA, which uses them. Fix this by making aio_ctx_prepare return true only when non-idle bottom halves are scheduled to run. Reported-by: malc Signed-off-by: Paolo Bonzini Signed-off-by: malc --- async.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/async.c b/async.c index 04f9dcbb4d..3f0e8f367c 100644 --- a/async.c +++ b/async.c @@ -122,11 +122,9 @@ aio_ctx_prepare(GSource *source, gint *timeout) { AioContext *ctx = (AioContext *) source; QEMUBH *bh; - bool scheduled = false; for (bh = ctx->first_bh; bh; bh = bh->next) { if (!bh->deleted && bh->scheduled) { - scheduled = true; if (bh->idle) { /* idle bottom halves will be polled at least * every 10ms */ @@ -135,12 +133,12 @@ aio_ctx_prepare(GSource *source, gint *timeout) /* non-idle bottom halves will be executed * immediately */ *timeout = 0; - break; + return true; } } } - return scheduled; + return false; } static gboolean From c8969eded252058e90e91f12f75f32aceae46ec9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 13 Nov 2012 10:34:17 +0100 Subject: [PATCH 32/67] nbd: fixes to read-only handling We do not need BLKROSET if the kernel supports setting flags. Also, always do BLKROSET even for a read-write export, otherwise the read-only state remains "sticky" after the invocation of "qemu-nbd -r". Signed-off-by: Paolo Bonzini --- nbd.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/nbd.c b/nbd.c index cec5a9449b..97a5914e0f 100644 --- a/nbd.c +++ b/nbd.c @@ -596,24 +596,23 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize) return -serrno; } - if (flags & NBD_FLAG_READ_ONLY) { - int read_only = 1; - TRACE("Setting readonly attribute"); + if (ioctl(fd, NBD_SET_FLAGS, flags) < 0) { + if (errno == ENOTTY) { + int read_only = (flags & NBD_FLAG_READ_ONLY) != 0; + TRACE("Setting readonly attribute"); - if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) { + if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) { + int serrno = errno; + LOG("Failed setting read-only attribute"); + return -serrno; + } + } else { int serrno = errno; - LOG("Failed setting read-only attribute"); + LOG("Failed setting flags"); return -serrno; } } - if (ioctl(fd, NBD_SET_FLAGS, flags) < 0 - && errno != ENOTTY) { - int serrno = errno; - LOG("Failed setting flags"); - return -serrno; - } - TRACE("Negotiation ended"); return 0; From 716b8e4dd2f7a1674bf77d49fd50139cb577e70f Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 13 Nov 2012 12:27:40 -0700 Subject: [PATCH 33/67] linux-headers: Update to 3.7-rc5 update-linux-headers.sh script run against Linux tag v3.7-rc5 Signed-off-by: Alex Williamson --- linux-headers/asm-powerpc/kvm_para.h | 6 +++--- linux-headers/asm-s390/kvm_para.h | 8 +------- linux-headers/asm-x86/kvm.h | 17 +++++++++++++++++ linux-headers/linux/kvm.h | 25 +++++++++++++++++++++---- linux-headers/linux/kvm_para.h | 6 +++--- linux-headers/linux/vfio.h | 6 +++--- linux-headers/linux/virtio_config.h | 6 +++--- linux-headers/linux/virtio_ring.h | 6 +++--- 8 files changed, 54 insertions(+), 26 deletions(-) diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h index c047a84000..5e04383a1d 100644 --- a/linux-headers/asm-powerpc/kvm_para.h +++ b/linux-headers/asm-powerpc/kvm_para.h @@ -17,8 +17,8 @@ * Authors: Hollis Blanchard */ -#ifndef __POWERPC_KVM_PARA_H__ -#define __POWERPC_KVM_PARA_H__ +#ifndef _UAPI__POWERPC_KVM_PARA_H__ +#define _UAPI__POWERPC_KVM_PARA_H__ #include @@ -87,4 +87,4 @@ struct kvm_vcpu_arch_shared { #define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1) -#endif /* __POWERPC_KVM_PARA_H__ */ +#endif /* _UAPI__POWERPC_KVM_PARA_H__ */ diff --git a/linux-headers/asm-s390/kvm_para.h b/linux-headers/asm-s390/kvm_para.h index 870051f645..ff1f4e7b30 100644 --- a/linux-headers/asm-s390/kvm_para.h +++ b/linux-headers/asm-s390/kvm_para.h @@ -1,5 +1,5 @@ /* - * definition for paravirtual devices on s390 + * User API definitions for paravirtual devices on s390 * * Copyright IBM Corp. 2008 * @@ -9,9 +9,3 @@ * * Author(s): Christian Borntraeger */ - -#ifndef __S390_KVM_PARA_H -#define __S390_KVM_PARA_H - - -#endif /* __S390_KVM_PARA_H */ diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 246617efd6..a65ec29e6f 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -9,6 +9,22 @@ #include #include +#define DE_VECTOR 0 +#define DB_VECTOR 1 +#define BP_VECTOR 3 +#define OF_VECTOR 4 +#define BR_VECTOR 5 +#define UD_VECTOR 6 +#define NM_VECTOR 7 +#define DF_VECTOR 8 +#define TS_VECTOR 10 +#define NP_VECTOR 11 +#define SS_VECTOR 12 +#define GP_VECTOR 13 +#define PF_VECTOR 14 +#define MF_VECTOR 16 +#define MC_VECTOR 18 + /* Select x86 specific features in */ #define __KVM_HAVE_PIT #define __KVM_HAVE_IOAPIC @@ -25,6 +41,7 @@ #define __KVM_HAVE_DEBUGREGS #define __KVM_HAVE_XSAVE #define __KVM_HAVE_XCRS +#define __KVM_HAVE_READONLY_MEM /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 4b9e575dd0..81d2feb7ab 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -101,9 +101,13 @@ struct kvm_userspace_memory_region { __u64 userspace_addr; /* start of the userspace allocated memory */ }; -/* for kvm_memory_region::flags */ -#define KVM_MEM_LOG_DIRTY_PAGES 1UL -#define KVM_MEMSLOT_INVALID (1UL << 1) +/* + * The bit 0 ~ bit 15 of kvm_memory_region::flags are visible for userspace, + * other bits are reserved for kvm internal use which are defined in + * include/linux/kvm_host.h. + */ +#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) +#define KVM_MEM_READONLY (1UL << 1) /* for KVM_IRQ_LINE */ struct kvm_irq_level { @@ -618,6 +622,10 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_GET_SMMU_INFO 78 #define KVM_CAP_S390_COW 79 #define KVM_CAP_PPC_ALLOC_HTAB 80 +#ifdef __KVM_HAVE_READONLY_MEM +#define KVM_CAP_READONLY_MEM 81 +#endif +#define KVM_CAP_IRQFD_RESAMPLE 82 #ifdef KVM_CAP_IRQ_ROUTING @@ -683,12 +691,21 @@ struct kvm_xen_hvm_config { #endif #define KVM_IRQFD_FLAG_DEASSIGN (1 << 0) +/* + * Available with KVM_CAP_IRQFD_RESAMPLE + * + * KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies + * the irqfd to operate in resampling mode for level triggered interrupt + * emlation. See Documentation/virtual/kvm/api.txt. + */ +#define KVM_IRQFD_FLAG_RESAMPLE (1 << 1) struct kvm_irqfd { __u32 fd; __u32 gsi; __u32 flags; - __u8 pad[20]; + __u32 resamplefd; + __u8 pad[16]; }; struct kvm_clock_data { diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h index 7bdcf93c1d..cea2c5c72d 100644 --- a/linux-headers/linux/kvm_para.h +++ b/linux-headers/linux/kvm_para.h @@ -1,5 +1,5 @@ -#ifndef __LINUX_KVM_PARA_H -#define __LINUX_KVM_PARA_H +#ifndef _UAPI__LINUX_KVM_PARA_H +#define _UAPI__LINUX_KVM_PARA_H /* * This header file provides a method for making a hypercall to the host @@ -25,4 +25,4 @@ */ #include -#endif /* __LINUX_KVM_PARA_H */ +#endif /* _UAPI__LINUX_KVM_PARA_H */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index f787b727a9..4758d1bfcf 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -8,8 +8,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef VFIO_H -#define VFIO_H +#ifndef _UAPIVFIO_H +#define _UAPIVFIO_H #include #include @@ -365,4 +365,4 @@ struct vfio_iommu_type1_dma_unmap { #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14) -#endif /* VFIO_H */ +#endif /* _UAPIVFIO_H */ diff --git a/linux-headers/linux/virtio_config.h b/linux-headers/linux/virtio_config.h index 4f51d8f3af..b7cda390fd 100644 --- a/linux-headers/linux/virtio_config.h +++ b/linux-headers/linux/virtio_config.h @@ -1,5 +1,5 @@ -#ifndef _LINUX_VIRTIO_CONFIG_H -#define _LINUX_VIRTIO_CONFIG_H +#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H +#define _UAPI_LINUX_VIRTIO_CONFIG_H /* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so * anyone can use the definitions to implement compatible drivers/servers. * @@ -51,4 +51,4 @@ * suppressed them? */ #define VIRTIO_F_NOTIFY_ON_EMPTY 24 -#endif /* _LINUX_VIRTIO_CONFIG_H */ +#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */ diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h index 1b333e2536..921694a084 100644 --- a/linux-headers/linux/virtio_ring.h +++ b/linux-headers/linux/virtio_ring.h @@ -1,5 +1,5 @@ -#ifndef _LINUX_VIRTIO_RING_H -#define _LINUX_VIRTIO_RING_H +#ifndef _UAPI_LINUX_VIRTIO_RING_H +#define _UAPI_LINUX_VIRTIO_RING_H /* An interface for efficient virtio implementation, currently for use by KVM * and lguest, but hopefully others soon. Do NOT change this since it will * break existing servers and clients. @@ -160,4 +160,4 @@ static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old); } -#endif /* _LINUX_VIRTIO_RING_H */ +#endif /* _UAPI_LINUX_VIRTIO_RING_H */ From e1d1e5867d0bd54c4fc51ec2cddc701258314db0 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 13 Nov 2012 12:27:40 -0700 Subject: [PATCH 34/67] vfio-pci: Add KVM INTx acceleration This makes use of the new level irqfd support enabling bypass of qemu userspace both on INTx injection and unmask. This significantly boosts the performance of devices making use of legacy interrupts (ex. ~60% better netperf TCP_RR scores for an e1000e assigned to a Linux guest and booted with pci=nomsi). This also avoids flipping mmaps on and off to simulate EOIs, so greatly improves performance of device access in addition to interrupt latency. Signed-off-by: Alex Williamson --- hw/vfio_pci.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 0473ae866c..4e9c2ddbf9 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -185,6 +185,21 @@ static void vfio_unmask_intx(VFIODevice *vdev) ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); } +#ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */ +static void vfio_mask_intx(VFIODevice *vdev) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, + .index = VFIO_PCI_INTX_IRQ_INDEX, + .start = 0, + .count = 1, + }; + + ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} +#endif + /* * Disabling BAR mmaping can be slow, but toggling it around INTx can * also be a huge overhead. We try to get the best of both worlds by @@ -248,6 +263,161 @@ static void vfio_eoi(VFIODevice *vdev) vfio_unmask_intx(vdev); } +static void vfio_enable_intx_kvm(VFIODevice *vdev) +{ +#ifdef CONFIG_KVM + struct kvm_irqfd irqfd = { + .fd = event_notifier_get_fd(&vdev->intx.interrupt), + .gsi = vdev->intx.route.irq, + .flags = KVM_IRQFD_FLAG_RESAMPLE, + }; + struct vfio_irq_set *irq_set; + int ret, argsz; + int32_t *pfd; + + if (!kvm_irqchip_in_kernel() || + vdev->intx.route.mode != PCI_INTX_ENABLED || + !kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) { + return; + } + + /* Get to a known interrupt state */ + qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev); + vfio_mask_intx(vdev); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + + /* Get an eventfd for resample/unmask */ + if (event_notifier_init(&vdev->intx.unmask, 0)) { + error_report("vfio: Error: event_notifier_init failed eoi\n"); + goto fail; + } + + /* KVM triggers it, VFIO listens for it */ + irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask); + + if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) { + error_report("vfio: Error: Failed to setup resample irqfd: %m\n"); + goto fail_irqfd; + } + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK; + irq_set->index = VFIO_PCI_INTX_IRQ_INDEX; + irq_set->start = 0; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + + *pfd = irqfd.resamplefd; + + ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); + g_free(irq_set); + if (ret) { + error_report("vfio: Error: Failed to setup INTx unmask fd: %m\n"); + goto fail_vfio; + } + + /* Let'em rip */ + vfio_unmask_intx(vdev); + + vdev->intx.kvm_accel = true; + + DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel enabled\n", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function); + + return; + +fail_vfio: + irqfd.flags = KVM_IRQFD_FLAG_DEASSIGN; + kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd); +fail_irqfd: + event_notifier_cleanup(&vdev->intx.unmask); +fail: + qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); + vfio_unmask_intx(vdev); +#endif +} + +static void vfio_disable_intx_kvm(VFIODevice *vdev) +{ +#ifdef CONFIG_KVM + struct kvm_irqfd irqfd = { + .fd = event_notifier_get_fd(&vdev->intx.interrupt), + .gsi = vdev->intx.route.irq, + .flags = KVM_IRQFD_FLAG_DEASSIGN, + }; + + if (!vdev->intx.kvm_accel) { + return; + } + + /* + * Get to a known state, hardware masked, QEMU ready to accept new + * interrupts, QEMU IRQ de-asserted. + */ + vfio_mask_intx(vdev); + vdev->intx.pending = false; + qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); + + /* Tell KVM to stop listening for an INTx irqfd */ + if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) { + error_report("vfio: Error: Failed to disable INTx irqfd: %m\n"); + } + + /* We only need to close the eventfd for VFIO to cleanup the kernel side */ + event_notifier_cleanup(&vdev->intx.unmask); + + /* QEMU starts listening for interrupt events. */ + qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev); + + vdev->intx.kvm_accel = false; + + /* If we've missed an event, let it re-fire through QEMU */ + vfio_unmask_intx(vdev); + + DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function); +#endif +} + +static void vfio_update_irq(PCIDevice *pdev) +{ + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + PCIINTxRoute route; + + if (vdev->interrupt != VFIO_INT_INTx) { + return; + } + + route = pci_device_route_intx_to_irq(&vdev->pdev, vdev->intx.pin); + + if (!pci_intx_route_changed(&vdev->intx.route, &route)) { + return; /* Nothing changed */ + } + + DPRINTF("%s(%04x:%02x:%02x.%x) IRQ moved %d -> %d\n", __func__, + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function, vdev->intx.route.irq, route.irq); + + vfio_disable_intx_kvm(vdev); + + vdev->intx.route = route; + + if (route.mode != PCI_INTX_ENABLED) { + return; + } + + vfio_enable_intx_kvm(vdev); + + /* Re-enable the interrupt in cased we missed an EOI */ + vfio_eoi(vdev); +} + static int vfio_enable_intx(VFIODevice *vdev) { uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1); @@ -262,6 +432,18 @@ static int vfio_enable_intx(VFIODevice *vdev) vfio_disable_interrupts(vdev); vdev->intx.pin = pin - 1; /* Pin A (1) -> irq[0] */ + +#ifdef CONFIG_KVM + /* + * Only conditional to avoid generating error messages on platforms + * where we won't actually use the result anyway. + */ + if (kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) { + vdev->intx.route = pci_device_route_intx_to_irq(&vdev->pdev, + vdev->intx.pin); + } +#endif + ret = event_notifier_init(&vdev->intx.interrupt, 0); if (ret) { error_report("vfio: Error: event_notifier_init failed\n"); @@ -290,6 +472,8 @@ static int vfio_enable_intx(VFIODevice *vdev) return -errno; } + vfio_enable_intx_kvm(vdev); + vdev->interrupt = VFIO_INT_INTx; DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, @@ -303,6 +487,7 @@ static void vfio_disable_intx(VFIODevice *vdev) int fd; qemu_del_timer(vdev->intx.mmap_timer); + vfio_disable_intx_kvm(vdev); vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX); vdev->intx.pending = false; qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0); @@ -1839,6 +2024,7 @@ static int vfio_initfn(PCIDevice *pdev) if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) { vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock, vfio_intx_mmap_enable, vdev); + pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_update_irq); ret = vfio_enable_intx(vdev); if (ret) { goto out_teardown; From a771c51703cf9f91023c6570426258bdf5ec775b Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 13 Nov 2012 12:27:40 -0700 Subject: [PATCH 35/67] vfio-pci: Use common msi_get_message We can get rid of our local version now that a helper exists. Signed-off-by: Alex Williamson --- hw/vfio_pci.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 4e9c2ddbf9..7c27834e06 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -688,28 +688,6 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) vector->use = false; } -/* TODO This should move to msi.c */ -static MSIMessage msi_get_msg(PCIDevice *pdev, unsigned int vector) -{ - uint16_t flags = pci_get_word(pdev->config + pdev->msi_cap + PCI_MSI_FLAGS); - bool msi64bit = flags & PCI_MSI_FLAGS_64BIT; - MSIMessage msg; - - if (msi64bit) { - msg.address = pci_get_quad(pdev->config + - pdev->msi_cap + PCI_MSI_ADDRESS_LO); - } else { - msg.address = pci_get_long(pdev->config + - pdev->msi_cap + PCI_MSI_ADDRESS_LO); - } - - msg.data = pci_get_word(pdev->config + pdev->msi_cap + - (msi64bit ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32)); - msg.data += vector; - - return msg; -} - static void vfio_enable_msix(VFIODevice *vdev) { vfio_disable_interrupts(vdev); @@ -748,7 +726,7 @@ retry: error_report("vfio: Error: event_notifier_init failed\n"); } - msg = msi_get_msg(&vdev->pdev, i); + msg = msi_get_message(&vdev->pdev, i); /* * Attempt to enable route through KVM irqchip, From 5ca9388a4d22a68439a04b0735c34bdcac553e48 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 7 Nov 2012 11:06:23 +0100 Subject: [PATCH 36/67] pixman: add output dir to include path Needed to make sure the (generated) pixman-version.h file is found. Based on a patch from Blue Swirl. Signed-off-by: Gerd Hoffmann --- configure | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 7290f50e11..e6fe4f8fe3 100755 --- a/configure +++ b/configure @@ -2121,11 +2121,10 @@ else echo " git submodule update --init pixman" exit 1 fi - pixman_cflags="-I${source_path}/pixman/pixman" - pixman_libs="-Lpixman/pixman/.libs -lpixman-1" + mkdir -p pixman/pixman + pixman_cflags="-I\$(SRC_PATH)/pixman/pixman -I\$(BUILD_DIR)/pixman/pixman" + pixman_libs="-L\$(BUILD_DIR)/pixman/pixman/.libs -lpixman-1" fi -QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags" -libs_softmmu="$libs_softmmu $pixman_libs" ########################################## # libcap probe @@ -3137,6 +3136,10 @@ if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then roms="$roms spapr-rtas" fi +# add pixman flags after all config tests are done +QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags" +libs_softmmu="$libs_softmmu $pixman_libs" + echo "Install prefix $prefix" echo "BIOS directory `eval echo $qemu_datadir`" echo "binary directory `eval echo $bindir`" @@ -4154,7 +4157,6 @@ DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas" DIRS="$DIRS roms/seabios roms/vgabios" DIRS="$DIRS qapi-generated" DIRS="$DIRS libcacard libcacard/libcacard libcacard/trace" -DIRS="$DIRS pixman" FILES="Makefile tests/tcg/Makefile qdict-test-data.txt" FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile" From 42da6041d5e30fcf49ba639477a05e781594a7a5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 7 Nov 2012 11:09:52 +0100 Subject: [PATCH 37/67] pixman: set --host for cross builds Set --host when calling pixman configure while doing cross builds so pixman's autoconf picks up the cross build tools correctly. Signed-off-by: Gerd Hoffmann --- Makefile | 2 +- configure | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ca14a215ce..ff2c16d026 100644 --- a/Makefile +++ b/Makefile @@ -122,7 +122,7 @@ subdir-pixman: pixman/Makefile $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,) pixman/Makefile: $(SRC_PATH)/pixman/configure - (cd pixman; $(SRC_PATH)/pixman/configure --disable-shared --enable-static) + (cd pixman; $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-shared --enable-static) $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) diff --git a/configure b/configure index e6fe4f8fe3..0a241ebac6 100755 --- a/configure +++ b/configure @@ -3649,6 +3649,11 @@ if test "$sparse" = "yes" ; then echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak fi +if test "$cross_prefix" != ""; then + echo "AUTOCONF_HOST := --host=${cross_prefix%-}" >> $config_host_mak +else + echo "AUTOCONF_HOST := " >> $config_host_mak +fi echo "LDFLAGS=$LDFLAGS" >> $config_host_mak echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak echo "ARLIBS_END=$arlibs_end" >> $config_host_mak From 4d5bdd0b460ee2ff8989b0f83fa38a3af052b343 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 7 Nov 2012 11:41:01 +0100 Subject: [PATCH 38/67] pixman: disable gtk gtk is only needed to build test cases. Disable it to simplify the build. Signed-off-by: Gerd Hoffmann --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ff2c16d026..e68bb8fae4 100644 --- a/Makefile +++ b/Makefile @@ -122,7 +122,7 @@ subdir-pixman: pixman/Makefile $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,) pixman/Makefile: $(SRC_PATH)/pixman/configure - (cd pixman; $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-shared --enable-static) + (cd pixman; $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static) $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) From c28fa5a0b3566b133b5e3336d04f1333970ac179 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 14 Nov 2012 13:26:54 +0100 Subject: [PATCH 39/67] pixman: pass cflags, add -fPIC Pass on CFLAGS to the pixman configure script. Add -fPIC to the cflags, needed to make the final link succeed. Signed-off-by: Gerd Hoffmann --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e68bb8fae4..4538b87e36 100644 --- a/Makefile +++ b/Makefile @@ -122,7 +122,7 @@ subdir-pixman: pixman/Makefile $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,) pixman/Makefile: $(SRC_PATH)/pixman/configure - (cd pixman; $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static) + (cd pixman; CFLAGS="$(CFLAGS) -fPIC" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static) $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) From b776eca138b641a0234a957a9ff5c2ca4c6772d5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 12 Nov 2012 12:18:38 +0100 Subject: [PATCH 40/67] pixman: build internal version early Signed-off-by: Eric Johnson Signed-off-by: Gerd Hoffmann --- configure | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 0a241ebac6..f847ee264e 100755 --- a/configure +++ b/configure @@ -3956,9 +3956,6 @@ if test "$target_softmmu" = "yes" ; then if test "$smartcard_nss" = "yes" ; then echo "subdir-$target: subdir-libcacard" >> $config_host_mak fi - if test "$pixman" = "internal" ; then - echo "subdir-$target: subdir-pixman" >> $config_host_mak - fi case "$target_arch2" in i386|x86_64) echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak @@ -4156,6 +4153,10 @@ echo "QEMU_INCLUDES+=$includes" >> $config_target_mak done # for target in $targets +if [ "$pixman" = "internal" ]; then + echo "config-host.h: subdir-pixman" >> $config_host_mak +fi + # build tree in object directory in case the source is not in the current directory DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32" DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas" From daa8e5a077e9d8ca2615f5590fa98b3fcc4c9f47 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 13 Nov 2012 09:38:06 +0100 Subject: [PATCH 41/67] pixman: add licensing info Signed-off-by: Gerd Hoffmann --- qemu-pixman.c | 5 +++++ qemu-pixman.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/qemu-pixman.c b/qemu-pixman.c index 7547ed74c1..063b52dbb1 100644 --- a/qemu-pixman.c +++ b/qemu-pixman.c @@ -1,3 +1,8 @@ +/* + * 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-pixman.h" int qemu_pixman_get_type(int rshift, int gshift, int bshift) diff --git a/qemu-pixman.h b/qemu-pixman.h index 7652c41277..783a39252e 100644 --- a/qemu-pixman.h +++ b/qemu-pixman.h @@ -1,3 +1,8 @@ +/* + * 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_PIXMAN_H #define QEMU_PIXMAN_H From feb33ea728a72730389bc5d4bf52d33f09c7868b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 14 Nov 2012 13:45:55 +0100 Subject: [PATCH 42/67] pixman: cleanup properly on make distclean Signed-off-by: Gerd Hoffmann --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 4538b87e36..81c660f9f4 100644 --- a/Makefile +++ b/Makefile @@ -278,6 +278,7 @@ distclean: clean for d in $(TARGET_DIRS) $(QEMULIBS); do \ rm -rf $$d || exit 1 ; \ done + test -f pixman/config.log && make -C pixman distclean KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \ ar de en-us fi fr-be hr it lv nl pl ru th \ From 68d001928b151a0c50f367c0bdca645b3d5e9ed3 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 14 Nov 2012 15:04:42 +0100 Subject: [PATCH 43/67] mips/malta: fix CBUS UART interrupt pin According to the MIPS Malta Developement Platform User's Manual, the i8259 interrupt controller is supposed to be connected to the hardware IRQ0, and the CBUS UART to the hardware interrupt 2. In QEMU they are both connected to hardware interrupt 0, the CBUS UART interrupt being wrong. This patch fixes that. It should be noted that the irq array in QEMU includes the software interrupts, hence env->irq[2] is the first hardware interrupt. Cc: Ralf Baechle Reviewed-by: Eric Johnson Signed-off-by: Aurelien Jarno --- hw/mips_malta.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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); From 6801038bc52d61f81ac8a25fbe392f1bad982887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E9=9F=8B=E4=BB=BB=20=28Wei-Ren=20Chen=29?= Date: Wed, 14 Nov 2012 10:49:55 +0800 Subject: [PATCH 44/67] target-mips: fix wrong microMIPS opcode encoding While reading microMIPS decoding, I found a possible wrong opcode encoding. According to [1] page 166, the bits 13..12 for MULTU is 0x01 rather than 0x00. Please review, thanks. [1] MIPS Architecture for Programmers VolumeIV-e: The MIPS DSP Application-Specific Extension to the microMIPS32 Architecture Signed-off-by: Chen Wei-Ren Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index f6fc0c27ae..01b48fa2a2 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, From df9ffb726ff13f850b8829be1bc85ed621b903ac Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 12 Nov 2012 12:40:46 +0100 Subject: [PATCH 45/67] vga: fix bochs alignment issue The bochs dispi interface traditionally uses port 0x1ce as 16bit index register and port 0x1cf as 16bit data register. The later is unaligned, and probably for that reason the the data register was moved to 0x1d0 for non-x86 archs. This patch makes the data register available at 0x1d0 on x86 too. The old x86 location is kept for compatibility reasons, so both 0x1cf and 0x1d0 can be used as data register on x86. Signed-off-by: Gerd Hoffmann --- docs/specs/standard-vga.txt | 3 ++- hw/vga.c | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) 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/hw/vga.c b/hw/vga.c index 81aa76bef9..2b0200a164 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -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(), }; From c96c53b5f10c4b34e9fe1dcb1a5aadf204c16279 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 12 Nov 2012 22:33:21 +0100 Subject: [PATCH 46/67] vga: fix mmio vga register mapping --- hw/vga-pci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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; } } From 68d98d3e42b2b291274537d1ae4092e11d321437 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Mon, 25 Jun 2012 14:36:33 -0500 Subject: [PATCH 47/67] vl: add -object option to create QOM objects from the command line This will create a new QOM object in the '/objects' path. Note that properties are set in order which allows for simple objects to be initialized entirely with this option and then realized. This option is roughly equivalent to -device but for things that are not devices. Signed-off-by: Anthony Liguori --- qemu-config.c | 10 +++++++++ qemu-options.hx | 8 +++++++ vl.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) 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-options.hx b/qemu-options.hx index fe8f15c541..dd86bfee6a 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2904,6 +2904,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/vl.c b/vl.c index 4f03a72e58..c8e9c782d6 100644 --- a/vl.c +++ b/vl.c @@ -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() From 0e5588438d921b8686bbf455f400f727b2ff7b62 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Mon, 25 Jun 2012 10:32:46 -0500 Subject: [PATCH 48/67] object: add object_property_add_bool (v2) Signed-off-by: Anthony Liguori --- v1 -> v2 - Fix whitespace (Andreas Faerber) --- include/qemu/object.h | 16 +++++++++++++ qom/object.c | 56 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) 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 @@ -946,6 +946,22 @@ void object_property_add_str(Object *obj, const char *name, void (*set)(Object *, const char *, struct Error **), 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 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)); From a9b7b2ad7b075dba5495271706670e5c6b1304bc Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Mon, 25 Jun 2012 10:03:47 -0500 Subject: [PATCH 49/67] rng: add RndBackend abstract object class This is the backend used by devices that need to request entropy. Signed-off-by: Anthony Liguori --- Makefile.objs | 2 + backends/Makefile.objs | 1 + backends/rng.c | 93 ++++++++++++++++++++++++++++++++++++++++++ include/qemu/rng.h | 93 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 backends/Makefile.objs create mode 100644 backends/rng.c create mode 100644 include/qemu/rng.h diff --git a/Makefile.objs b/Makefile.objs index 37be7e26f7..dc1e699914 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -100,6 +100,8 @@ common-obj-y += vl.o common-obj-$(CONFIG_SLIRP) += slirp/ +common-obj-y += backends/ + ###################################################################### # libseccomp ifeq ($(CONFIG_SECCOMP),y) diff --git a/backends/Makefile.objs b/backends/Makefile.objs new file mode 100644 index 0000000000..06e08c782d --- /dev/null +++ b/backends/Makefile.objs @@ -0,0 +1 @@ +common-obj-y += rng.o 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 + * + * 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); 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 + * + * 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 From 5c74521d249486fa3e749dbbf6d56a70d4d7235f Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Mon, 25 Jun 2012 10:34:09 -0500 Subject: [PATCH 50/67] rng-random: add an RNG backend that uses /dev/random (v3) The filename can be overridden but it expects a non-blocking source of entropy. A typical invocation would be: qemu -object rng-random,id=rng0 -device virtio-rng-pci,rng=rng0 This can also be used with /dev/urandom by using the command line: qemu -object rng-random,filename=/dev/urandom,id=rng0 \ -device virtio-rng-pci,rng=rng0 Signed-off-by: Anthony Liguori --- v1 -> v2 - merged header split patch into this one v2 -> v3 - bug fix in rng-random (Paolo) --- backends/Makefile.objs | 2 +- backends/rng-random.c | 161 ++++++++++++++++++++++++++++++++++++++ include/qemu/rng-random.h | 22 ++++++ 3 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 backends/rng-random.c create mode 100644 include/qemu/rng-random.h diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 06e08c782d..23ca19b320 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -1 +1 @@ -common-obj-y += rng.o +common-obj-y += rng.o rng-random.o 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 + * + * 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/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 + * + * 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 From 1da2738f5566263177d09c1b9eaf7cbeeb17e815 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Mon, 25 Jun 2012 13:13:31 -0500 Subject: [PATCH 51/67] rng-egd: introduce EGD compliant RNG backend This backend talks EGD to a CharDriverState. A typical way to invoke this would be: qemu -chardev socket,host=localhost,port=1024,id=chr0 \ -object rng-egd,chardev=chr0,id=egd0 \ -device virtio-rng-pci,rng=egd0 Signed-off-by: Anthony Liguori --- backends/Makefile.objs | 2 +- backends/rng-egd.c | 215 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 backends/rng-egd.c diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 23ca19b320..875eebce6a 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -1 +1 @@ -common-obj-y += rng.o rng-random.o +common-obj-y += rng.o rng-random.o rng-egd.o diff --git a/backends/rng-egd.c b/backends/rng-egd.c new file mode 100644 index 0000000000..ec5835839a --- /dev/null +++ b/backends/rng-egd.c @@ -0,0 +1,215 @@ +/* + * QEMU Random Number Generator Backend + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori + * + * 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_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 + */ + g_slist_free_full(s->requests, + (GDestroyNotify)rng_egd_free_request); + s->requests = NULL; +} + +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); + + g_slist_free_full(s->requests, (GDestroyNotify)rng_egd_free_request); + s->requests = NULL; +} + +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); From 16c915ba42b45df7a64a6908287f03bfa3764bed Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Wed, 20 Jun 2012 12:29:32 +0530 Subject: [PATCH 52/67] virtio-rng: hardware random number generator device The Linux kernel already has a virtio-rng driver, this is the device implementation. When the guest asks for entropy from the virtio hwrng, it puts a buffer in the vq. We then put entropy into that buffer, and push it back to the guest. Signed-off-by: Amit Shah Signed-off-by: Anthony Liguori --- aliguori: converted to new RngBackend interface aliguori: remove entropy needed event aliguori: fix migration --- hw/Makefile.objs | 1 + hw/pci.h | 1 + hw/s390-virtio-bus.c | 37 ++++++++ hw/s390-virtio-bus.h | 2 + hw/virtio-pci.c | 60 ++++++++++++ hw/virtio-pci.h | 2 + hw/virtio-rng.c | 211 +++++++++++++++++++++++++++++++++++++++++++ hw/virtio-rng.h | 24 +++++ hw/virtio.h | 3 + 9 files changed, 341 insertions(+) create mode 100644 hw/virtio-rng.c create mode 100644 hw/virtio-rng.h 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/pci.h b/hw/pci.h index 241c1d8905..4da0c2a4c9 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -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/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/virtio-pci.c b/hw/virtio-pci.c index 96031500ee..a3d4777e8d 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -852,6 +852,28 @@ 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; + + 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 +1004,43 @@ 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), + 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 +1105,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..b7fb5e9d61 --- /dev/null +++ b/hw/virtio-rng.c @@ -0,0 +1,211 @@ +/* + * A virtio device implementing a hardware random number generator. + * + * Copyright 2012 Red Hat, Inc. + * Copyright 2012 Amit Shah + * + * 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; +} 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; +} + +/* 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; + } + + 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. + */ + len = pop_an_elem(vrng); + if (len) { + 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); + size_t size; + + size = pop_an_elem(vrng); + if (size) { + rng_backend_request_entropy(vrng->rng, size, chr_read, 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); + } + return 0; +} + +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; + 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..fbb01048ba --- /dev/null +++ b/hw/virtio-rng.h @@ -0,0 +1,24 @@ +/* + * Virtio RNG Support + * + * Copyright Red Hat, Inc. 2012 + * Copyright Amit Shah + * + * 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" + +/* The Virtio ID for the virtio rng device */ +#define VIRTIO_ID_RNG 4 + +struct VirtIORNGConf { + RngBackend *rng; +}; + +#endif 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, \ From 904d6f588063fb5ad2b61998acdf1e73fb465067 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 30 Oct 2012 17:45:05 -0500 Subject: [PATCH 53/67] virtio-rng: add rate limiting support This adds parameters to virtio-rng-pci to allow rate limiting the entropy a guest receives. An example command line: $ qemu -device virtio-rng-pci,max-bytes=1024,period=1000 Would limit entropy collection to 1Kb/s. Signed-off-by: Anthony Liguori --- hw/virtio-pci.c | 7 ++++++ hw/virtio-rng.c | 63 ++++++++++++++++++++++++++++++++++++++++++------- hw/virtio-rng.h | 2 ++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index a3d4777e8d..f90296d672 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -1015,6 +1015,13 @@ static void virtio_rng_initfn(Object *obj) 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(), }; diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c index b7fb5e9d61..3ca96c855f 100644 --- a/hw/virtio-rng.c +++ b/hw/virtio-rng.c @@ -31,6 +31,12 @@ typedef struct VirtIORNG { 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) @@ -55,6 +61,8 @@ static size_t pop_an_elem(VirtIORNG *vrng) 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) { @@ -66,6 +74,8 @@ static void chr_read(void *opaque, const void *buf, size_t size) return; } + vrng->quota_remaining -= size; + offset = 0; while (offset < size) { if (!pop_an_elem(vrng)) { @@ -85,21 +95,30 @@ static void chr_read(void *opaque, const void *buf, size_t size) * didn't have enough data to fill them all, indicate we want more * data. */ - len = pop_an_elem(vrng); - if (len) { + 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); - size_t size; - - size = pop_an_elem(vrng); - if (size) { - rng_backend_request_entropy(vrng->rng, size, chr_read, vrng); - } + virtio_rng_process(vrng); } static uint32_t get_features(VirtIODevice *vdev, uint32_t f) @@ -163,9 +182,27 @@ static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) 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; @@ -196,6 +233,16 @@ VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf) 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); diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h index fbb01048ba..7324d0ab57 100644 --- a/hw/virtio-rng.h +++ b/hw/virtio-rng.h @@ -19,6 +19,8 @@ struct VirtIORNGConf { RngBackend *rng; + uint64_t max_bytes; + uint32_t period_ms; }; #endif From 500054f161c29ff9db125c0b872809191ad6920b Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 26 Oct 2012 12:05:49 -0500 Subject: [PATCH 54/67] virtio-rng-pci: create a default backend if none exists This allows you to specify: $ qemu -device virtio-rng-pci And things will Just Work with a reasonable default. Signed-off-by: Anthony Liguori --- hw/virtio-pci.c | 13 +++++++++++++ hw/virtio-rng.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index f90296d672..71f4fb5dc6 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -857,6 +857,19 @@ 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; diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h index 7324d0ab57..f42d748eba 100644 --- a/hw/virtio-rng.h +++ b/hw/virtio-rng.h @@ -13,6 +13,7 @@ #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 @@ -21,6 +22,7 @@ struct VirtIORNGConf { RngBackend *rng; uint64_t max_bytes; uint32_t period_ms; + RndRandom *default_backend; }; #endif From 9cb535fe4ef08b01e583ec955767a0899ff79afe Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 16 Nov 2012 13:09:34 -0600 Subject: [PATCH 55/67] rng-egd: don't use gslist_free_full This function was only introduced in glib 2.28.0. Signed-off-by: Anthony Liguori --- backends/rng-egd.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/backends/rng-egd.c b/backends/rng-egd.c index ec5835839a..ad8473777c 100644 --- a/backends/rng-egd.c +++ b/backends/rng-egd.c @@ -110,6 +110,18 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size) } } +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); @@ -118,9 +130,7 @@ static void rng_egd_cancel_requests(RngBackend *b) * queue waiting to be read, this is okay, because there will always be * more data than we requested originally */ - g_slist_free_full(s->requests, - (GDestroyNotify)rng_egd_free_request); - s->requests = NULL; + rng_egd_free_requests(s); } static void rng_egd_opened(RngBackend *b, Error **errp) @@ -185,8 +195,7 @@ static void rng_egd_finalize(Object *obj) g_free(s->chr_name); - g_slist_free_full(s->requests, (GDestroyNotify)rng_egd_free_request); - s->requests = NULL; + rng_egd_free_requests(s); } static void rng_egd_class_init(ObjectClass *klass, void *data) From 7b5eff4daa65ab8672de8c126d7757cbbeb31a08 Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Mon, 12 Nov 2012 13:27:43 +0400 Subject: [PATCH 56/67] target-cris/translate.c: Code style clean-up Signed-off-by: Evgeny Voevodin Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- target-cris/translate.c | 4798 ++++++++++++++++++++------------------- 1 file changed, 2419 insertions(+), 2379 deletions(-) diff --git a/target-cris/translate.c b/target-cris/translate.c index f8ebc43a86..023980ec56 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; + 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; + 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 update_cc; + int cc_op; + int cc_size; + uint32_t cc_mask; - int cc_size_uptodate; /* -1 invalid or last written value. */ + 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 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; + 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) + unsigned int size, unsigned int sign) { - int r; + 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; + 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; + 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); + 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); + /* 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); - } + 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; + 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); + 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); + /* 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); - } + 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; + 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); + /* 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); + 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; + if (dc->flags_uptodate) { + return; + } - cris_flush_cc_state(dc); + 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); + 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; } - dc->flags_uptodate = 1; + 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); + } + } + 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) + 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 (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); + 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) + 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; - } + /* 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); + 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; + int arith_opt, move_opt; - /* TODO: optimize more condition codes. */ + /* 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 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; + 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; + 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; + 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; + 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); + 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; + 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(); + 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); + /* 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_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; + 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(); + 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); + /* 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_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; - }; + 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) + unsigned int size, int sign) { - 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); + } - 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(); - } + 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; + unsigned int rs; + uint32_t imm; + int is_imm; + int insn_len = 2; - rs = dc->op1; - is_imm = rs == 15 && dc->postinc; + 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++; + /* 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; + 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); + int size = memsize_zz(dc); - LOG_DIS("move.%c $r%u, $r%u\n", - memsize_char(size), dc->op1, dc->op2); + 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; + 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; + 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); + 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; + 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; + 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); - } + 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); - } + /* 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; - } + 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; - } + /* 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; - } + /* 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); + /* 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); + 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; + 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); + 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[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; + 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); + 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; + 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; + 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); + /* 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; + 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; + 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); + 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); + 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); - } + 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); + /* 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; + /* 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; + TCGv tmp; + TCGv addr; + int i; - LOG_DIS("movem $r%u, [$r%u%s\n", dc->op2, dc->op1, - dc->postinc ? "+]" : "]"); + LOG_DIS("movem $r%u, [$r%u%s\n", dc->op2, dc->op1, + dc->postinc ? "+]" : "]"); - cris_flush_cc_state(dc); + 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; + 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); + 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; - } + 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); + 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; + /* 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; + } + 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}, + /* 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_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_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_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_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_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_ADDI_R, dec_addi_r}, + {DEC_ADDI_ACR, dec_addi_acr}, - {DEC_ADD_R, dec_add_r}, - {DEC_SUB_R, dec_sub_r}, + {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_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_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_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_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_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_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_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}, + {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} + {{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); + /* 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; - } - } + /* 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; + /* 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); - } + 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; + 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); + 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; - } + 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; + /* 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; + 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; + 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; + 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; + /* 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; + 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)); - } + 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; + 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); + 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; - } + 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); + /* 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; + 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); + 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); - } + 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->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; + if (dc->jmp == JMP_DIRECT_CC) { + int l1; - l1 = gen_new_label(); - cris_evaluate_flags(dc); + 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; - } - } + /* 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 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)); + if (dc->clear_locked_irq) { + t_gen_mov_env_TN(locked_irq, tcg_const_tl(0)); + } - npc = dc->pc; + 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); - } + /* 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); + 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; - } + 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; + } #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, gen_opc_ptr - 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; + int i; + uint32_t srs; - if (!env || !f) - return; + 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); + 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"); + 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]; } From 8232a46a165c20fdc8f6bb2d06c71be55afce051 Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Mon, 12 Nov 2012 13:27:44 +0400 Subject: [PATCH 57/67] tcg/tcg.h: Duplicate global TCG variables in TCGContext Signed-off-by: Evgeny Voevodin Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/tcg.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tcg/tcg.h b/tcg/tcg.h index c2ae873715..6ffec1d47a 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -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 */ From efd7f48600e0e7803765d7b31cea131aae2b7329 Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Mon, 12 Nov 2012 13:27:45 +0400 Subject: [PATCH 58/67] TCG: Use gen_opc_ptr from context instead of global variable. Signed-off-by: Evgeny Voevodin Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- target-alpha/translate.c | 8 ++-- target-arm/translate.c | 8 ++-- target-cris/translate.c | 10 ++--- target-i386/translate.c | 8 ++-- target-lm32/translate.c | 10 ++--- target-m68k/translate.c | 8 ++-- target-microblaze/translate.c | 10 ++--- target-mips/translate.c | 9 +++-- target-openrisc/translate.c | 10 ++--- target-ppc/translate.c | 9 +++-- target-s390x/translate.c | 9 +++-- target-sh4/translate.c | 8 ++-- target-sparc/translate.c | 8 ++-- target-unicore32/translate.c | 8 ++-- target-xtensa/translate.c | 6 +-- tcg/tcg-op.h | 70 +++++++++++++++++------------------ tcg/tcg.c | 16 ++++---- 17 files changed, 109 insertions(+), 106 deletions(-) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 8c4dd021f3..f160f83ffe 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -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 - 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 - 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..014f3582b9 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -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 - 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 - 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 023980ec56..02969d4d53 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3297,7 +3297,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, check_breakpoint(env, dc); if (search_pc) { - j = gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -3381,7 +3381,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, 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); @@ -3434,9 +3434,9 @@ gen_intermediate_code_internal(CPUCRISState *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 - gen_opc_buf; lj++; while (lj <= j) { gen_opc_instr_start[lj++] = 0; @@ -3452,7 +3452,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, 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); + dc->pc - pc_start, tcg_ctx.gen_opc_ptr - gen_opc_buf); } #endif #endif diff --git a/target-i386/translate.c b/target-i386/translate.c index 7fdb8bcbbe..2658bf29c9 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -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 - 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 - 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..8c2a6181d8 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -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 - 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 - gen_opc_buf; lj++; while (lj <= j) { gen_opc_instr_start[lj++] = 0; @@ -1122,7 +1122,7 @@ 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 - gen_opc_buf); } #endif } diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 1430d4c991..ede3536dc4 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -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 - 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 - 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..a84c22ee0f 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -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 - 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 - gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; @@ -1916,7 +1916,7 @@ 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 - gen_opc_buf); } #endif #endif diff --git a/target-mips/translate.c b/target-mips/translate.c index 01b48fa2a2..cc126f5382 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -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 - 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 - 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..eba134e0b7 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -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 - 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 - gen_opc_buf; k++; while (k <= j) { gen_opc_instr_start[k++] = 0; @@ -1799,7 +1799,7 @@ 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 - gen_opc_buf); } #endif } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f0d49eea3f..b2a8374e61 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -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 - 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 - 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..945cc51aaf 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -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 - 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 - 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..b43e6c28dc 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -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 - 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 - 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..47bbc91426 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -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 - 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 - 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..d6bb6696ab 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -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 - 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 - 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..f272eac56d 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -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 - 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/tcg-op.h b/tcg/tcg-op.h index 8d1da2b670..9bc890fd6f 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -27,58 +27,58 @@ 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; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I32(arg1); } static inline void tcg_gen_op1_i64(TCGOpcode opc, TCGv_i64 arg1) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I64(arg1); } static inline void tcg_gen_op1i(TCGOpcode opc, TCGArg arg1) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = arg1; } static inline void tcg_gen_op2_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I32(arg1); *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; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I64(arg1); *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; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I32(arg1); *gen_opparam_ptr++ = arg2; } static inline void tcg_gen_op2i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGArg arg2) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I64(arg1); *gen_opparam_ptr++ = arg2; } static inline void tcg_gen_op2ii(TCGOpcode opc, TCGArg arg1, TCGArg arg2) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = arg1; *gen_opparam_ptr++ = arg2; } @@ -86,7 +86,7 @@ static inline void tcg_gen_op2ii(TCGOpcode opc, TCGArg arg1, TCGArg arg2) static inline void tcg_gen_op3_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3) { - *gen_opc_ptr++ = opc; + *tcg_ctx.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); @@ -95,7 +95,7 @@ static inline void tcg_gen_op3_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, static inline void tcg_gen_op3_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3) { - *gen_opc_ptr++ = opc; + *tcg_ctx.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); @@ -104,7 +104,7 @@ static inline void tcg_gen_op3_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, static inline void tcg_gen_op3i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGArg arg3) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I32(arg1); *gen_opparam_ptr++ = GET_TCGV_I32(arg2); *gen_opparam_ptr++ = arg3; @@ -113,7 +113,7 @@ static inline void tcg_gen_op3i_i32(TCGOpcode opc, TCGv_i32 arg1, static inline void tcg_gen_op3i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGArg arg3) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I64(arg1); *gen_opparam_ptr++ = GET_TCGV_I64(arg2); *gen_opparam_ptr++ = arg3; @@ -122,7 +122,7 @@ static inline void tcg_gen_op3i_i64(TCGOpcode opc, TCGv_i64 arg1, static inline void tcg_gen_ldst_op_i32(TCGOpcode opc, TCGv_i32 val, TCGv_ptr base, TCGArg offset) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I32(val); *gen_opparam_ptr++ = GET_TCGV_PTR(base); *gen_opparam_ptr++ = offset; @@ -131,7 +131,7 @@ static inline void tcg_gen_ldst_op_i32(TCGOpcode opc, TCGv_i32 val, static inline void tcg_gen_ldst_op_i64(TCGOpcode opc, TCGv_i64 val, TCGv_ptr base, TCGArg offset) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I64(val); *gen_opparam_ptr++ = GET_TCGV_PTR(base); *gen_opparam_ptr++ = offset; @@ -140,7 +140,7 @@ static inline void tcg_gen_ldst_op_i64(TCGOpcode opc, TCGv_i64 val, 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; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I64(val); *gen_opparam_ptr++ = GET_TCGV_I32(addr); *gen_opparam_ptr++ = mem_index; @@ -149,7 +149,7 @@ static inline void tcg_gen_qemu_ldst_op_i64_i32(TCGOpcode opc, TCGv_i64 val, 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; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I64(val); *gen_opparam_ptr++ = GET_TCGV_I64(addr); *gen_opparam_ptr++ = mem_index; @@ -158,7 +158,7 @@ static inline void tcg_gen_qemu_ldst_op_i64_i64(TCGOpcode opc, TCGv_i64 val, 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; + *tcg_ctx.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); @@ -168,7 +168,7 @@ static inline void tcg_gen_op4_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, 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; + *tcg_ctx.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); @@ -178,7 +178,7 @@ static inline void tcg_gen_op4_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, static inline void tcg_gen_op4i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3, TCGArg arg4) { - *gen_opc_ptr++ = opc; + *tcg_ctx.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); @@ -188,7 +188,7 @@ static inline void tcg_gen_op4i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, static inline void tcg_gen_op4i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3, TCGArg arg4) { - *gen_opc_ptr++ = opc; + *tcg_ctx.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); @@ -198,7 +198,7 @@ static inline void tcg_gen_op4i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, static inline void tcg_gen_op4ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGArg arg3, TCGArg arg4) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I32(arg1); *gen_opparam_ptr++ = GET_TCGV_I32(arg2); *gen_opparam_ptr++ = arg3; @@ -208,7 +208,7 @@ static inline void tcg_gen_op4ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2 static inline void tcg_gen_op4ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGArg arg3, TCGArg arg4) { - *gen_opc_ptr++ = opc; + *tcg_ctx.gen_opc_ptr++ = opc; *gen_opparam_ptr++ = GET_TCGV_I64(arg1); *gen_opparam_ptr++ = GET_TCGV_I64(arg2); *gen_opparam_ptr++ = arg3; @@ -218,7 +218,7 @@ static inline void tcg_gen_op4ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2 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; + *tcg_ctx.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); @@ -229,7 +229,7 @@ static inline void tcg_gen_op5_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, 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; + *tcg_ctx.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); @@ -240,7 +240,7 @@ static inline void tcg_gen_op5_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, 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; + *tcg_ctx.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); @@ -251,7 +251,7 @@ static inline void tcg_gen_op5i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, 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; + *tcg_ctx.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); @@ -263,7 +263,7 @@ 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; + *tcg_ctx.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); @@ -275,7 +275,7 @@ 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; + *tcg_ctx.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); @@ -287,7 +287,7 @@ 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; + *tcg_ctx.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); @@ -300,7 +300,7 @@ 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; + *tcg_ctx.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); @@ -313,7 +313,7 @@ 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; + *tcg_ctx.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); @@ -326,7 +326,7 @@ 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; + *tcg_ctx.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); @@ -339,7 +339,7 @@ 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; + *tcg_ctx.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); @@ -352,7 +352,7 @@ 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; + *tcg_ctx.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); diff --git a/tcg/tcg.c b/tcg/tcg.c index 35fba50c7f..d04392dacd 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -297,7 +297,7 @@ void tcg_func_start(TCGContext *s) s->goto_tb_issue_mask = 0; #endif - gen_opc_ptr = gen_opc_buf; + s->gen_opc_ptr = gen_opc_buf; gen_opparam_ptr = gen_opparam_buf; #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) @@ -641,7 +641,7 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, } #endif /* TCG_TARGET_EXTEND_ARGS */ - *gen_opc_ptr++ = INDEX_op_call; + *s->gen_opc_ptr++ = INDEX_op_call; nparam = gen_opparam_ptr++; if (ret != TCG_CALL_DUMMY_ARG) { #if TCG_TARGET_REG_BITS < 64 @@ -898,7 +898,7 @@ void tcg_dump_ops(TCGContext *s) first_insn = 1; opc_ptr = gen_opc_buf; args = gen_opparam_buf; - while (opc_ptr < gen_opc_ptr) { + while (opc_ptr < s->gen_opc_ptr) { c = *opc_ptr++; def = &tcg_op_defs[c]; if (c == INDEX_op_debug_insn_start) { @@ -1229,9 +1229,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 - 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)); @@ -1448,7 +1448,7 @@ static void tcg_liveness_analysis(TCGContext *s) static void tcg_liveness_analysis(TCGContext *s) { int nb_ops; - nb_ops = gen_opc_ptr - gen_opc_buf; + nb_ops = s->gen_opc_ptr - 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)); @@ -2222,7 +2222,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, #ifdef USE_TCG_OPTIMIZATIONS gen_opparam_ptr = - tcg_optimize(s, gen_opc_ptr, gen_opparam_buf, tcg_op_defs); + tcg_optimize(s, s->gen_opc_ptr, gen_opparam_buf, tcg_op_defs); #endif #ifdef CONFIG_PROFILER @@ -2334,7 +2334,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 - gen_opc_buf); s->op_count += n; if (n > s->op_count_max) s->op_count_max = n; From c4afe5c4d30e1dd6fc1f2b0b32ffb50f4d5ada82 Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Mon, 12 Nov 2012 13:27:46 +0400 Subject: [PATCH 59/67] TCG: Use gen_opparam_ptr from context instead of global variable. Signed-off-by: Evgeny Voevodin Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- gen-icount.h | 2 +- tcg/tcg-op.h | 254 +++++++++++++++++++++++++-------------------------- tcg/tcg.c | 36 ++++---- 3 files changed, 146 insertions(+), 146 deletions(-) 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/tcg/tcg-op.h b/tcg/tcg-op.h index 9bc890fd6f..0b3cb0be3a 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -33,230 +33,230 @@ static inline void tcg_gen_op0(TCGOpcode opc) static inline void tcg_gen_op1_i32(TCGOpcode opc, TCGv_i32 arg1) { *tcg_ctx.gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I32(arg1); } static inline void tcg_gen_op1_i64(TCGOpcode opc, TCGv_i64 arg1) { *tcg_ctx.gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); + *tcg_ctx.gen_opparam_ptr++ = GET_TCGV_I64(arg1); } static inline void tcg_gen_op1i(TCGOpcode opc, TCGArg arg1) { *tcg_ctx.gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = arg1; + *tcg_ctx.gen_opparam_ptr++ = arg1; } static inline void tcg_gen_op2_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2) { *tcg_ctx.gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = GET_TCGV_I32(arg2); + *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) { *tcg_ctx.gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = GET_TCGV_I64(arg2); + *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) { *tcg_ctx.gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I32(arg1); - *gen_opparam_ptr++ = arg2; + *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) { *tcg_ctx.gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = GET_TCGV_I64(arg1); - *gen_opparam_ptr++ = arg2; + *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) { *tcg_ctx.gen_opc_ptr++ = opc; - *gen_opparam_ptr++ = arg1; - *gen_opparam_ptr++ = arg2; + *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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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) { *tcg_ctx.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_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, @@ -264,11 +264,11 @@ static inline void tcg_gen_op5ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGArg arg4, TCGArg arg5) { *tcg_ctx.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_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, @@ -276,11 +276,11 @@ static inline void tcg_gen_op5ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGArg arg4, TCGArg arg5) { *tcg_ctx.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_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, @@ -288,12 +288,12 @@ static inline void tcg_gen_op6_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg6) { *tcg_ctx.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_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, @@ -301,12 +301,12 @@ static inline void tcg_gen_op6_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg6) { *tcg_ctx.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_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, @@ -314,12 +314,12 @@ static inline void tcg_gen_op6i_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg5, TCGArg arg6) { *tcg_ctx.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_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, @@ -327,12 +327,12 @@ static inline void tcg_gen_op6i_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg5, TCGArg arg6) { *tcg_ctx.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_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, @@ -340,12 +340,12 @@ static inline void tcg_gen_op6ii_i32(TCGOpcode opc, TCGv_i32 arg1, TCGv_i32 arg4, TCGArg arg5, TCGArg arg6) { *tcg_ctx.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_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, @@ -353,12 +353,12 @@ static inline void tcg_gen_op6ii_i64(TCGOpcode opc, TCGv_i64 arg1, TCGv_i64 arg4, TCGArg arg5, TCGArg arg6) { *tcg_ctx.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_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) diff --git a/tcg/tcg.c b/tcg/tcg.c index d04392dacd..96535b6187 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -298,7 +298,7 @@ void tcg_func_start(TCGContext *s) #endif s->gen_opc_ptr = gen_opc_buf; - gen_opparam_ptr = gen_opparam_buf; + s->gen_opparam_ptr = 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 @@ -642,22 +642,22 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, #endif /* TCG_TARGET_EXTEND_ARGS */ *s->gen_opc_ptr++ = INDEX_op_call; - nparam = gen_opparam_ptr++; + 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 +671,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 +686,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) { @@ -1240,7 +1240,7 @@ 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]; @@ -2221,7 +2221,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, #endif #ifdef USE_TCG_OPTIMIZATIONS - gen_opparam_ptr = + s->gen_opparam_ptr = tcg_optimize(s, s->gen_opc_ptr, gen_opparam_buf, tcg_op_defs); #endif From 92414b31e726ead5fd93a5bee5a6d1aecc66e454 Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Mon, 12 Nov 2012 13:27:47 +0400 Subject: [PATCH 60/67] TCG: Use gen_opc_buf from context instead of global variable. Signed-off-by: Evgeny Voevodin Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- target-alpha/translate.c | 6 ++-- target-arm/translate.c | 6 ++-- target-cris/translate.c | 8 ++--- target-i386/translate.c | 6 ++-- target-lm32/translate.c | 9 ++--- target-m68k/translate.c | 6 ++-- target-microblaze/translate.c | 9 ++--- target-mips/translate.c | 6 ++-- target-openrisc/translate.c | 9 ++--- target-ppc/translate.c | 6 ++-- target-s390x/translate.c | 6 ++-- target-sh4/translate.c | 6 ++-- target-sparc/translate.c | 6 ++-- target-unicore32/translate.c | 6 ++-- target-xtensa/translate.c | 4 +-- tcg/optimize.c | 62 +++++++++++++++++------------------ tcg/tcg.c | 30 ++++++++--------- 17 files changed, 97 insertions(+), 94 deletions(-) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index f160f83ffe..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -3465,7 +3465,7 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = tcg_ctx.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 014f3582b9..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -9974,7 +9974,7 @@ done_generating: } #endif if (search_pc) { - j = tcg_ctx.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 02969d4d53..0b0e86dbd1 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3232,7 +3232,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, 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->ppc = pc_start; @@ -3297,7 +3297,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, check_breakpoint(env, dc); if (search_pc) { - j = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -3436,7 +3436,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = tcg_ctx.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; @@ -3452,7 +3452,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, 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, tcg_ctx.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-i386/translate.c b/target-i386/translate.c index 2658bf29c9..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -8034,7 +8034,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, *tcg_ctx.gen_opc_ptr = INDEX_op_end; /* we don't forget to fill the last values */ if (search_pc) { - j = tcg_ctx.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 8c2a6181d8..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -1107,7 +1107,7 @@ static void gen_intermediate_code_internal(CPULM32State *env, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = tcg_ctx.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, tcg_ctx.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 ede3536dc4..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -3075,7 +3075,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, } #endif if (search_pc) { - j = tcg_ctx.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 a84c22ee0f..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -1899,7 +1899,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = tcg_ctx.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, tcg_ctx.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 cc126f5382..8b438f8bb0 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -15633,7 +15633,7 @@ done_generating: gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = tcg_ctx.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 eba134e0b7..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (k < j) { k++; while (k < j) { @@ -1784,7 +1784,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = tcg_ctx.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, tcg_ctx.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 b2a8374e61..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; @@ -9675,7 +9675,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, } } if (unlikely(search_pc)) { - j = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -9777,7 +9777,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (unlikely(search_pc)) { - j = tcg_ctx.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 945cc51aaf..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -5209,7 +5209,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - j = tcg_ctx.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 b43e6c28dc..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; @@ -1999,7 +1999,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, } } if (search_pc) { - i = tcg_ctx.gen_opc_ptr - gen_opc_buf; + i = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (ii < i) { ii++; while (ii < i) @@ -2058,7 +2058,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { - i = tcg_ctx.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 47bbc91426..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) @@ -5336,7 +5336,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (spc) { - j = tcg_ctx.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 d6bb6696ab..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { @@ -2114,7 +2114,7 @@ done_generating: } #endif if (search_pc) { - j = tcg_ctx.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 f272eac56d..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 = tcg_ctx.gen_opc_ptr - gen_opc_buf; + j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { lj++; while (lj < j) { 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.c b/tcg/tcg.c index 96535b6187..a039001369 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -297,7 +297,7 @@ void tcg_func_start(TCGContext *s) s->goto_tb_issue_mask = 0; #endif - s->gen_opc_ptr = gen_opc_buf; + s->gen_opc_ptr = s->gen_opc_buf; s->gen_opparam_ptr = gen_opparam_buf; #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) @@ -896,7 +896,7 @@ void tcg_dump_ops(TCGContext *s) char buf[128]; first_insn = 1; - opc_ptr = gen_opc_buf; + opc_ptr = s->gen_opc_buf; args = gen_opparam_buf; while (opc_ptr < s->gen_opc_ptr) { c = *opc_ptr++; @@ -1231,7 +1231,7 @@ static void tcg_liveness_analysis(TCGContext *s) s->gen_opc_ptr++; /* skip end */ - nb_ops = s->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)); @@ -1243,7 +1243,7 @@ static void tcg_liveness_analysis(TCGContext *s) 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 +1266,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 +1347,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 +1367,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 +1394,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 @@ -1448,7 +1448,7 @@ static void tcg_liveness_analysis(TCGContext *s) static void tcg_liveness_analysis(TCGContext *s) { int nb_ops; - nb_ops = s->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)); @@ -2253,7 +2253,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_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 +2334,7 @@ int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf) #ifdef CONFIG_PROFILER { int n; - n = (s->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; From 1ff0a2c594356b134af6742b9cb5e5757c620881 Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Mon, 12 Nov 2012 13:27:48 +0400 Subject: [PATCH 61/67] TCG: Use gen_opparam_buf from context instead of global variable. Signed-off-by: Evgeny Voevodin Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/tcg.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index a039001369..ea0bd3a7a7 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -298,7 +298,7 @@ void tcg_func_start(TCGContext *s) #endif s->gen_opc_ptr = s->gen_opc_buf; - s->gen_opparam_ptr = gen_opparam_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 @@ -897,7 +897,7 @@ void tcg_dump_ops(TCGContext *s) first_insn = 1; opc_ptr = s->gen_opc_buf; - args = gen_opparam_buf; + args = s->gen_opparam_buf; while (opc_ptr < s->gen_opc_ptr) { c = *opc_ptr++; def = &tcg_op_defs[c]; @@ -1440,8 +1440,9 @@ 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 */ @@ -2222,7 +2223,7 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, #ifdef USE_TCG_OPTIMIZATIONS s->gen_opparam_ptr = - tcg_optimize(s, s->gen_opc_ptr, gen_opparam_buf, tcg_op_defs); + tcg_optimize(s, s->gen_opc_ptr, s->gen_opparam_buf, tcg_op_defs); #endif #ifdef CONFIG_PROFILER @@ -2249,7 +2250,7 @@ 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(;;) { From 83eeb39669a19716a44bcad5a34158543b3779b8 Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Mon, 12 Nov 2012 13:27:49 +0400 Subject: [PATCH 62/67] TCG: Remove unused global variables Signed-off-by: Evgeny Voevodin Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/tcg.c | 4 ---- tcg/tcg.h | 4 ---- translate-all.c | 3 --- 3 files changed, 11 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index ea0bd3a7a7..4f756962c5 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -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; diff --git a/tcg/tcg.h b/tcg/tcg.h index 6ffec1d47a..9481e35ab4 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -465,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/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]; From 2c5c4451e69a69c0fad3303c25cc7eaad6950f79 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 3 Nov 2012 15:42:21 +0000 Subject: [PATCH 63/67] libseccomp: require version 1.0.0 Debian Wheezy has version 0.1.0 which is not compatible, avoid it. Signed-off-by: Blue Swirl --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index f847ee264e..e6c5712723 100755 --- a/configure +++ b/configure @@ -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 From 3bc2f570ec9fc930619a8ef26a22dd6d03c25dac Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Nov 2012 18:35:27 +0100 Subject: [PATCH 64/67] build: replace weak symbols with a static library Weak symbols were a nice idea, but they turned out not to be a good one. Toolchain support is just too sparse, in particular llvm-gcc is totally broken. This patch uses a surprisingly low-tech approach: a static library. Symbols in a static library are always overridden by symbols in an object file. Furthermore, if you place each function in a separate source file, object files for unused functions will not be taken in. This means that each function can use all the dependencies that it needs (especially QAPI stuff such as error_setg). Thus, all stubs are placed in separate object files and put together in a static library. The library then is linked to all programs. Signed-off-by: Paolo Bonzini Tested-by: Peter Maydell Reviewed-by: Peter Maydell Tested-by: Stefan Weil Signed-off-by: Blue Swirl --- Makefile | 16 +++++++++++----- Makefile.objs | 5 +++++ Makefile.target | 4 ++-- compiler.h | 11 ----------- osdep.c | 32 -------------------------------- oslib-win32.c | 7 ------- qemu-sockets.c | 22 ---------------------- qmp.c | 9 --------- rules.mak | 2 +- stubs/Makefile.objs | 8 ++++++++ stubs/arch-query-cpu-def.c | 9 +++++++++ stubs/fd-register.c | 6 ++++++ stubs/fdset-add-fd.c | 7 +++++++ stubs/fdset-find-fd.c | 7 +++++++ stubs/fdset-get-fd.c | 7 +++++++ stubs/fdset-remove-fd.c | 7 +++++++ stubs/get-fd.c | 8 ++++++++ stubs/set-fd-handler.c | 11 +++++++++++ 18 files changed, 89 insertions(+), 89 deletions(-) create mode 100644 stubs/Makefile.objs create mode 100644 stubs/arch-query-cpu-def.c create mode 100644 stubs/fd-register.c create mode 100644 stubs/fdset-add-fd.c create mode 100644 stubs/fdset-find-fd.c create mode 100644 stubs/fdset-get-fd.c create mode 100644 stubs/fdset-remove-fd.c create mode 100644 stubs/get-fd.c create mode 100644 stubs/set-fd-handler.c diff --git a/Makefile b/Makefile index 81c660f9f4..b8301a2521 100644 --- a/Makefile +++ b/Makefile @@ -157,6 +157,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 +189,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 +238,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 dc1e699914..3c7abca433 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -1,3 +1,7 @@ +####################################################################### +# Stub library, linked in tools +stub-obj-y = stubs/ + ####################################################################### # Target-independent parts used in system and user emulation universal-obj-y = @@ -239,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/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 */ diff --git a/osdep.c b/osdep.c index 2f7a49159a..3a63d26e75 100644 --- a/osdep.c +++ b/osdep.c @@ -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) 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-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; diff --git a/qmp.c b/qmp.c index 13e83a59e0..e3a7f0b217 100644 --- a/qmp.c +++ b/qmp.c @@ -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/rules.mak b/rules.mak index 1b173aa981..d0b04e44f5 100644 --- a/rules.mak +++ b/rules.mak @@ -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/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(); +} From de91f537997c96204e35fb308aacb102071f0827 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 18 Nov 2012 20:06:19 +0100 Subject: [PATCH 65/67] tci: fix build breakage for target MIPS commit 5f7319cd introduced GETPC() usage for MIPS, which is currently not defined when building with --enable-tcg-interpreter. Add MIPS to the list of targets we selectively define GETPC() for. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- exec-all.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 From 13586813446054aeff71b359aa627e201094375c Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 18 Nov 2012 20:16:26 +0100 Subject: [PATCH 66/67] tci: Fix build breakage (unresolved symbol tcg_out_tb_finalize) Commit 32761257c0b9fa7ee04d2871a6e48a41f119c469 enabled qemu_ld/st optimization unconditionally for some hosts. The TCG interpreter still does not support this kind of optimization. Therefore builds with TCI fail with an unresolved symbol tcg_out_tb_finalize. This is fixed here. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- configure | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/configure b/configure index e6c5712723..780b19afd6 100755 --- a/configure +++ b/configure @@ -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 From e24dc9feb0d68142d54dc3c097f57588836d1338 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 18 Sep 2012 22:52:14 +0200 Subject: [PATCH 67/67] tci: Support deposit operations The operations for INDEX_op_deposit_i32 and INDEX_op_deposit_i64 are now supported and enabled by default. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- tcg/tci/tcg-target.c | 24 ++++++++++++++++++++++++ tcg/tci/tcg-target.h | 4 ++-- tci.c | 22 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) 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 } }, @@ -199,6 +202,9 @@ static const TCGTargetOpDef tcg_target_op_defs[] = { #if TCG_TARGET_HAS_rot_i64 { 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 } }, @@ -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 diff --git a/tci.c b/tci.c index 98f5f713e0..9c87c8e8b3 100644 --- a/tci.c +++ b/tci.c @@ -688,6 +688,17 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) t2 = tci_read_ri32(&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); @@ -935,6 +946,17 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) case INDEX_op_rotr_i64: 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);