From 7943a2fac78b1b865093923bf1bdb08ae8664b3d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 30 Nov 2010 11:54:33 +0100 Subject: spice: add qxl vgabios binary. Just compiled from vgabios git repo @ git.qemu.org, copyed over and committed. Also added to the list of blobs in the Makefile. Signed-off-by: Gerd Hoffmann --- Makefile | 2 +- pc-bios/vgabios-qxl.bin | Bin 0 -> 40448 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 pc-bios/vgabios-qxl.bin diff --git a/Makefile b/Makefile index c80566c76d..6d601eef6e 100644 --- a/Makefile +++ b/Makefile @@ -205,7 +205,7 @@ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr ifdef INSTALL_BLOBS BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \ -vgabios-stdvga.bin vgabios-vmware.bin \ +vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \ gpxe-eepro100-80861209.rom \ pxe-e1000.bin \ diff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin new file mode 100644 index 0000000000..3156c6e3f1 Binary files /dev/null and b/pc-bios/vgabios-qxl.bin differ -- cgit v1.2.3 From a19cbfb346425cc760ed19b4e746417df636b761 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Apr 2010 11:50:11 +0200 Subject: spice: add qxl device qxl is a paravirtual graphics card. The qxl device is the bridge between the guest and the spice server (aka libspice-server). The spice server will send the rendering commands to the spice client, which will actually render them. The spice server is also able to render locally, which is done in case the guest wants read something from video memory. Local rendering is also used to support display over vnc and sdl. qxl is activated using "-vga qxl". qxl supports multihead, additional cards can be added via '-device qxl". [ v2: add copyright to files ] [ v2: use qemu-common.h for standard includes ] [ v2: create separate qxl-vga device for primary ] Signed-off-by: Gerd Hoffmann --- Makefile.target | 1 + hw/hw.h | 14 + hw/pc.c | 8 + hw/qxl-logger.c | 248 +++++++++ hw/qxl-render.c | 226 ++++++++ hw/qxl.c | 1587 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/qxl.h | 112 ++++ hw/vga_int.h | 2 +- qemu-options.hx | 6 +- sysemu.h | 3 +- ui/spice-core.c | 15 + vl.c | 4 +- 12 files changed, 2222 insertions(+), 4 deletions(-) create mode 100644 hw/qxl-logger.c create mode 100644 hw/qxl-render.c create mode 100644 hw/qxl.c create mode 100644 hw/qxl.h diff --git a/Makefile.target b/Makefile.target index 578484452b..c40833bd23 100644 --- a/Makefile.target +++ b/Makefile.target @@ -224,6 +224,7 @@ obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o obj-i386-y += pc_piix.o +obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o # shared objects obj-ppc-y = ppc.o diff --git a/hw/hw.h b/hw/hw.h index 77bfb58b89..163a68327e 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -528,6 +528,17 @@ extern const VMStateInfo vmstate_info_unused_buffer; .start = (_start), \ } +#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\ + .info = &vmstate_info_buffer, \ + .flags = VMS_VBUFFER|VMS_POINTER, \ + .offset = offsetof(_state, _field), \ + .start = (_start), \ +} + #define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \ .name = (stringify(_field)), \ .version_id = (_version), \ @@ -745,6 +756,9 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \ VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size) +#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size) \ + VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size) + #define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \ VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size) diff --git a/hw/pc.c b/hw/pc.c index 119c1106c2..f28e23727c 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -40,6 +40,7 @@ #include "sysbus.h" #include "sysemu.h" #include "blockdev.h" +#include "ui/qemu-spice.h" /* output Bochs bios info messages */ //#define DEBUG_BIOS @@ -991,6 +992,13 @@ void pc_vga_init(PCIBus *pci_bus) pci_vmsvga_init(pci_bus); else fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); +#ifdef CONFIG_SPICE + } else if (qxl_enabled) { + if (pci_bus) + pci_create_simple(pci_bus, -1, "qxl-vga"); + else + fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__); +#endif } else if (std_vga_enabled) { if (pci_bus) { pci_vga_init(pci_bus); diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c new file mode 100644 index 0000000000..76f43e646c --- /dev/null +++ b/hw/qxl-logger.c @@ -0,0 +1,248 @@ +/* + * qxl command logging -- for debug purposes + * + * Copyright (C) 2010 Red Hat, Inc. + * + * maintained by Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qxl.h" + +static const char *qxl_type[] = { + [ QXL_CMD_NOP ] = "nop", + [ QXL_CMD_DRAW ] = "draw", + [ QXL_CMD_UPDATE ] = "update", + [ QXL_CMD_CURSOR ] = "cursor", + [ QXL_CMD_MESSAGE ] = "message", + [ QXL_CMD_SURFACE ] = "surface", +}; + +static const char *qxl_draw_type[] = { + [ QXL_DRAW_NOP ] = "nop", + [ QXL_DRAW_FILL ] = "fill", + [ QXL_DRAW_OPAQUE ] = "opaque", + [ QXL_DRAW_COPY ] = "copy", + [ QXL_COPY_BITS ] = "copy-bits", + [ QXL_DRAW_BLEND ] = "blend", + [ QXL_DRAW_BLACKNESS ] = "blackness", + [ QXL_DRAW_WHITENESS ] = "whitemess", + [ QXL_DRAW_INVERS ] = "invers", + [ QXL_DRAW_ROP3 ] = "rop3", + [ QXL_DRAW_STROKE ] = "stroke", + [ QXL_DRAW_TEXT ] = "text", + [ QXL_DRAW_TRANSPARENT ] = "transparent", + [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend", +}; + +static const char *qxl_draw_effect[] = { + [ QXL_EFFECT_BLEND ] = "blend", + [ QXL_EFFECT_OPAQUE ] = "opaque", + [ QXL_EFFECT_REVERT_ON_DUP ] = "revert-on-dup", + [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup", + [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup", + [ QXL_EFFECT_NOP_ON_DUP ] = "nop-on-dup", + [ QXL_EFFECT_NOP ] = "nop", + [ QXL_EFFECT_OPAQUE_BRUSH ] = "opaque-brush", +}; + +static const char *qxl_surface_cmd[] = { + [ QXL_SURFACE_CMD_CREATE ] = "create", + [ QXL_SURFACE_CMD_DESTROY ] = "destroy", +}; + +static const char *spice_surface_fmt[] = { + [ SPICE_SURFACE_FMT_INVALID ] = "invalid", + [ SPICE_SURFACE_FMT_1_A ] = "alpha/1", + [ SPICE_SURFACE_FMT_8_A ] = "alpha/8", + [ SPICE_SURFACE_FMT_16_555 ] = "555/16", + [ SPICE_SURFACE_FMT_16_565 ] = "565/16", + [ SPICE_SURFACE_FMT_32_xRGB ] = "xRGB/32", + [ SPICE_SURFACE_FMT_32_ARGB ] = "ARGB/32", +}; + +static const char *qxl_cursor_cmd[] = { + [ QXL_CURSOR_SET ] = "set", + [ QXL_CURSOR_MOVE ] = "move", + [ QXL_CURSOR_HIDE ] = "hide", + [ QXL_CURSOR_TRAIL ] = "trail", +}; + +static const char *spice_cursor_type[] = { + [ SPICE_CURSOR_TYPE_ALPHA ] = "alpha", + [ SPICE_CURSOR_TYPE_MONO ] = "mono", + [ SPICE_CURSOR_TYPE_COLOR4 ] = "color4", + [ SPICE_CURSOR_TYPE_COLOR8 ] = "color8", + [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16", + [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24", + [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32", +}; + +static const char *qxl_v2n(const char *n[], size_t l, int v) +{ + if (v >= l || !n[v]) { + return "???"; + } + return n[v]; +} +#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value) + +static void qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id) +{ + QXLImage *image; + QXLImageDescriptor *desc; + + image = qxl_phys2virt(qxl, addr, group_id); + desc = &image->descriptor; + fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d", + desc->id, desc->type, desc->flags, desc->width, desc->height); + switch (desc->type) { + case SPICE_IMAGE_TYPE_BITMAP: + fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d" + " palette %" PRIx64 " data %" PRIx64, + image->bitmap.format, image->bitmap.flags, + image->bitmap.x, image->bitmap.y, + image->bitmap.stride, + image->bitmap.palette, image->bitmap.data); + break; + } + fprintf(stderr, ")"); +} + +static void qxl_log_rect(QXLRect *rect) +{ + fprintf(stderr, " %dx%d+%d+%d", + rect->right - rect->left, + rect->bottom - rect->top, + rect->left, rect->top); +} + +static void qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy, int group_id) +{ + fprintf(stderr, " src %" PRIx64, + copy->src_bitmap); + qxl_log_image(qxl, copy->src_bitmap, group_id); + fprintf(stderr, " area"); + qxl_log_rect(©->src_area); + fprintf(stderr, " rop %d", copy->rop_descriptor); +} + +static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id) +{ + fprintf(stderr, ": surface_id %d type %s effect %s", + draw->surface_id, + qxl_name(qxl_draw_type, draw->type), + qxl_name(qxl_draw_effect, draw->effect)); + switch (draw->type) { + case QXL_DRAW_COPY: + qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); + break; + } +} + +static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw, + int group_id) +{ + fprintf(stderr, ": type %s effect %s", + qxl_name(qxl_draw_type, draw->type), + qxl_name(qxl_draw_effect, draw->effect)); + if (draw->bitmap_offset) { + fprintf(stderr, ": bitmap %d", + draw->bitmap_offset); + qxl_log_rect(&draw->bitmap_area); + } + switch (draw->type) { + case QXL_DRAW_COPY: + qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id); + break; + } +} + +static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd) +{ + fprintf(stderr, ": %s id %d", + qxl_name(qxl_surface_cmd, cmd->type), + cmd->surface_id); + if (cmd->type == QXL_SURFACE_CMD_CREATE) { + fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)", + cmd->u.surface_create.width, + cmd->u.surface_create.height, + cmd->u.surface_create.stride, + qxl_name(spice_surface_fmt, cmd->u.surface_create.format), + qxl->guest_surfaces.count, qxl->guest_surfaces.max); + } + if (cmd->type == QXL_SURFACE_CMD_DESTROY) { + fprintf(stderr, " (count %d)", qxl->guest_surfaces.count); + } +} + +void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) +{ + QXLCursor *cursor; + + fprintf(stderr, ": %s", + qxl_name(qxl_cursor_cmd, cmd->type)); + switch (cmd->type) { + case QXL_CURSOR_SET: + fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64, + cmd->u.set.position.x, + cmd->u.set.position.y, + cmd->u.set.visible ? "yes" : "no", + cmd->u.set.shape); + cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); + fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d" + " unique 0x%" PRIx64 " data-size %d", + qxl_name(spice_cursor_type, cursor->header.type), + cursor->header.width, cursor->header.height, + cursor->header.hot_spot_x, cursor->header.hot_spot_y, + cursor->header.unique, cursor->data_size); + break; + case QXL_CURSOR_MOVE: + fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y); + break; + } +} + +void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) +{ + bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; + void *data; + + if (!qxl->cmdlog) { + return; + } + fprintf(stderr, "qxl-%d/%s:", qxl->id, ring); + fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data, + qxl_name(qxl_type, ext->cmd.type), + compat ? "(compat)" : ""); + + data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + switch (ext->cmd.type) { + case QXL_CMD_DRAW: + if (!compat) { + qxl_log_cmd_draw(qxl, data, ext->group_id); + } else { + qxl_log_cmd_draw_compat(qxl, data, ext->group_id); + } + break; + case QXL_CMD_SURFACE: + qxl_log_cmd_surface(qxl, data); + break; + case QXL_CMD_CURSOR: + qxl_log_cmd_cursor(qxl, data, ext->group_id); + break; + } + fprintf(stderr, "\n"); +} diff --git a/hw/qxl-render.c b/hw/qxl-render.c new file mode 100644 index 0000000000..58965e0179 --- /dev/null +++ b/hw/qxl-render.c @@ -0,0 +1,226 @@ +/* + * qxl local rendering (aka display on sdl/vnc) + * + * Copyright (C) 2010 Red Hat, Inc. + * + * maintained by Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qxl.h" + +static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) +{ + uint8_t *src = qxl->guest_primary.data; + uint8_t *dst = qxl->guest_primary.flipped; + int len, i; + + src += (qxl->guest_primary.surface.height - rect->top - 1) * + qxl->guest_primary.stride; + dst += rect->top * qxl->guest_primary.stride; + src += rect->left * qxl->guest_primary.bytes_pp; + dst += rect->left * qxl->guest_primary.bytes_pp; + len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp; + + for (i = rect->top; i < rect->bottom; i++) { + memcpy(dst, src, len); + dst += qxl->guest_primary.stride; + src -= qxl->guest_primary.stride; + } +} + +void qxl_render_resize(PCIQXLDevice *qxl) +{ + QXLSurfaceCreate *sc = &qxl->guest_primary.surface; + + qxl->guest_primary.stride = sc->stride; + qxl->guest_primary.resized++; + switch (sc->format) { + case SPICE_SURFACE_FMT_16_555: + qxl->guest_primary.bytes_pp = 2; + qxl->guest_primary.bits_pp = 15; + break; + case SPICE_SURFACE_FMT_16_565: + qxl->guest_primary.bytes_pp = 2; + qxl->guest_primary.bits_pp = 16; + break; + case SPICE_SURFACE_FMT_32_xRGB: + case SPICE_SURFACE_FMT_32_ARGB: + qxl->guest_primary.bytes_pp = 4; + qxl->guest_primary.bits_pp = 32; + break; + default: + fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__, + qxl->guest_primary.surface.format); + qxl->guest_primary.bytes_pp = 4; + qxl->guest_primary.bits_pp = 32; + break; + } +} + +void qxl_render_update(PCIQXLDevice *qxl) +{ + VGACommonState *vga = &qxl->vga; + QXLRect dirty[32], update; + void *ptr; + int i; + + if (qxl->guest_primary.resized) { + qxl->guest_primary.resized = 0; + + if (qxl->guest_primary.flipped) { + qemu_free(qxl->guest_primary.flipped); + qxl->guest_primary.flipped = NULL; + } + qemu_free_displaysurface(vga->ds); + + qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset); + if (qxl->guest_primary.stride < 0) { + /* spice surface is upside down -> need extra buffer to flip */ + qxl->guest_primary.stride = -qxl->guest_primary.stride; + qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width * + qxl->guest_primary.stride); + ptr = qxl->guest_primary.flipped; + } else { + ptr = qxl->guest_primary.data; + } + dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n", + __FUNCTION__, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.stride, + qxl->guest_primary.bytes_pp, + qxl->guest_primary.bits_pp, + qxl->guest_primary.flipped ? "yes" : "no"); + vga->ds->surface = + qemu_create_displaysurface_from(qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.bits_pp, + qxl->guest_primary.stride, + ptr); + dpy_resize(vga->ds); + } + + if (!qxl->guest_primary.commands) { + return; + } + qxl->guest_primary.commands = 0; + + update.left = 0; + update.right = qxl->guest_primary.surface.width; + update.top = 0; + update.bottom = qxl->guest_primary.surface.height; + + memset(dirty, 0, sizeof(dirty)); + qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update, + dirty, ARRAY_SIZE(dirty), 1); + + for (i = 0; i < ARRAY_SIZE(dirty); i++) { + if (qemu_spice_rect_is_empty(dirty+i)) { + break; + } + if (qxl->guest_primary.flipped) { + qxl_flip(qxl, dirty+i); + } + dpy_update(vga->ds, + dirty[i].left, dirty[i].top, + dirty[i].right - dirty[i].left, + dirty[i].bottom - dirty[i].top); + } +} + +static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor) +{ + QEMUCursor *c; + uint8_t *image, *mask; + int size; + + c = cursor_alloc(cursor->header.width, cursor->header.height); + c->hot_x = cursor->header.hot_spot_x; + c->hot_y = cursor->header.hot_spot_y; + switch (cursor->header.type) { + case SPICE_CURSOR_TYPE_ALPHA: + size = cursor->header.width * cursor->header.height * sizeof(uint32_t); + memcpy(c->data, cursor->chunk.data, size); + if (qxl->debug > 2) { + cursor_print_ascii_art(c, "qxl/alpha"); + } + break; + case SPICE_CURSOR_TYPE_MONO: + mask = cursor->chunk.data; + image = mask + cursor_get_mono_bpl(c) * c->width; + cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask); + if (qxl->debug > 2) { + cursor_print_ascii_art(c, "qxl/mono"); + } + break; + default: + fprintf(stderr, "%s: not implemented: type %d\n", + __FUNCTION__, cursor->header.type); + goto fail; + } + return c; + +fail: + cursor_put(c); + return NULL; +} + + +/* called from spice server thread context only */ +void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) +{ + QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + QXLCursor *cursor; + QEMUCursor *c; + int x = -1, y = -1; + + if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) { + return; + } + + if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) { + fprintf(stderr, "%s", __FUNCTION__); + qxl_log_cmd_cursor(qxl, cmd, ext->group_id); + fprintf(stderr, "\n"); + } + switch (cmd->type) { + case QXL_CURSOR_SET: + x = cmd->u.set.position.x; + y = cmd->u.set.position.y; + cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); + if (cursor->chunk.data_size != cursor->data_size) { + fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__); + return; + } + c = qxl_cursor(qxl, cursor); + if (c == NULL) { + c = cursor_builtin_left_ptr(); + } + qemu_mutex_lock_iothread(); + qxl->ssd.ds->cursor_define(c); + qxl->ssd.ds->mouse_set(x, y, 1); + qemu_mutex_unlock_iothread(); + cursor_put(c); + break; + case QXL_CURSOR_MOVE: + x = cmd->u.position.x; + y = cmd->u.position.y; + qemu_mutex_lock_iothread(); + qxl->ssd.ds->mouse_set(x, y, 1); + qemu_mutex_unlock_iothread(); + break; + } +} diff --git a/hw/qxl.c b/hw/qxl.c new file mode 100644 index 0000000000..207aa63f90 --- /dev/null +++ b/hw/qxl.c @@ -0,0 +1,1587 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * written by Yaniv Kamay, Izik Eidus, Gerd Hoffmann + * maintained by Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "qemu-common.h" +#include "qemu-timer.h" +#include "qemu-queue.h" +#include "monitor.h" +#include "sysemu.h" + +#include "qxl.h" + +#undef SPICE_RING_PROD_ITEM +#define SPICE_RING_PROD_ITEM(r, ret) { \ + typeof(r) start = r; \ + typeof(r) end = r + 1; \ + uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \ + typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \ + if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ + abort(); \ + } \ + ret = &m_item->el; \ + } + +#undef SPICE_RING_CONS_ITEM +#define SPICE_RING_CONS_ITEM(r, ret) { \ + typeof(r) start = r; \ + typeof(r) end = r + 1; \ + uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \ + typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \ + if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ + abort(); \ + } \ + ret = &m_item->el; \ + } + +#undef ALIGN +#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1)) + +#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" + +#define QXL_MODE(_x, _y, _b, _o) \ + { .x_res = _x, \ + .y_res = _y, \ + .bits = _b, \ + .stride = (_x) * (_b) / 8, \ + .x_mili = PIXEL_SIZE * (_x), \ + .y_mili = PIXEL_SIZE * (_y), \ + .orientation = _o, \ + } + +#define QXL_MODE_16_32(x_res, y_res, orientation) \ + QXL_MODE(x_res, y_res, 16, orientation), \ + QXL_MODE(x_res, y_res, 32, orientation) + +#define QXL_MODE_EX(x_res, y_res) \ + QXL_MODE_16_32(x_res, y_res, 0), \ + QXL_MODE_16_32(y_res, x_res, 1), \ + QXL_MODE_16_32(x_res, y_res, 2), \ + QXL_MODE_16_32(y_res, x_res, 3) + +static QXLMode qxl_modes[] = { + QXL_MODE_EX(640, 480), + QXL_MODE_EX(800, 480), + QXL_MODE_EX(800, 600), + QXL_MODE_EX(832, 624), + QXL_MODE_EX(960, 640), + QXL_MODE_EX(1024, 600), + QXL_MODE_EX(1024, 768), + QXL_MODE_EX(1152, 864), + QXL_MODE_EX(1152, 870), + QXL_MODE_EX(1280, 720), + QXL_MODE_EX(1280, 760), + QXL_MODE_EX(1280, 768), + QXL_MODE_EX(1280, 800), + QXL_MODE_EX(1280, 960), + QXL_MODE_EX(1280, 1024), + QXL_MODE_EX(1360, 768), + QXL_MODE_EX(1366, 768), + QXL_MODE_EX(1400, 1050), + QXL_MODE_EX(1440, 900), + QXL_MODE_EX(1600, 900), + QXL_MODE_EX(1600, 1200), + QXL_MODE_EX(1680, 1050), + QXL_MODE_EX(1920, 1080), +#if VGA_RAM_SIZE >= (16 * 1024 * 1024) + /* these modes need more than 8 MB video memory */ + QXL_MODE_EX(1920, 1200), + QXL_MODE_EX(1920, 1440), + QXL_MODE_EX(2048, 1536), + QXL_MODE_EX(2560, 1440), + QXL_MODE_EX(2560, 1600), +#endif +#if VGA_RAM_SIZE >= (32 * 1024 * 1024) + /* these modes need more than 16 MB video memory */ + QXL_MODE_EX(2560, 2048), + QXL_MODE_EX(2800, 2100), + QXL_MODE_EX(3200, 2400), +#endif +}; + +static PCIQXLDevice *qxl0; + +static void qxl_send_events(PCIQXLDevice *d, uint32_t events); +static void qxl_destroy_primary(PCIQXLDevice *d); +static void qxl_reset_memslots(PCIQXLDevice *d); +static void qxl_reset_surfaces(PCIQXLDevice *d); +static void qxl_ring_set_dirty(PCIQXLDevice *qxl); + +static inline uint32_t msb_mask(uint32_t val) +{ + uint32_t mask; + + do { + mask = ~(val - 1) & val; + val &= ~mask; + } while (mask < val); + + return mask; +} + +static ram_addr_t qxl_rom_size(void) +{ + uint32_t rom_size = sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes); + rom_size = MAX(rom_size, TARGET_PAGE_SIZE); + rom_size = msb_mask(rom_size * 2 - 1); + return rom_size; +} + +static void init_qxl_rom(PCIQXLDevice *d) +{ + QXLRom *rom = qemu_get_ram_ptr(d->rom_offset); + QXLModes *modes = (QXLModes *)(rom + 1); + uint32_t ram_header_size; + uint32_t surface0_area_size; + uint32_t num_pages; + uint32_t fb, maxfb = 0; + int i; + + memset(rom, 0, d->rom_size); + + rom->magic = cpu_to_le32(QXL_ROM_MAGIC); + rom->id = cpu_to_le32(d->id); + rom->log_level = cpu_to_le32(d->guestdebug); + rom->modes_offset = cpu_to_le32(sizeof(QXLRom)); + + rom->slot_gen_bits = MEMSLOT_GENERATION_BITS; + rom->slot_id_bits = MEMSLOT_SLOT_BITS; + rom->slots_start = 1; + rom->slots_end = NUM_MEMSLOTS - 1; + rom->n_surfaces = cpu_to_le32(NUM_SURFACES); + + modes->n_modes = cpu_to_le32(ARRAY_SIZE(qxl_modes)); + for (i = 0; i < modes->n_modes; i++) { + fb = qxl_modes[i].y_res * qxl_modes[i].stride; + if (maxfb < fb) { + maxfb = fb; + } + modes->modes[i].id = cpu_to_le32(i); + modes->modes[i].x_res = cpu_to_le32(qxl_modes[i].x_res); + modes->modes[i].y_res = cpu_to_le32(qxl_modes[i].y_res); + modes->modes[i].bits = cpu_to_le32(qxl_modes[i].bits); + modes->modes[i].stride = cpu_to_le32(qxl_modes[i].stride); + modes->modes[i].x_mili = cpu_to_le32(qxl_modes[i].x_mili); + modes->modes[i].y_mili = cpu_to_le32(qxl_modes[i].y_mili); + modes->modes[i].orientation = cpu_to_le32(qxl_modes[i].orientation); + } + if (maxfb < VGA_RAM_SIZE && d->id == 0) + maxfb = VGA_RAM_SIZE; + + ram_header_size = ALIGN(sizeof(QXLRam), 4096); + surface0_area_size = ALIGN(maxfb, 4096); + num_pages = d->vga.vram_size; + num_pages -= ram_header_size; + num_pages -= surface0_area_size; + num_pages = num_pages / TARGET_PAGE_SIZE; + + rom->draw_area_offset = cpu_to_le32(0); + rom->surface0_area_size = cpu_to_le32(surface0_area_size); + rom->pages_offset = cpu_to_le32(surface0_area_size); + rom->num_pages = cpu_to_le32(num_pages); + rom->ram_header_offset = cpu_to_le32(d->vga.vram_size - ram_header_size); + + d->shadow_rom = *rom; + d->rom = rom; + d->modes = modes; +} + +static void init_qxl_ram(PCIQXLDevice *d) +{ + uint8_t *buf; + uint64_t *item; + + buf = d->vga.vram_ptr; + d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset)); + d->ram->magic = cpu_to_le32(QXL_RAM_MAGIC); + d->ram->int_pending = cpu_to_le32(0); + d->ram->int_mask = cpu_to_le32(0); + SPICE_RING_INIT(&d->ram->cmd_ring); + SPICE_RING_INIT(&d->ram->cursor_ring); + SPICE_RING_INIT(&d->ram->release_ring); + SPICE_RING_PROD_ITEM(&d->ram->release_ring, item); + *item = 0; + qxl_ring_set_dirty(d); +} + +/* can be called from spice server thread context */ +static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end) +{ + while (addr < end) { + cpu_physical_memory_set_dirty(addr); + addr += TARGET_PAGE_SIZE; + } +} + +static void qxl_rom_set_dirty(PCIQXLDevice *qxl) +{ + ram_addr_t addr = qxl->rom_offset; + qxl_set_dirty(addr, addr + qxl->rom_size); +} + +/* called from spice server thread context only */ +static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr) +{ + ram_addr_t addr = qxl->vga.vram_offset; + void *base = qxl->vga.vram_ptr; + intptr_t offset; + + offset = ptr - base; + offset &= ~(TARGET_PAGE_SIZE-1); + assert(offset < qxl->vga.vram_size); + qxl_set_dirty(addr + offset, addr + offset + TARGET_PAGE_SIZE); +} + +/* can be called from spice server thread context */ +static void qxl_ring_set_dirty(PCIQXLDevice *qxl) +{ + ram_addr_t addr = qxl->vga.vram_offset + qxl->shadow_rom.ram_header_offset; + ram_addr_t end = qxl->vga.vram_offset + qxl->vga.vram_size; + qxl_set_dirty(addr, end); +} + +/* + * keep track of some command state, for savevm/loadvm. + * called from spice server thread context only + */ +static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) +{ + switch (le32_to_cpu(ext->cmd.type)) { + case QXL_CMD_SURFACE: + { + QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + uint32_t id = le32_to_cpu(cmd->surface_id); + PANIC_ON(id >= NUM_SURFACES); + if (cmd->type == QXL_SURFACE_CMD_CREATE) { + qxl->guest_surfaces.cmds[id] = ext->cmd.data; + qxl->guest_surfaces.count++; + if (qxl->guest_surfaces.max < qxl->guest_surfaces.count) + qxl->guest_surfaces.max = qxl->guest_surfaces.count; + } + if (cmd->type == QXL_SURFACE_CMD_DESTROY) { + qxl->guest_surfaces.cmds[id] = 0; + qxl->guest_surfaces.count--; + } + break; + } + case QXL_CMD_CURSOR: + { + QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + if (cmd->type == QXL_CURSOR_SET) { + qxl->guest_cursor = ext->cmd.data; + } + break; + } + } +} + +/* spice display interface callbacks */ + +static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + + dprint(qxl, 1, "%s:\n", __FUNCTION__); + qxl->ssd.worker = qxl_worker; +} + +static void interface_set_compression_level(QXLInstance *sin, int level) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + + dprint(qxl, 1, "%s: %d\n", __FUNCTION__, level); + qxl->shadow_rom.compression_level = cpu_to_le32(level); + qxl->rom->compression_level = cpu_to_le32(level); + qxl_rom_set_dirty(qxl); +} + +static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + + qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time); + qxl->rom->mm_clock = cpu_to_le32(mm_time); + qxl_rom_set_dirty(qxl); +} + +static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + + dprint(qxl, 1, "%s:\n", __FUNCTION__); + info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; + info->memslot_id_bits = MEMSLOT_SLOT_BITS; + info->num_memslots = NUM_MEMSLOTS; + info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; + info->internal_groupslot_id = 0; + info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS; + info->n_surfaces = NUM_SURFACES; +} + +/* called from spice server thread context only */ +static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + SimpleSpiceUpdate *update; + QXLCommandRing *ring; + QXLCommand *cmd; + int notify; + + switch (qxl->mode) { + case QXL_MODE_VGA: + dprint(qxl, 2, "%s: vga\n", __FUNCTION__); + update = qemu_spice_create_update(&qxl->ssd); + if (update == NULL) { + return false; + } + *ext = update->ext; + qxl_log_command(qxl, "vga", ext); + return true; + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: + case QXL_MODE_UNDEFINED: + dprint(qxl, 2, "%s: %s\n", __FUNCTION__, + qxl->cmdflags ? "compat" : "native"); + ring = &qxl->ram->cmd_ring; + if (SPICE_RING_IS_EMPTY(ring)) { + return false; + } + SPICE_RING_CONS_ITEM(ring, cmd); + ext->cmd = *cmd; + ext->group_id = MEMSLOT_GROUP_GUEST; + ext->flags = qxl->cmdflags; + SPICE_RING_POP(ring, notify); + qxl_ring_set_dirty(qxl); + if (notify) { + qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY); + } + qxl->guest_primary.commands++; + qxl_track_command(qxl, ext); + qxl_log_command(qxl, "cmd", ext); + return true; + default: + return false; + } +} + +/* called from spice server thread context only */ +static int interface_req_cmd_notification(QXLInstance *sin) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int wait = 1; + + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: + case QXL_MODE_UNDEFINED: + SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait); + qxl_ring_set_dirty(qxl); + break; + default: + /* nothing */ + break; + } + return wait; +} + +/* called from spice server thread context only */ +static inline void qxl_push_free_res(PCIQXLDevice *d, int flush) +{ + QXLReleaseRing *ring = &d->ram->release_ring; + uint64_t *item; + int notify; + +#define QXL_FREE_BUNCH_SIZE 32 + + if (ring->prod - ring->cons + 1 == ring->num_items) { + /* ring full -- can't push */ + return; + } + if (!flush && d->oom_running) { + /* collect everything from oom handler before pushing */ + return; + } + if (!flush && d->num_free_res < QXL_FREE_BUNCH_SIZE) { + /* collect a bit more before pushing */ + return; + } + + SPICE_RING_PUSH(ring, notify); + dprint(d, 2, "free: push %d items, notify %s, ring %d/%d [%d,%d]\n", + d->num_free_res, notify ? "yes" : "no", + ring->prod - ring->cons, ring->num_items, + ring->prod, ring->cons); + if (notify) { + qxl_send_events(d, QXL_INTERRUPT_DISPLAY); + } + SPICE_RING_PROD_ITEM(ring, item); + *item = 0; + d->num_free_res = 0; + d->last_release = NULL; + qxl_ring_set_dirty(d); +} + +/* called from spice server thread context only */ +static void interface_release_resource(QXLInstance *sin, + struct QXLReleaseInfoExt ext) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + QXLReleaseRing *ring; + uint64_t *item, id; + + if (ext.group_id == MEMSLOT_GROUP_HOST) { + /* host group -> vga mode update request */ + qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id); + return; + } + + /* + * ext->info points into guest-visible memory + * pci bar 0, $command.release_info + */ + ring = &qxl->ram->release_ring; + SPICE_RING_PROD_ITEM(ring, item); + if (*item == 0) { + /* stick head into the ring */ + id = ext.info->id; + ext.info->next = 0; + qxl_ram_set_dirty(qxl, &ext.info->next); + *item = id; + qxl_ring_set_dirty(qxl); + } else { + /* append item to the list */ + qxl->last_release->next = ext.info->id; + qxl_ram_set_dirty(qxl, &qxl->last_release->next); + ext.info->next = 0; + qxl_ram_set_dirty(qxl, &ext.info->next); + } + qxl->last_release = ext.info; + qxl->num_free_res++; + dprint(qxl, 3, "%4d\r", qxl->num_free_res); + qxl_push_free_res(qxl, 0); +} + +/* called from spice server thread context only */ +static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + QXLCursorRing *ring; + QXLCommand *cmd; + int notify; + + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: + case QXL_MODE_UNDEFINED: + ring = &qxl->ram->cursor_ring; + if (SPICE_RING_IS_EMPTY(ring)) { + return false; + } + SPICE_RING_CONS_ITEM(ring, cmd); + ext->cmd = *cmd; + ext->group_id = MEMSLOT_GROUP_GUEST; + ext->flags = qxl->cmdflags; + SPICE_RING_POP(ring, notify); + qxl_ring_set_dirty(qxl); + if (notify) { + qxl_send_events(qxl, QXL_INTERRUPT_CURSOR); + } + qxl->guest_primary.commands++; + qxl_track_command(qxl, ext); + qxl_log_command(qxl, "csr", ext); + if (qxl->id == 0) { + qxl_render_cursor(qxl, ext); + } + return true; + default: + return false; + } +} + +/* called from spice server thread context only */ +static int interface_req_cursor_notification(QXLInstance *sin) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int wait = 1; + + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: + case QXL_MODE_UNDEFINED: + SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait); + qxl_ring_set_dirty(qxl); + break; + default: + /* nothing */ + break; + } + return wait; +} + +/* called from spice server thread context */ +static void interface_notify_update(QXLInstance *sin, uint32_t update_id) +{ + fprintf(stderr, "%s: abort()\n", __FUNCTION__); + abort(); +} + +/* called from spice server thread context only */ +static int interface_flush_resources(QXLInstance *sin) +{ + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int ret; + + dprint(qxl, 1, "free: guest flush (have %d)\n", qxl->num_free_res); + ret = qxl->num_free_res; + if (ret) { + qxl_push_free_res(qxl, 1); + } + return ret; +} + +static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", + .base.major_version = SPICE_INTERFACE_QXL_MAJOR, + .base.minor_version = SPICE_INTERFACE_QXL_MINOR, + + .attache_worker = interface_attach_worker, + .set_compression_level = interface_set_compression_level, + .set_mm_time = interface_set_mm_time, + .get_init_info = interface_get_init_info, + + /* the callbacks below are called from spice server thread context */ + .get_command = interface_get_command, + .req_cmd_notification = interface_req_cmd_notification, + .release_resource = interface_release_resource, + .get_cursor_command = interface_get_cursor_command, + .req_cursor_notification = interface_req_cursor_notification, + .notify_update = interface_notify_update, + .flush_resources = interface_flush_resources, +}; + +static void qxl_enter_vga_mode(PCIQXLDevice *d) +{ + if (d->mode == QXL_MODE_VGA) { + return; + } + dprint(d, 1, "%s\n", __FUNCTION__); + qemu_spice_create_host_primary(&d->ssd); + d->mode = QXL_MODE_VGA; + memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); +} + +static void qxl_exit_vga_mode(PCIQXLDevice *d) +{ + if (d->mode != QXL_MODE_VGA) { + return; + } + dprint(d, 1, "%s\n", __FUNCTION__); + qxl_destroy_primary(d); +} + +static void qxl_set_irq(PCIQXLDevice *d) +{ + uint32_t pending = le32_to_cpu(d->ram->int_pending); + uint32_t mask = le32_to_cpu(d->ram->int_mask); + int level = !!(pending & mask); + qemu_set_irq(d->pci.irq[0], level); + qxl_ring_set_dirty(d); +} + +static void qxl_write_config(PCIDevice *d, uint32_t address, + uint32_t val, int len) +{ + PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, d); + VGACommonState *vga = &qxl->vga; + + vga_dirty_log_stop(vga); + pci_default_write_config(d, address, val, len); + if (vga->map_addr && qxl->pci.io_regions[0].addr == -1) { + vga->map_addr = 0; + } + vga_dirty_log_start(vga); +} + +static void qxl_check_state(PCIQXLDevice *d) +{ + QXLRam *ram = d->ram; + + assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring)); + assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring)); +} + +static void qxl_reset_state(PCIQXLDevice *d) +{ + QXLRam *ram = d->ram; + QXLRom *rom = d->rom; + + assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring)); + assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring)); + d->shadow_rom.update_id = cpu_to_le32(0); + *rom = d->shadow_rom; + qxl_rom_set_dirty(d); + init_qxl_ram(d); + d->num_free_res = 0; + d->last_release = NULL; + memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); +} + +static void qxl_soft_reset(PCIQXLDevice *d) +{ + dprint(d, 1, "%s:\n", __FUNCTION__); + qxl_check_state(d); + + if (d->id == 0) { + qxl_enter_vga_mode(d); + } else { + d->mode = QXL_MODE_UNDEFINED; + } +} + +static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) +{ + dprint(d, 1, "%s: start%s\n", __FUNCTION__, + loadvm ? " (loadvm)" : ""); + + qemu_mutex_unlock_iothread(); + d->ssd.worker->reset_cursor(d->ssd.worker); + d->ssd.worker->reset_image_cache(d->ssd.worker); + qemu_mutex_lock_iothread(); + qxl_reset_surfaces(d); + qxl_reset_memslots(d); + + /* pre loadvm reset must not touch QXLRam. This lives in + * device memory, is migrated together with RAM and thus + * already loaded at this point */ + if (!loadvm) { + qxl_reset_state(d); + } + qemu_spice_create_host_memslot(&d->ssd); + qxl_soft_reset(d); + + dprint(d, 1, "%s: done\n", __FUNCTION__); +} + +static void qxl_reset_handler(DeviceState *dev) +{ + PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev); + qxl_hard_reset(d, 0); +} + +static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + VGACommonState *vga = opaque; + PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga); + + if (qxl->mode != QXL_MODE_VGA) { + dprint(qxl, 1, "%s\n", __FUNCTION__); + qxl_destroy_primary(qxl); + qxl_soft_reset(qxl); + } + vga_ioport_write(opaque, addr, val); +} + +static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) +{ + static const int regions[] = { + QXL_RAM_RANGE_INDEX, + QXL_VRAM_RANGE_INDEX, + }; + uint64_t guest_start; + uint64_t guest_end; + int pci_region; + pcibus_t pci_start; + pcibus_t pci_end; + intptr_t virt_start; + QXLDevMemSlot memslot; + int i; + + guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start); + guest_end = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end); + + dprint(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n", + __FUNCTION__, slot_id, + guest_start, guest_end); + + PANIC_ON(slot_id >= NUM_MEMSLOTS); + PANIC_ON(guest_start > guest_end); + + for (i = 0; i < ARRAY_SIZE(regions); i++) { + pci_region = regions[i]; + pci_start = d->pci.io_regions[pci_region].addr; + pci_end = pci_start + d->pci.io_regions[pci_region].size; + /* mapped? */ + if (pci_start == -1) { + continue; + } + /* start address in range ? */ + if (guest_start < pci_start || guest_start > pci_end) { + continue; + } + /* end address in range ? */ + if (guest_end > pci_end) { + continue; + } + /* passed */ + break; + } + PANIC_ON(i == ARRAY_SIZE(regions)); /* finished loop without match */ + + switch (pci_region) { + case QXL_RAM_RANGE_INDEX: + virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset); + break; + case QXL_VRAM_RANGE_INDEX: + virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset); + break; + default: + /* should not happen */ + abort(); + } + + memslot.slot_id = slot_id; + memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */ + memslot.virt_start = virt_start + (guest_start - pci_start); + memslot.virt_end = virt_start + (guest_end - pci_start); + memslot.addr_delta = memslot.virt_start - delta; + memslot.generation = d->rom->slot_generation = 0; + qxl_rom_set_dirty(d); + + dprint(d, 1, "%s: slot %d: host virt 0x%" PRIx64 " - 0x%" PRIx64 "\n", + __FUNCTION__, memslot.slot_id, + memslot.virt_start, memslot.virt_end); + + d->ssd.worker->add_memslot(d->ssd.worker, &memslot); + d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; + d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; + d->guest_slots[slot_id].delta = delta; + d->guest_slots[slot_id].active = 1; +} + +static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) +{ + dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id); + d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id); + d->guest_slots[slot_id].active = 0; +} + +static void qxl_reset_memslots(PCIQXLDevice *d) +{ + dprint(d, 1, "%s:\n", __FUNCTION__); + d->ssd.worker->reset_memslots(d->ssd.worker); + memset(&d->guest_slots, 0, sizeof(d->guest_slots)); +} + +static void qxl_reset_surfaces(PCIQXLDevice *d) +{ + dprint(d, 1, "%s:\n", __FUNCTION__); + d->mode = QXL_MODE_UNDEFINED; + qemu_mutex_unlock_iothread(); + d->ssd.worker->destroy_surfaces(d->ssd.worker); + qemu_mutex_lock_iothread(); + memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); +} + +/* called from spice server thread context only */ +void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) +{ + uint64_t phys = le64_to_cpu(pqxl); + uint32_t slot = (phys >> (64 - 8)) & 0xff; + uint64_t offset = phys & 0xffffffffffff; + + switch (group_id) { + case MEMSLOT_GROUP_HOST: + return (void*)offset; + case MEMSLOT_GROUP_GUEST: + PANIC_ON(slot > NUM_MEMSLOTS); + PANIC_ON(!qxl->guest_slots[slot].active); + PANIC_ON(offset < qxl->guest_slots[slot].delta); + offset -= qxl->guest_slots[slot].delta; + PANIC_ON(offset > qxl->guest_slots[slot].size) + return qxl->guest_slots[slot].ptr + offset; + default: + PANIC_ON(1); + } +} + +static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) +{ + QXLDevSurfaceCreate surface; + QXLSurfaceCreate *sc = &qxl->guest_primary.surface; + + assert(qxl->mode != QXL_MODE_NATIVE); + qxl_exit_vga_mode(qxl); + + dprint(qxl, 1, "%s: %dx%d\n", __FUNCTION__, + le32_to_cpu(sc->width), le32_to_cpu(sc->height)); + + surface.format = le32_to_cpu(sc->format); + surface.height = le32_to_cpu(sc->height); + surface.mem = le64_to_cpu(sc->mem); + surface.position = le32_to_cpu(sc->position); + surface.stride = le32_to_cpu(sc->stride); + surface.width = le32_to_cpu(sc->width); + surface.type = le32_to_cpu(sc->type); + surface.flags = le32_to_cpu(sc->flags); + + surface.mouse_mode = true; + surface.group_id = MEMSLOT_GROUP_GUEST; + if (loadvm) { + surface.flags |= QXL_SURF_FLAG_KEEP_DATA; + } + + qxl->mode = QXL_MODE_NATIVE; + qxl->cmdflags = 0; + qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface); + + /* for local rendering */ + qxl_render_resize(qxl); +} + +static void qxl_destroy_primary(PCIQXLDevice *d) +{ + if (d->mode == QXL_MODE_UNDEFINED) { + return; + } + + dprint(d, 1, "%s\n", __FUNCTION__); + + d->mode = QXL_MODE_UNDEFINED; + d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0); +} + +static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) +{ + pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr; + pcibus_t end = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start; + QXLMode *mode = d->modes->modes + modenr; + uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr; + QXLMemSlot slot = { + .mem_start = start, + .mem_end = end + }; + QXLSurfaceCreate surface = { + .width = mode->x_res, + .height = mode->y_res, + .stride = -mode->x_res * 4, + .format = SPICE_SURFACE_FMT_32_xRGB, + .flags = loadvm ? QXL_SURF_FLAG_KEEP_DATA : 0, + .mouse_mode = true, + .mem = devmem + d->shadow_rom.draw_area_offset, + }; + + dprint(d, 1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%lx ]\n", __FUNCTION__, + modenr, mode->x_res, mode->y_res, mode->bits, devmem); + if (!loadvm) { + qxl_hard_reset(d, 0); + } + + d->guest_slots[0].slot = slot; + qxl_add_memslot(d, 0, devmem); + + d->guest_primary.surface = surface; + qxl_create_guest_primary(d, 0); + + d->mode = QXL_MODE_COMPAT; + d->cmdflags = QXL_COMMAND_FLAG_COMPAT; +#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */ + if (mode->bits == 16) { + d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP; + } +#endif + d->shadow_rom.mode = cpu_to_le32(modenr); + d->rom->mode = cpu_to_le32(modenr); + qxl_rom_set_dirty(d); +} + +static void ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + PCIQXLDevice *d = opaque; + uint32_t io_port = addr - d->io_base; + + switch (io_port) { + case QXL_IO_RESET: + case QXL_IO_SET_MODE: + case QXL_IO_MEMSLOT_ADD: + case QXL_IO_MEMSLOT_DEL: + case QXL_IO_CREATE_PRIMARY: + break; + default: + if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT) + break; + dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port); + return; + } + + switch (io_port) { + case QXL_IO_UPDATE_AREA: + { + QXLRect update = d->ram->update_area; + qemu_mutex_unlock_iothread(); + d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface, + &update, NULL, 0, 0); + qemu_mutex_lock_iothread(); + break; + } + case QXL_IO_NOTIFY_CMD: + d->ssd.worker->wakeup(d->ssd.worker); + break; + case QXL_IO_NOTIFY_CURSOR: + d->ssd.worker->wakeup(d->ssd.worker); + break; + case QXL_IO_UPDATE_IRQ: + qxl_set_irq(d); + break; + case QXL_IO_NOTIFY_OOM: + if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) { + break; + } + pthread_yield(); + if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) { + break; + } + d->oom_running = 1; + d->ssd.worker->oom(d->ssd.worker); + d->oom_running = 0; + break; + case QXL_IO_SET_MODE: + dprint(d, 1, "QXL_SET_MODE %d\n", val); + qxl_set_mode(d, val, 0); + break; + case QXL_IO_LOG: + if (d->guestdebug) { + fprintf(stderr, "qxl/guest: %s", d->ram->log_buf); + } + break; + case QXL_IO_RESET: + dprint(d, 1, "QXL_IO_RESET\n"); + qxl_hard_reset(d, 0); + break; + case QXL_IO_MEMSLOT_ADD: + PANIC_ON(val >= NUM_MEMSLOTS); + PANIC_ON(d->guest_slots[val].active); + d->guest_slots[val].slot = d->ram->mem_slot; + qxl_add_memslot(d, val, 0); + break; + case QXL_IO_MEMSLOT_DEL: + qxl_del_memslot(d, val); + break; + case QXL_IO_CREATE_PRIMARY: + PANIC_ON(val != 0); + dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n"); + d->guest_primary.surface = d->ram->create_surface; + qxl_create_guest_primary(d, 0); + break; + case QXL_IO_DESTROY_PRIMARY: + PANIC_ON(val != 0); + dprint(d, 1, "QXL_IO_DESTROY_PRIMARY\n"); + qxl_destroy_primary(d); + break; + case QXL_IO_DESTROY_SURFACE_WAIT: + d->ssd.worker->destroy_surface_wait(d->ssd.worker, val); + break; + case QXL_IO_DESTROY_ALL_SURFACES: + d->ssd.worker->destroy_surfaces(d->ssd.worker); + break; + default: + fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); + abort(); + } +} + +static uint32_t ioport_read(void *opaque, uint32_t addr) +{ + PCIQXLDevice *d = opaque; + + dprint(d, 1, "%s: unexpected\n", __FUNCTION__); + return 0xff; +} + +static void qxl_map(PCIDevice *pci, int region_num, + pcibus_t addr, pcibus_t size, int type) +{ + static const char *names[] = { + [ QXL_IO_RANGE_INDEX ] = "ioports", + [ QXL_RAM_RANGE_INDEX ] = "devram", + [ QXL_ROM_RANGE_INDEX ] = "rom", + [ QXL_VRAM_RANGE_INDEX ] = "vram", + }; + PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci); + + dprint(qxl, 1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__, + region_num, names[region_num], addr, size); + + switch (region_num) { + case QXL_IO_RANGE_INDEX: + register_ioport_write(addr, size, 1, ioport_write, pci); + register_ioport_read(addr, size, 1, ioport_read, pci); + qxl->io_base = addr; + break; + case QXL_RAM_RANGE_INDEX: + cpu_register_physical_memory(addr, size, qxl->vga.vram_offset | IO_MEM_RAM); + qxl->vga.map_addr = addr; + qxl->vga.map_end = addr + size; + if (qxl->id == 0) { + vga_dirty_log_start(&qxl->vga); + } + break; + case QXL_ROM_RANGE_INDEX: + cpu_register_physical_memory(addr, size, qxl->rom_offset | IO_MEM_ROM); + break; + case QXL_VRAM_RANGE_INDEX: + cpu_register_physical_memory(addr, size, qxl->vram_offset | IO_MEM_RAM); + break; + } +} + +static void pipe_read(void *opaque) +{ + PCIQXLDevice *d = opaque; + char dummy; + int len; + + do { + len = read(d->pipe[0], &dummy, sizeof(dummy)); + } while (len == sizeof(dummy)); + qxl_set_irq(d); +} + +/* called from spice server thread context only */ +static void qxl_send_events(PCIQXLDevice *d, uint32_t events) +{ + uint32_t old_pending; + uint32_t le_events = cpu_to_le32(events); + + assert(d->ssd.running); + old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); + if ((old_pending & le_events) == le_events) { + return; + } + if (pthread_self() == d->main) { + qxl_set_irq(d); + } else { + if (write(d->pipe[1], d, 1) != 1) { + dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__); + } + } +} + +static void init_pipe_signaling(PCIQXLDevice *d) +{ + if (pipe(d->pipe) < 0) { + dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__); + return; + } +#ifdef CONFIG_IOTHREAD + fcntl(d->pipe[0], F_SETFL, O_NONBLOCK); +#else + fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */); +#endif + fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); + fcntl(d->pipe[0], F_SETOWN, getpid()); + + d->main = pthread_self(); + qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); +} + +/* graphics console */ + +static void qxl_hw_update(void *opaque) +{ + PCIQXLDevice *qxl = opaque; + VGACommonState *vga = &qxl->vga; + + switch (qxl->mode) { + case QXL_MODE_VGA: + vga->update(vga); + break; + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: + qxl_render_update(qxl); + break; + default: + break; + } +} + +static void qxl_hw_invalidate(void *opaque) +{ + PCIQXLDevice *qxl = opaque; + VGACommonState *vga = &qxl->vga; + + vga->invalidate(vga); +} + +static void qxl_hw_screen_dump(void *opaque, const char *filename) +{ + PCIQXLDevice *qxl = opaque; + VGACommonState *vga = &qxl->vga; + + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: + qxl_render_update(qxl); + ppm_save(filename, qxl->ssd.ds->surface); + break; + case QXL_MODE_VGA: + vga->screen_dump(vga, filename); + break; + default: + break; + } +} + +static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) +{ + PCIQXLDevice *qxl = opaque; + VGACommonState *vga = &qxl->vga; + + if (qxl->mode == QXL_MODE_VGA) { + vga->text_update(vga, chardata); + return; + } +} + +static void qxl_vm_change_state_handler(void *opaque, int running, int reason) +{ + PCIQXLDevice *qxl = opaque; + qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason); + + if (!running && qxl->mode == QXL_MODE_NATIVE) { + /* dirty all vram (which holds surfaces) to make sure it is saved */ + /* FIXME #1: should go out during "live" stage */ + /* FIXME #2: we only need to save the areas which are actually used */ + ram_addr_t addr = qxl->vram_offset; + qxl_set_dirty(addr, addr + qxl->vram_size); + } +} + +/* display change listener */ + +static void display_update(struct DisplayState *ds, int x, int y, int w, int h) +{ + if (qxl0->mode == QXL_MODE_VGA) { + qemu_spice_display_update(&qxl0->ssd, x, y, w, h); + } +} + +static void display_resize(struct DisplayState *ds) +{ + if (qxl0->mode == QXL_MODE_VGA) { + qemu_spice_display_resize(&qxl0->ssd); + } +} + +static void display_refresh(struct DisplayState *ds) +{ + if (qxl0->mode == QXL_MODE_VGA) { + qemu_spice_display_refresh(&qxl0->ssd); + } +} + +static DisplayChangeListener display_listener = { + .dpy_update = display_update, + .dpy_resize = display_resize, + .dpy_refresh = display_refresh, +}; + +static int qxl_init_common(PCIQXLDevice *qxl) +{ + uint8_t* config = qxl->pci.config; + uint32_t pci_device_id; + uint32_t pci_device_rev; + uint32_t io_size; + + qxl->mode = QXL_MODE_UNDEFINED; + qxl->generation = 1; + qxl->num_memslots = NUM_MEMSLOTS; + qxl->num_surfaces = NUM_SURFACES; + + switch (qxl->revision) { + case 1: /* spice 0.4 -- qxl-1 */ + pci_device_id = QXL_DEVICE_ID_STABLE; + pci_device_rev = QXL_REVISION_STABLE_V04; + break; + case 2: /* spice 0.6 -- qxl-2 */ + pci_device_id = QXL_DEVICE_ID_STABLE; + pci_device_rev = QXL_REVISION_STABLE_V06; + break; + default: /* experimental */ + pci_device_id = QXL_DEVICE_ID_DEVEL; + pci_device_rev = 1; + break; + } + + pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID); + pci_config_set_device_id(config, pci_device_id); + pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); + pci_set_byte(&config[PCI_INTERRUPT_PIN], 1); + + qxl->rom_size = qxl_rom_size(); + qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size); + init_qxl_rom(qxl); + init_qxl_ram(qxl); + + if (qxl->vram_size < 16 * 1024 * 1024) { + qxl->vram_size = 16 * 1024 * 1024; + } + if (qxl->revision == 1) { + qxl->vram_size = 4096; + } + qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); + qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size); + + io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); + if (qxl->revision == 1) { + io_size = 8; + } + + pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX, + io_size, PCI_BASE_ADDRESS_SPACE_IO, qxl_map); + + pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX, + qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY, + qxl_map); + + pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX, + qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY, + qxl_map); + + pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size, + PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map); + + qxl->ssd.qxl.base.sif = &qxl_interface.base; + qxl->ssd.qxl.id = qxl->id; + qemu_spice_add_interface(&qxl->ssd.qxl.base); + qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl); + + init_pipe_signaling(qxl); + qxl_reset_state(qxl); + + return 0; +} + +static int qxl_init_primary(PCIDevice *dev) +{ + PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); + VGACommonState *vga = &qxl->vga; + ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); + + qxl->id = 0; + + if (ram_size < 32 * 1024 * 1024) { + ram_size = 32 * 1024 * 1024; + } + vga_common_init(vga, ram_size); + vga_init(vga); + register_ioport_write(0x3c0, 16, 1, qxl_vga_ioport_write, vga); + register_ioport_write(0x3b4, 2, 1, qxl_vga_ioport_write, vga); + register_ioport_write(0x3d4, 2, 1, qxl_vga_ioport_write, vga); + register_ioport_write(0x3ba, 1, 1, qxl_vga_ioport_write, vga); + register_ioport_write(0x3da, 1, 1, qxl_vga_ioport_write, vga); + + vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, + qxl_hw_screen_dump, qxl_hw_text_update, qxl); + qxl->ssd.ds = vga->ds; + qxl->ssd.bufsize = (16 * 1024 * 1024); + qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize); + + qxl0 = qxl; + register_displaychangelistener(vga->ds, &display_listener); + + pci_config_set_class(dev->config, PCI_CLASS_DISPLAY_VGA); + return qxl_init_common(qxl); +} + +static int qxl_init_secondary(PCIDevice *dev) +{ + static int device_id = 1; + PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); + ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); + + qxl->id = device_id++; + + if (ram_size < 16 * 1024 * 1024) { + ram_size = 16 * 1024 * 1024; + } + qxl->vga.vram_size = ram_size; + qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram", + qxl->vga.vram_size); + qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset); + + pci_config_set_class(dev->config, PCI_CLASS_DISPLAY_OTHER); + return qxl_init_common(qxl); +} + +static void qxl_pre_save(void *opaque) +{ + PCIQXLDevice* d = opaque; + uint8_t *ram_start = d->vga.vram_ptr; + + dprint(d, 1, "%s:\n", __FUNCTION__); + if (d->last_release == NULL) { + d->last_release_offset = 0; + } else { + d->last_release_offset = (uint8_t *)d->last_release - ram_start; + } + assert(d->last_release_offset < d->vga.vram_size); +} + +static int qxl_pre_load(void *opaque) +{ + PCIQXLDevice* d = opaque; + + dprint(d, 1, "%s: start\n", __FUNCTION__); + qxl_hard_reset(d, 1); + qxl_exit_vga_mode(d); + dprint(d, 1, "%s: done\n", __FUNCTION__); + return 0; +} + +static int qxl_post_load(void *opaque, int version) +{ + PCIQXLDevice* d = opaque; + uint8_t *ram_start = d->vga.vram_ptr; + QXLCommandExt *cmds; + int in, out, i, newmode; + + dprint(d, 1, "%s: start\n", __FUNCTION__); + + assert(d->last_release_offset < d->vga.vram_size); + if (d->last_release_offset == 0) { + d->last_release = NULL; + } else { + d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset); + } + + d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset); + + dprint(d, 1, "%s: restore mode\n", __FUNCTION__); + newmode = d->mode; + d->mode = QXL_MODE_UNDEFINED; + switch (newmode) { + case QXL_MODE_UNDEFINED: + break; + case QXL_MODE_VGA: + qxl_enter_vga_mode(d); + break; + case QXL_MODE_NATIVE: + for (i = 0; i < NUM_MEMSLOTS; i++) { + if (!d->guest_slots[i].active) { + continue; + } + qxl_add_memslot(d, i, 0); + } + qxl_create_guest_primary(d, 1); + + /* replay surface-create and cursor-set commands */ + cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); + for (in = 0, out = 0; in < NUM_SURFACES; in++) { + if (d->guest_surfaces.cmds[in] == 0) { + continue; + } + cmds[out].cmd.data = d->guest_surfaces.cmds[in]; + cmds[out].cmd.type = QXL_CMD_SURFACE; + cmds[out].group_id = MEMSLOT_GROUP_GUEST; + out++; + } + cmds[out].cmd.data = d->guest_cursor; + cmds[out].cmd.type = QXL_CMD_CURSOR; + cmds[out].group_id = MEMSLOT_GROUP_GUEST; + out++; + d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out); + qemu_free(cmds); + + break; + case QXL_MODE_COMPAT: + qxl_set_mode(d, d->shadow_rom.mode, 1); + break; + } + dprint(d, 1, "%s: done\n", __FUNCTION__); + + /* spice 0.4 compatibility -- accept but ignore */ + qemu_free(d->worker_data); + d->worker_data = NULL; + d->worker_data_size = 0; + + return 0; +} + +#define QXL_SAVE_VERSION 20 + +static bool qxl_test_worker_data(void *opaque, int version_id) +{ + PCIQXLDevice* d = opaque; + + if (d->revision != 1) { + return false; + } + if (!d->worker_data_size) { + return false; + } + if (!d->worker_data) { + d->worker_data = qemu_malloc(d->worker_data_size); + } + return true; +} + +static bool qxl_test_spice04(void *opaque, int version_id) +{ + PCIQXLDevice* d = opaque; + return d->revision == 1; +} + +static bool qxl_test_spice06(void *opaque) +{ + PCIQXLDevice* d = opaque; + return d->revision > 1; +} + +static VMStateDescription qxl_memslot = { + .name = "qxl-memslot", + .version_id = QXL_SAVE_VERSION, + .minimum_version_id = QXL_SAVE_VERSION, + .fields = (VMStateField[]) { + VMSTATE_UINT64(slot.mem_start, struct guest_slots), + VMSTATE_UINT64(slot.mem_end, struct guest_slots), + VMSTATE_UINT32(active, struct guest_slots), + VMSTATE_END_OF_LIST() + } +}; + +static VMStateDescription qxl_surface = { + .name = "qxl-surface", + .version_id = QXL_SAVE_VERSION, + .minimum_version_id = QXL_SAVE_VERSION, + .fields = (VMStateField[]) { + VMSTATE_UINT32(width, QXLSurfaceCreate), + VMSTATE_UINT32(height, QXLSurfaceCreate), + VMSTATE_INT32(stride, QXLSurfaceCreate), + VMSTATE_UINT32(format, QXLSurfaceCreate), + VMSTATE_UINT32(position, QXLSurfaceCreate), + VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate), + VMSTATE_UINT32(flags, QXLSurfaceCreate), + VMSTATE_UINT32(type, QXLSurfaceCreate), + VMSTATE_UINT64(mem, QXLSurfaceCreate), + VMSTATE_END_OF_LIST() + } +}; + +static VMStateDescription qxl_vmstate_spice06 = { + .name = "qxl/spice06", + .version_id = QXL_SAVE_VERSION, + .minimum_version_id = QXL_SAVE_VERSION, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice), + VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0, + qxl_memslot, struct guest_slots), + VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0, + qxl_surface, QXLSurfaceCreate), + VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice), + VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0, + vmstate_info_uint64, uint64_t), + VMSTATE_UINT64(guest_cursor, PCIQXLDevice), + VMSTATE_END_OF_LIST() + }, +}; + +static VMStateDescription qxl_vmstate = { + .name = "qxl", + .version_id = QXL_SAVE_VERSION, + .minimum_version_id = QXL_SAVE_VERSION, + .pre_save = qxl_pre_save, + .pre_load = qxl_pre_load, + .post_load = qxl_post_load, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(pci, PCIQXLDevice), + VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState), + VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice), + VMSTATE_UINT32(num_free_res, PCIQXLDevice), + VMSTATE_UINT32(last_release_offset, PCIQXLDevice), + VMSTATE_UINT32(mode, PCIQXLDevice), + VMSTATE_UINT32(ssd.unique, PCIQXLDevice), + + /* spice 0.4 sends/expects them */ + VMSTATE_VBUFFER_UINT32(vga.vram_ptr, PCIQXLDevice, 0, qxl_test_spice04, 0, + vga.vram_size), + VMSTATE_UINT32_TEST(worker_data_size, PCIQXLDevice, qxl_test_spice04), + VMSTATE_VBUFFER_UINT32(worker_data, PCIQXLDevice, 0, qxl_test_worker_data, 0, + worker_data_size), + + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + /* additional spice 0.6 state */ + .vmsd = &qxl_vmstate_spice06, + .needed = qxl_test_spice06, + },{ + /* end of list */ + }, + }, +}; + +static PCIDeviceInfo qxl_info_primary = { + .qdev.name = "qxl-vga", + .qdev.desc = "Spice QXL GPU (primary, vga compatible)", + .qdev.size = sizeof(PCIQXLDevice), + .qdev.reset = qxl_reset_handler, + .qdev.vmsd = &qxl_vmstate, + .init = qxl_init_primary, + .config_write = qxl_write_config, + .romfile = "vgabios-qxl.bin", + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024), + DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024), + DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2), + DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static PCIDeviceInfo qxl_info_secondary = { + .qdev.name = "qxl", + .qdev.desc = "Spice QXL GPU (secondary)", + .qdev.size = sizeof(PCIQXLDevice), + .qdev.reset = qxl_reset_handler, + .qdev.vmsd = &qxl_vmstate, + .init = qxl_init_secondary, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024), + DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024), + DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2), + DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void qxl_register(void) +{ + pci_qdev_register(&qxl_info_primary); + pci_qdev_register(&qxl_info_secondary); +} + +device_init(qxl_register); diff --git a/hw/qxl.h b/hw/qxl.h new file mode 100644 index 0000000000..98e11ce8d1 --- /dev/null +++ b/hw/qxl.h @@ -0,0 +1,112 @@ +#include "qemu-common.h" + +#include "console.h" +#include "hw.h" +#include "pci.h" +#include "vga_int.h" + +#include "ui/qemu-spice.h" +#include "ui/spice-display.h" + +enum qxl_mode { + QXL_MODE_UNDEFINED, + QXL_MODE_VGA, + QXL_MODE_COMPAT, /* spice 0.4.x */ + QXL_MODE_NATIVE, +}; + +typedef struct PCIQXLDevice { + PCIDevice pci; + SimpleSpiceDisplay ssd; + int id; + uint32_t debug; + uint32_t guestdebug; + uint32_t cmdlog; + enum qxl_mode mode; + uint32_t cmdflags; + int generation; + uint32_t revision; + + int32_t num_memslots; + int32_t num_surfaces; + + struct guest_slots { + QXLMemSlot slot; + void *ptr; + uint64_t size; + uint64_t delta; + uint32_t active; + } guest_slots[NUM_MEMSLOTS]; + + struct guest_primary { + QXLSurfaceCreate surface; + uint32_t commands; + uint32_t resized; + int32_t stride; + uint32_t bits_pp; + uint32_t bytes_pp; + uint8_t *data, *flipped; + } guest_primary; + + struct surfaces { + QXLPHYSICAL cmds[NUM_SURFACES]; + uint32_t count; + uint32_t max; + } guest_surfaces; + QXLPHYSICAL guest_cursor; + + /* thread signaling */ + pthread_t main; + int pipe[2]; + + /* ram pci bar */ + QXLRam *ram; + VGACommonState vga; + uint32_t num_free_res; + QXLReleaseInfo *last_release; + uint32_t last_release_offset; + uint32_t oom_running; + + /* rom pci bar */ + QXLRom shadow_rom; + QXLRom *rom; + QXLModes *modes; + uint32_t rom_size; + uint64_t rom_offset; + + /* vram pci bar */ + uint32_t vram_size; + uint64_t vram_offset; + + /* io bar */ + uint32_t io_base; + + /* spice 0.4 loadvm compatibility */ + void *worker_data; + uint32_t worker_data_size; +} PCIQXLDevice; + +#define PANIC_ON(x) if ((x)) { \ + printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \ + exit(-1); \ +} + +#define dprint(_qxl, _level, _fmt, ...) \ + do { \ + if (_qxl->debug >= _level) { \ + fprintf(stderr, "qxl-%d: ", _qxl->id); \ + fprintf(stderr, _fmt, ## __VA_ARGS__); \ + } \ + } while (0) + +/* qxl.c */ +void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); + +/* qxl-logger.c */ +void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); +void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); + +/* qxl-render.c */ +void qxl_render_resize(PCIQXLDevice *qxl); +void qxl_render_update(PCIQXLDevice *qxl); +void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); diff --git a/hw/vga_int.h b/hw/vga_int.h index bc1327fbf6..1067f2cc5f 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -106,7 +106,7 @@ typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s); typedef struct VGACommonState { uint8_t *vram_ptr; ram_addr_t vram_offset; - unsigned int vram_size; + uint32_t vram_size; uint32_t lfb_addr; uint32_t lfb_end; uint32_t map_addr; diff --git a/qemu-options.hx b/qemu-options.hx index 4d99a58fc5..fd732104e1 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -751,7 +751,7 @@ Rotate graphical output 90 deg left (only PXA LCD). ETEXI DEF("vga", HAS_ARG, QEMU_OPTION_vga, - "-vga [std|cirrus|vmware|xenfb|none]\n" + "-vga [std|cirrus|vmware|qxl|xenfb|none]\n" " select video card type\n", QEMU_ARCH_ALL) STEXI @item -vga @var{type} @@ -772,6 +772,10 @@ this option. VMWare SVGA-II compatible adapter. Use it if you have sufficiently recent XFree86/XOrg server or Windows guest with a driver for this card. +@item qxl +QXL paravirtual graphic card. It is VGA compatible (including VESA +2.0 VBE support). Works best with qxl guest drivers installed though. +Recommended choice when using the spice protocol. @item none Disable VGA card. @end table diff --git a/sysemu.h b/sysemu.h index b81a70ec3e..d9b445ba7b 100644 --- a/sysemu.h +++ b/sysemu.h @@ -102,7 +102,7 @@ extern int incoming_expected; extern int bios_size; typedef enum { - VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB + VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL, } VGAInterfaceType; extern int vga_interface_type; @@ -110,6 +110,7 @@ extern int vga_interface_type; #define std_vga_enabled (vga_interface_type == VGA_STD) #define xenfb_enabled (vga_interface_type == VGA_XENFB) #define vmsvga_enabled (vga_interface_type == VGA_VMWARE) +#define qxl_enabled (vga_interface_type == VGA_QXL) extern int graphic_width; extern int graphic_height; diff --git a/ui/spice-core.c b/ui/spice-core.c index d13bdc269d..b7fa0315bd 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -370,6 +370,21 @@ void qemu_spice_init(void) int qemu_spice_add_interface(SpiceBaseInstance *sin) { + if (!spice_server) { + if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) { + fprintf(stderr, "Oops: spice configured but not active\n"); + exit(1); + } + /* + * Create a spice server instance. + * It does *not* listen on the network. + * It handles QXL local rendering only. + * + * With a command line like '-vnc :0 -vga qxl' you'll end up here. + */ + spice_server = spice_server_new(); + spice_server_init(spice_server, &core_interface); + } return spice_server_add_interface(spice_server, sin); } diff --git a/vl.c b/vl.c index 2cd263eda4..e3f79e0d8d 100644 --- a/vl.c +++ b/vl.c @@ -1411,6 +1411,8 @@ static void select_vgahw (const char *p) vga_interface_type = VGA_VMWARE; } else if (strstart(p, "xenfb", &opts)) { vga_interface_type = VGA_XENFB; + } else if (strstart(p, "qxl", &opts)) { + vga_interface_type = VGA_QXL; } else if (!strstart(p, "none", &opts)) { invalid_vga: fprintf(stderr, "Unknown vga type: %s\n", p); @@ -2945,7 +2947,7 @@ int main(int argc, char **argv, char **envp) } } #ifdef CONFIG_SPICE - if (using_spice) { + if (using_spice && !qxl_enabled) { qemu_spice_display_init(ds); } #endif -- cgit v1.2.3 From 6f8c63fbd7edc0b41c09f8f8e2d41a3a65464a43 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 11 Oct 2010 18:03:51 +0200 Subject: spice: connection events. This patch adds support for connection events to spice. The events are quite simliar to the vnc events. Unlike vnc spice uses multiple tcp channels though. qemu will report every single tcp connection (aka spice channel). If you want track spice sessions only you can filter for the main channel (channel-type == 1). Signed-off-by: Gerd Hoffmann --- QMP/qmp-events.txt | 64 ++++++++++++++++++++++++++++++++++++++++++++++ monitor.c | 10 ++++++++ monitor.h | 3 +++ ui/spice-core.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+) diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index aa2021082f..0ce5d4efe2 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -182,6 +182,70 @@ Example: "host": "127.0.0.1", "sasl_username": "luiz" } }, "timestamp": { "seconds": 1263475302, "microseconds": 150772 } } +SPICE_CONNECTED, SPICE_DISCONNECTED +----------------------------------- + +Emitted when a SPICE client connects or disconnects. + +Data: + +- "server": Server information (json-object) + - "host": IP address (json-string) + - "port": port number (json-string) + - "family": address family (json-string, "ipv4" or "ipv6") +- "client": Client information (json-object) + - "host": IP address (json-string) + - "port": port number (json-string) + - "family": address family (json-string, "ipv4" or "ipv6") + +Example: + +{ "timestamp": {"seconds": 1290688046, "microseconds": 388707}, + "event": "SPICE_CONNECTED", + "data": { + "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"}, + "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"} +}} + + +SPICE_INITIALIZED +----------------- + +Emitted after initial handshake and authentication takes place (if any) +and the SPICE channel is up'n'running + +Data: + +- "server": Server information (json-object) + - "host": IP address (json-string) + - "port": port number (json-string) + - "family": address family (json-string, "ipv4" or "ipv6") + - "auth": authentication method (json-string, optional) +- "client": Client information (json-object) + - "host": IP address (json-string) + - "port": port number (json-string) + - "family": address family (json-string, "ipv4" or "ipv6") + - "connection-id": spice connection id. All channels with the same id + belong to the same spice session (json-int) + - "channel-type": channel type. "1" is the main control channel, filter for + this one if you want track spice sessions only (json-int) + - "channel-id": channel id. Usually "0", might be different needed when + multiple channels of the same type exist, such as multiple + display channels in a multihead setup (json-int) + - "tls": whevener the channel is encrypted (json-bool) + +Example: + +{ "timestamp": {"seconds": 1290688046, "microseconds": 417172}, + "event": "SPICE_INITIALIZED", + "data": {"server": {"auth": "spice", "port": "5921", + "family": "ipv4", "host": "127.0.0.1"}, + "client": {"port": "49004", "family": "ipv4", "channel-type": 3, + "connection-id": 1804289383, "host": "127.0.0.1", + "channel-id": 0, "tls": true} +}} + + WATCHDOG -------- diff --git a/monitor.c b/monitor.c index ec31eac8c1..f04dda527a 100644 --- a/monitor.c +++ b/monitor.c @@ -59,6 +59,7 @@ #ifdef CONFIG_SIMPLE_TRACE #include "trace.h" #endif +#include "ui/qemu-spice.h" //#define DEBUG //#define DEBUG_COMPLETION @@ -459,6 +460,15 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) case QEVENT_WATCHDOG: event_name = "WATCHDOG"; break; + case QEVENT_SPICE_CONNECTED: + event_name = "SPICE_CONNECTED"; + break; + case QEVENT_SPICE_INITIALIZED: + event_name = "SPICE_INITIALIZED"; + break; + case QEVENT_SPICE_DISCONNECTED: + event_name = "SPICE_DISCONNECTED"; + break; default: abort(); break; diff --git a/monitor.h b/monitor.h index 2d36bba87f..4f2d328db5 100644 --- a/monitor.h +++ b/monitor.h @@ -32,6 +32,9 @@ typedef enum MonitorEvent { QEVENT_BLOCK_IO_ERROR, QEVENT_RTC_CHANGE, QEVENT_WATCHDOG, + QEVENT_SPICE_CONNECTED, + QEVENT_SPICE_INITIALIZED, + QEVENT_SPICE_DISCONNECTED, QEVENT_MAX, } MonitorEvent; diff --git a/ui/spice-core.c b/ui/spice-core.c index b7fa0315bd..93461c6d06 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -18,16 +18,24 @@ #include #include +#include + #include "qemu-common.h" #include "qemu-spice.h" #include "qemu-timer.h" #include "qemu-queue.h" #include "qemu-x509.h" +#include "qemu_socket.h" +#include "qint.h" +#include "qbool.h" +#include "qstring.h" +#include "qjson.h" #include "monitor.h" /* core bits */ static SpiceServer *spice_server; +static const char *auth = "spice"; int using_spice = 0; struct SpiceTimer { @@ -121,6 +129,68 @@ static void watch_remove(SpiceWatch *watch) qemu_free(watch); } +#if SPICE_INTERFACE_CORE_MINOR >= 3 + +static void add_addr_info(QDict *dict, struct sockaddr *addr, int len) +{ + char host[NI_MAXHOST], port[NI_MAXSERV]; + const char *family; + + getnameinfo(addr, len, host, sizeof(host), port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV); + family = inet_strfamily(addr->sa_family); + + qdict_put(dict, "host", qstring_from_str(host)); + qdict_put(dict, "port", qstring_from_str(port)); + qdict_put(dict, "family", qstring_from_str(family)); +} + +static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info) +{ + int tls = info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS; + + qdict_put(dict, "connection-id", qint_from_int(info->connection_id)); + qdict_put(dict, "channel-type", qint_from_int(info->type)); + qdict_put(dict, "channel-id", qint_from_int(info->id)); + qdict_put(dict, "tls", qbool_from_int(tls)); +} + +static void channel_event(int event, SpiceChannelEventInfo *info) +{ + static const int qevent[] = { + [ SPICE_CHANNEL_EVENT_CONNECTED ] = QEVENT_SPICE_CONNECTED, + [ SPICE_CHANNEL_EVENT_INITIALIZED ] = QEVENT_SPICE_INITIALIZED, + [ SPICE_CHANNEL_EVENT_DISCONNECTED ] = QEVENT_SPICE_DISCONNECTED, + }; + QDict *server, *client; + QObject *data; + + client = qdict_new(); + add_addr_info(client, &info->paddr, info->plen); + + server = qdict_new(); + add_addr_info(server, &info->laddr, info->llen); + + if (event == SPICE_CHANNEL_EVENT_INITIALIZED) { + qdict_put(server, "auth", qstring_from_str(auth)); + add_channel_info(client, info); + } + + data = qobject_from_jsonf("{ 'client': %p, 'server': %p }", + QOBJECT(client), QOBJECT(server)); + monitor_protocol_event(qevent[event], data); + qobject_decref(data); +} + +#else /* SPICE_INTERFACE_CORE_MINOR >= 3 */ + +static QList *channel_list_get(void) +{ + return NULL; +} + +#endif /* SPICE_INTERFACE_CORE_MINOR >= 3 */ + static SpiceCoreInterface core_interface = { .base.type = SPICE_INTERFACE_CORE, .base.description = "qemu core services", @@ -135,6 +205,10 @@ static SpiceCoreInterface core_interface = { .watch_add = watch_add, .watch_update_mask = watch_update_mask, .watch_remove = watch_remove, + +#if SPICE_INTERFACE_CORE_MINOR >= 3 + .channel_event = channel_event, +#endif }; /* config string parsing */ @@ -316,6 +390,7 @@ void qemu_spice_init(void) spice_server_set_ticket(spice_server, password, 0, 0, 0); } if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) { + auth = "none"; spice_server_set_noauth(spice_server); } -- cgit v1.2.3 From cb42a870c3f5b38911b1428cb785dd702bc47d0f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 30 Nov 2010 11:02:51 +0100 Subject: spice: add qmp 'query-spice' and hmp 'info spice' commands. The patch adds a 'query-spice' monitor command which returns informations about the spice server configuration and also a list of channel connections. Signed-off-by: Gerd Hoffmann --- monitor.c | 20 +++++++++ qmp-commands.hx | 70 +++++++++++++++++++++++++++++ ui/qemu-spice.h | 3 ++ ui/spice-core.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 229 insertions(+) diff --git a/monitor.c b/monitor.c index f04dda527a..1047ceea97 100644 --- a/monitor.c +++ b/monitor.c @@ -2581,6 +2581,16 @@ static const mon_cmd_t info_cmds[] = { .user_print = do_info_vnc_print, .mhandler.info_new = do_info_vnc, }, +#if defined(CONFIG_SPICE) + { + .name = "spice", + .args_type = "", + .params = "", + .help = "show the spice server status", + .user_print = do_info_spice_print, + .mhandler.info_new = do_info_spice, + }, +#endif { .name = "name", .args_type = "", @@ -2768,6 +2778,16 @@ static const mon_cmd_t qmp_query_cmds[] = { .user_print = do_info_vnc_print, .mhandler.info_new = do_info_vnc, }, +#if defined(CONFIG_SPICE) + { + .name = "spice", + .args_type = "", + .params = "", + .help = "show the spice server status", + .user_print = do_info_spice_print, + .mhandler.info_new = do_info_spice, + }, +#endif { .name = "name", .args_type = "", diff --git a/qmp-commands.hx b/qmp-commands.hx index e5f157fe10..b4e601751f 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1438,6 +1438,76 @@ Example: EQMP +SQMP +query-spice +----------- + +Show SPICE server information. + +Return a json-object with server information. Connected clients are returned +as a json-array of json-objects. + +The main json-object contains the following: + +- "enabled": true or false (json-bool) +- "host": server's IP address (json-string) +- "port": server's port number (json-int, optional) +- "tls-port": server's port number (json-int, optional) +- "auth": authentication method (json-string) + - Possible values: "none", "spice" +- "channels": a json-array of all active channels clients + +Channels are described by a json-object, each one contain the following: + +- "host": client's IP address (json-string) +- "family": address family (json-string) + - Possible values: "ipv4", "ipv6", "unix", "unknown" +- "port": client's port number (json-string) +- "connection-id": spice connection id. All channels with the same id + belong to the same spice session (json-int) +- "channel-type": channel type. "1" is the main control channel, filter for + this one if you want track spice sessions only (json-int) +- "channel-id": channel id. Usually "0", might be different needed when + multiple channels of the same type exist, such as multiple + display channels in a multihead setup (json-int) +- "tls": whevener the channel is encrypted (json-bool) + +Example: + +-> { "execute": "query-spice" } +<- { + "return": { + "enabled": true, + "auth": "spice", + "port": 5920, + "tls-port": 5921, + "host": "0.0.0.0", + "channels": [ + { + "port": "54924", + "family": "ipv4", + "channel-type": 1, + "connection-id": 1804289383, + "host": "127.0.0.1", + "channel-id": 0, + "tls": true + }, + { + "port": "36710", + "family": "ipv4", + "channel-type": 4, + "connection-id": 1804289383, + "host": "127.0.0.1", + "channel-id": 0, + "tls": false + }, + [ ... more channels follow ... ] + ] + } + } + +EQMP + SQMP query-name ---------- diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 0e3ad9b8c0..8b23ac9d04 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -33,6 +33,9 @@ void qemu_spice_audio_init(void); void qemu_spice_display_init(DisplayState *ds); int qemu_spice_add_interface(SpiceBaseInstance *sin); +void do_info_spice_print(Monitor *mon, const QObject *data); +void do_info_spice(Monitor *mon, QObject **ret_data); + #else /* CONFIG_SPICE */ #define using_spice 0 diff --git a/ui/spice-core.c b/ui/spice-core.c index 93461c6d06..d29d20359d 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -131,6 +131,36 @@ static void watch_remove(SpiceWatch *watch) #if SPICE_INTERFACE_CORE_MINOR >= 3 +typedef struct ChannelList ChannelList; +struct ChannelList { + SpiceChannelEventInfo *info; + QTAILQ_ENTRY(ChannelList) link; +}; +static QTAILQ_HEAD(, ChannelList) channel_list = QTAILQ_HEAD_INITIALIZER(channel_list); + +static void channel_list_add(SpiceChannelEventInfo *info) +{ + ChannelList *item; + + item = qemu_mallocz(sizeof(*item)); + item->info = info; + QTAILQ_INSERT_TAIL(&channel_list, item, link); +} + +static void channel_list_del(SpiceChannelEventInfo *info) +{ + ChannelList *item; + + QTAILQ_FOREACH(item, &channel_list, link) { + if (item->info != info) { + continue; + } + QTAILQ_REMOVE(&channel_list, item, link); + qemu_free(item); + return; + } +} + static void add_addr_info(QDict *dict, struct sockaddr *addr, int len) { char host[NI_MAXHOST], port[NI_MAXSERV]; @@ -155,6 +185,22 @@ static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info) qdict_put(dict, "tls", qbool_from_int(tls)); } +static QList *channel_list_get(void) +{ + ChannelList *item; + QList *list; + QDict *dict; + + list = qlist_new(); + QTAILQ_FOREACH(item, &channel_list, link) { + dict = qdict_new(); + add_addr_info(dict, &item->info->paddr, item->info->plen); + add_channel_info(dict, item->info); + qlist_append(list, dict); + } + return list; +} + static void channel_event(int event, SpiceChannelEventInfo *info) { static const int qevent[] = { @@ -174,6 +220,10 @@ static void channel_event(int event, SpiceChannelEventInfo *info) if (event == SPICE_CHANNEL_EVENT_INITIALIZED) { qdict_put(server, "auth", qstring_from_str(auth)); add_channel_info(client, info); + channel_list_add(info); + } + if (event == SPICE_CHANNEL_EVENT_DISCONNECTED) { + channel_list_del(info); } data = qobject_from_jsonf("{ 'client': %p, 'server': %p }", @@ -278,6 +328,92 @@ static const char *wan_compression_names[] = { /* functions for the rest of qemu */ +static void info_spice_iter(QObject *obj, void *opaque) +{ + QDict *client; + Monitor *mon = opaque; + + client = qobject_to_qdict(obj); + monitor_printf(mon, "Channel:\n"); + monitor_printf(mon, " address: %s:%s%s\n", + qdict_get_str(client, "host"), + qdict_get_str(client, "port"), + qdict_get_bool(client, "tls") ? " [tls]" : ""); + monitor_printf(mon, " session: %" PRId64 "\n", + qdict_get_int(client, "connection-id")); + monitor_printf(mon, " channel: %d:%d\n", + (int)qdict_get_int(client, "channel-type"), + (int)qdict_get_int(client, "channel-id")); +} + +void do_info_spice_print(Monitor *mon, const QObject *data) +{ + QDict *server; + QList *channels; + const char *host; + int port; + + server = qobject_to_qdict(data); + if (qdict_get_bool(server, "enabled") == 0) { + monitor_printf(mon, "Server: disabled\n"); + return; + } + + monitor_printf(mon, "Server:\n"); + host = qdict_get_str(server, "host"); + port = qdict_get_try_int(server, "port", -1); + if (port != -1) { + monitor_printf(mon, " address: %s:%d\n", host, port); + } + port = qdict_get_try_int(server, "tls-port", -1); + if (port != -1) { + monitor_printf(mon, " address: %s:%d [tls]\n", host, port); + } + monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth")); + + channels = qdict_get_qlist(server, "channels"); + if (qlist_empty(channels)) { + monitor_printf(mon, "Channels: none\n"); + } else { + qlist_iter(channels, info_spice_iter, mon); + } +} + +void do_info_spice(Monitor *mon, QObject **ret_data) +{ + QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); + QDict *server; + QList *clist; + const char *addr; + int port, tls_port; + + if (!spice_server) { + *ret_data = qobject_from_jsonf("{ 'enabled': false }"); + return; + } + + addr = qemu_opt_get(opts, "addr"); + port = qemu_opt_get_number(opts, "port", 0); + tls_port = qemu_opt_get_number(opts, "tls-port", 0); + clist = channel_list_get(); + + server = qdict_new(); + qdict_put(server, "enabled", qbool_from_int(true)); + qdict_put(server, "auth", qstring_from_str(auth)); + qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0")); + if (port) { + qdict_put(server, "port", qint_from_int(port)); + } + if (tls_port) { + qdict_put(server, "tls-port", qint_from_int(tls_port)); + } + if (clist) { + qdict_put(server, "channels", clist); + } + + *ret_data = QOBJECT(server); +} + static int add_channel(const char *name, const char *value, void *opaque) { int security = 0; -- cgit v1.2.3 From 6bffdf0f83263bad1dd2187c533758d7cb6f5bcf Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 7 Oct 2010 11:50:24 +0200 Subject: vnc: auth reject cleanup protocol_client_auth_vnc() has two places where the auth can fail, with identical code sending the reject message to the client. Move the common code to the end of the function and make both error paths jump there. No functional change. Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 864342e84d..da70757440 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2085,15 +2085,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) if (!vs->vd->password || !vs->vd->password[0]) { VNC_DEBUG("No password configured on server"); - vnc_write_u32(vs, 1); /* Reject auth */ - if (vs->minor >= 8) { - static const char err[] = "Authentication failed"; - vnc_write_u32(vs, sizeof(err)); - vnc_write(vs, err, sizeof(err)); - } - vnc_flush(vs); - vnc_client_error(vs); - return 0; + goto reject; } memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE); @@ -2109,14 +2101,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) /* Compare expected vs actual challenge response */ if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) { VNC_DEBUG("Client challenge reponse did not match\n"); - vnc_write_u32(vs, 1); /* Reject auth */ - if (vs->minor >= 8) { - static const char err[] = "Authentication failed"; - vnc_write_u32(vs, sizeof(err)); - vnc_write(vs, err, sizeof(err)); - } - vnc_flush(vs); - vnc_client_error(vs); + goto reject; } else { VNC_DEBUG("Accepting VNC challenge response\n"); vnc_write_u32(vs, 0); /* Accept auth */ @@ -2125,6 +2110,17 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) start_client_init(vs); } return 0; + +reject: + vnc_write_u32(vs, 1); /* Reject auth */ + if (vs->minor >= 8) { + static const char err[] = "Authentication failed"; + vnc_write_u32(vs, sizeof(err)); + vnc_write(vs, err, sizeof(err)); + } + vnc_flush(vs); + vnc_client_error(vs); + return 0; } void start_auth_vnc(VncState *vs) -- cgit v1.2.3 From 3c9405a0f7d76602415b3cbe8d52d7714b6ce5af Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 7 Oct 2010 11:50:45 +0200 Subject: vnc: support password expire This patch adds support for expiring passwords to vnc. It adds a new vnc_display_pw_expire() function which specifies the time when the password will expire. Signed-off-by: Gerd Hoffmann --- console.h | 1 + qemu-common.h | 3 +++ ui/vnc.c | 14 ++++++++++++++ ui/vnc.h | 1 + 4 files changed, 19 insertions(+) diff --git a/console.h b/console.h index aafb0312c5..b2fc908549 100644 --- a/console.h +++ b/console.h @@ -369,6 +369,7 @@ void vnc_display_init(DisplayState *ds); void vnc_display_close(DisplayState *ds); int vnc_display_open(DisplayState *ds, const char *display); int vnc_display_password(DisplayState *ds, const char *password); +int vnc_display_pw_expire(DisplayState *ds, time_t expires); void do_info_vnc_print(Monitor *mon, const QObject *data); void do_info_vnc(Monitor *mon, QObject **ret_data); char *vnc_display_local_addr(DisplayState *ds); diff --git a/qemu-common.h b/qemu-common.h index de82c2ea13..188b05f98c 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -50,6 +50,9 @@ typedef struct DeviceState DeviceState; #if !defined(ENOTSUP) #define ENOTSUP 4096 #endif +#ifndef TIME_MAX +#define TIME_MAX LONG_MAX +#endif #ifndef CONFIG_IOVEC #define CONFIG_IOVEC diff --git a/ui/vnc.c b/ui/vnc.c index da70757440..495d6d6ef1 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2082,11 +2082,16 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) unsigned char response[VNC_AUTH_CHALLENGE_SIZE]; int i, j, pwlen; unsigned char key[8]; + time_t now = time(NULL); if (!vs->vd->password || !vs->vd->password[0]) { VNC_DEBUG("No password configured on server"); goto reject; } + if (vs->vd->expires < now) { + VNC_DEBUG("Password is expired"); + goto reject; + } memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE); @@ -2432,6 +2437,7 @@ void vnc_display_init(DisplayState *ds) vs->ds = ds; QTAILQ_INIT(&vs->clients); + vs->expires = TIME_MAX; if (keyboard_layout) vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); @@ -2503,6 +2509,14 @@ int vnc_display_password(DisplayState *ds, const char *password) return 0; } +int vnc_display_pw_expire(DisplayState *ds, time_t expires) +{ + VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; + + vs->expires = expires; + return 0; +} + char *vnc_display_local_addr(DisplayState *ds) { VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; diff --git a/ui/vnc.h b/ui/vnc.h index 9619b247fb..4f895becb9 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -120,6 +120,7 @@ struct VncDisplay char *display; char *password; + time_t expires; int auth; bool lossy; #ifdef CONFIG_VNC_TLS -- cgit v1.2.3 From 7572150c189c6553c2448334116ab717680de66d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 7 Oct 2010 12:22:54 +0200 Subject: vnc/spice: add set_passwd monitor command. This patch adds new set_password and expire_password monitor commands which allows to change and expire the password for spice and vnc connections. See the doc update patch chunk for details. Signed-off-by: Gerd Hoffmann --- hmp-commands.hx | 54 ++++++++++++++++++++++++++++++ monitor.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 57 ++++++++++++++++++++++++++++++++ ui/qemu-spice.h | 5 +++ ui/spice-core.c | 35 ++++++++++++++++++++ 5 files changed, 251 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index 23024ba6f2..f0ae3b9fd8 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1132,6 +1132,60 @@ STEXI @item block_passwd @var{device} @var{password} @findex block_passwd Set the encrypted device @var{device} password to @var{password} +ETEXI + + { + .name = "set_password", + .args_type = "protocol:s,password:s,connected:s?", + .params = "protocol password action-if-connected", + .help = "set spice/vnc password", + .user_print = monitor_user_noop, + .mhandler.cmd_new = set_password, + }, + +STEXI +@item set_password [ vnc | spice ] password [ action-if-connected ] +@findex set_password + +Change spice/vnc password. Use zero to make the password stay valid +forever. @var{action-if-connected} specifies what should happen in +case a connection is established: @var{fail} makes the password change +fail. @var{disconnect} changes the password and disconnects the +client. @var{keep} changes the password and keeps the connection up. +@var{keep} is the default. +ETEXI + + { + .name = "expire_password", + .args_type = "protocol:s,time:s", + .params = "protocol time", + .help = "set spice/vnc password expire-time", + .user_print = monitor_user_noop, + .mhandler.cmd_new = expire_password, + }, + +STEXI +@item expire_password [ vnc | spice ] expire-time +@findex expire_password + +Specify when a password for spice/vnc becomes +invalid. @var{expire-time} accepts: + +@table @var +@item now +Invalidate password instantly. + +@item never +Password stays valid forever. + +@item +nsec +Password stays valid for @var{nsec} seconds starting now. + +@item nsec +Password is invalidated at the given time. @var{nsec} are the seconds +passed since 1970, i.e. unix epoch. + +@end table ETEXI { diff --git a/monitor.c b/monitor.c index 1047ceea97..b13a363131 100644 --- a/monitor.c +++ b/monitor.c @@ -34,6 +34,7 @@ #include "net.h" #include "net/slirp.h" #include "qemu-char.h" +#include "ui/qemu-spice.h" #include "sysemu.h" #include "monitor.h" #include "readline.h" @@ -1075,6 +1076,105 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data) return ret; } +static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *protocol = qdict_get_str(qdict, "protocol"); + const char *password = qdict_get_str(qdict, "password"); + const char *connected = qdict_get_try_str(qdict, "connected"); + int disconnect_if_connected = 0; + int fail_if_connected = 0; + int rc; + + if (connected) { + if (strcmp(connected, "fail") == 0) { + fail_if_connected = 1; + } else if (strcmp(connected, "disconnect") == 0) { + disconnect_if_connected = 1; + } else if (strcmp(connected, "keep") == 0) { + /* nothing */ + } else { + qerror_report(QERR_INVALID_PARAMETER, "connected"); + return -1; + } + } + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); + return -1; + } + rc = qemu_spice_set_passwd(password, fail_if_connected, + disconnect_if_connected); + if (rc != 0) { + qerror_report(QERR_SET_PASSWD_FAILED); + return -1; + } + return 0; + } + + if (strcmp(protocol, "vnc") == 0) { + if (fail_if_connected || disconnect_if_connected) { + /* vnc supports "connected=keep" only */ + qerror_report(QERR_INVALID_PARAMETER, "connected"); + return -1; + } + rc = vnc_display_password(NULL, password); + if (rc != 0) { + qerror_report(QERR_SET_PASSWD_FAILED); + return -1; + } + return 0; + } + + qerror_report(QERR_INVALID_PARAMETER, "protocol"); + return -1; +} + +static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *protocol = qdict_get_str(qdict, "protocol"); + const char *whenstr = qdict_get_str(qdict, "time"); + time_t when; + int rc; + + if (strcmp(whenstr, "now")) { + when = 0; + } else if (strcmp(whenstr, "never")) { + when = TIME_MAX; + } else if (whenstr[0] == '+') { + when = time(NULL) + strtoull(whenstr+1, NULL, 10); + } else { + when = strtoull(whenstr, NULL, 10); + } + + if (strcmp(protocol, "spice") == 0) { + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); + return -1; + } + rc = qemu_spice_set_pw_expire(when); + if (rc != 0) { + qerror_report(QERR_SET_PASSWD_FAILED); + return -1; + } + return 0; + } + + if (strcmp(protocol, "vnc") == 0) { + rc = vnc_display_pw_expire(NULL, when); + if (rc != 0) { + qerror_report(QERR_SET_PASSWD_FAILED); + return -1; + } + return 0; + } + + qerror_report(QERR_INVALID_PARAMETER, "protocol"); + return -1; +} + static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data) { vga_hw_screen_dump(qdict_get_str(qdict, "filename")); diff --git a/qmp-commands.hx b/qmp-commands.hx index b4e601751f..1d71711f2e 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -735,6 +735,63 @@ Example: "password": "12345" } } <- { "return": {} } +EQMP + + { + .name = "set_password", + .args_type = "protocol:s,password:s,connected:s?", + .params = "protocol password action-if-connected", + .help = "set spice/vnc password", + .user_print = monitor_user_noop, + .mhandler.cmd_new = set_password, + }, + +SQMP +set_password +------------ + +Set the password for vnc/spice protocols. + +Arguments: + +- "protocol": protocol name (json-string) +- "password": password (json-string) +- "connected": [ keep | disconnect | fail ] (josn-string, optional) + +Example: + +-> { "execute": "set_password", "arguments": { "protocol": "vnc", + "password": "secret" } } +<- { "return": {} } + +EQMP + + { + .name = "expire_password", + .args_type = "protocol:s,time:s", + .params = "protocol time", + .help = "set spice/vnc password expire-time", + .user_print = monitor_user_noop, + .mhandler.cmd_new = expire_password, + }, + +SQMP +expire_password +--------------- + +Set the password expire time for vnc/spice protocols. + +Arguments: + +- "protocol": protocol name (json-string) +- "time": [ now | never | +secs | secs ] (json-string) + +Example: + +-> { "execute": "expire_password", "arguments": { "protocol": "vnc", + "time": "+60" } } +<- { "return": {} } + EQMP { diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 8b23ac9d04..48239c3dbd 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -32,6 +32,9 @@ void qemu_spice_input_init(void); void qemu_spice_audio_init(void); void qemu_spice_display_init(DisplayState *ds); int qemu_spice_add_interface(SpiceBaseInstance *sin); +int qemu_spice_set_passwd(const char *passwd, + bool fail_if_connected, bool disconnect_if_connected); +int qemu_spice_set_pw_expire(time_t expires); void do_info_spice_print(Monitor *mon, const QObject *data); void do_info_spice(Monitor *mon, QObject **ret_data); @@ -39,6 +42,8 @@ void do_info_spice(Monitor *mon, QObject **ret_data); #else /* CONFIG_SPICE */ #define using_spice 0 +#define qemu_spice_set_passwd(_p, _f1, _f2) (-1) +#define qemu_spice_set_pw_expire(_e) (-1) #endif /* CONFIG_SPICE */ diff --git a/ui/spice-core.c b/ui/spice-core.c index d29d20359d..27a1ced430 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -36,6 +36,8 @@ static SpiceServer *spice_server; static const char *auth = "spice"; +static char *auth_passwd; +static time_t auth_expires = TIME_MAX; int using_spice = 0; struct SpiceTimer { @@ -599,6 +601,39 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) return spice_server_add_interface(spice_server, sin); } +static int qemu_spice_set_ticket(bool fail_if_conn, bool disconnect_if_conn) +{ + time_t lifetime, now = time(NULL); + char *passwd; + + if (now < auth_expires) { + passwd = auth_passwd; + lifetime = (auth_expires - now); + if (lifetime > INT_MAX) { + lifetime = INT_MAX; + } + } else { + passwd = NULL; + lifetime = 1; + } + return spice_server_set_ticket(spice_server, passwd, lifetime, + fail_if_conn, disconnect_if_conn); +} + +int qemu_spice_set_passwd(const char *passwd, + bool fail_if_conn, bool disconnect_if_conn) +{ + free(auth_passwd); + auth_passwd = strdup(passwd); + return qemu_spice_set_ticket(fail_if_conn, disconnect_if_conn); +} + +int qemu_spice_set_pw_expire(time_t expires) +{ + auth_expires = expires; + return qemu_spice_set_ticket(false, false); +} + static void spice_register_config(void) { qemu_add_opts(&qemu_spice_opts); -- cgit v1.2.3 From d41160a3e64b26c9d78ecfd78b0e7ef3e878d475 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 19 Dec 2010 13:42:56 +0000 Subject: Sparc: implement monitor command 'info tlb' Use existing dump_mmu() to implement monitor command 'info tlb'. Signed-off-by: Blue Swirl --- hmp-commands.hx | 2 +- monitor.c | 11 +++++- target-sparc/cpu.h | 2 +- target-sparc/helper.c | 88 ++++++++++++++++++++++++------------------------ target-sparc/op_helper.c | 20 +++++------ 5 files changed, 66 insertions(+), 57 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index dd3db36108..4befbe2e56 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1190,7 +1190,7 @@ show i8259 (PIC) state @item info pci show emulated PCI device info @item info tlb -show virtual to physical memory mappings (i386 only) +show virtual to physical memory mappings (i386, SH4 and SPARC only) @item info mem show the active virtual memory mappings (i386 only) @item info jit diff --git a/monitor.c b/monitor.c index aae81bb8ad..5d74fe30b1 100644 --- a/monitor.c +++ b/monitor.c @@ -2272,6 +2272,15 @@ static void tlb_info(Monitor *mon) #endif +#if defined(TARGET_SPARC) +static void tlb_info(Monitor *mon) +{ + CPUState *env1 = mon_get_cpu(); + + dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1); +} +#endif + static void do_info_kvm_print(Monitor *mon, const QObject *data) { QDict *qdict; @@ -2744,7 +2753,7 @@ static const mon_cmd_t info_cmds[] = { .user_print = do_pci_info_print, .mhandler.info_new = do_pci_info, }, -#if defined(TARGET_I386) || defined(TARGET_SH4) +#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) { .name = "tlb", .args_type = "", diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 1be66e7fa6..7225b2ed3c 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -448,7 +448,7 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw int mmu_idx, int is_softmmu); #define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev); -void dump_mmu(CPUSPARCState *env); +void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env); /* translate.c */ void gen_intermediate_code_init(CPUSPARCState *env); diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 7e45d7ac5c..6b337ca091 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -320,47 +320,45 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) return 0; } -#ifdef DEBUG_MMU -void dump_mmu(CPUState *env) +void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) { target_ulong va, va1, va2; unsigned int n, m, o; target_phys_addr_t pde_ptr, pa; uint32_t pde; - printf("MMU dump:\n"); pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); pde = ldl_phys(pde_ptr); - printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n", - (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); + (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n", + (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { pde = mmu_probe(env, va, 2); if (pde) { pa = cpu_get_phys_page_debug(env, va); - printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx - " PDE: " TARGET_FMT_lx "\n", va, pa, pde); + (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx + " PDE: " TARGET_FMT_lx "\n", va, pa, pde); for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { pde = mmu_probe(env, va1, 1); if (pde) { pa = cpu_get_phys_page_debug(env, va1); - printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx - " PDE: " TARGET_FMT_lx "\n", va1, pa, pde); + (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " + TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", + va1, pa, pde); for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { pde = mmu_probe(env, va2, 0); if (pde) { pa = cpu_get_phys_page_debug(env, va2); - printf(" VA: " TARGET_FMT_lx ", PA: " - TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n", - va2, pa, pde); + (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " + TARGET_FMT_plx " PTE: " + TARGET_FMT_lx "\n", + va2, pa, pde); } } } } } } - printf("MMU dump ends\n"); } -#endif /* DEBUG_MMU */ #else /* !TARGET_SPARC64 */ @@ -622,18 +620,19 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, return 1; } -#ifdef DEBUG_MMU -void dump_mmu(CPUState *env) +void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) { unsigned int i; const char *mask; - printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", - env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context); + (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %" + PRId64 "\n", + env->dmmu.mmu_primary_context, + env->dmmu.mmu_secondary_context); if ((env->lsu & DMMU_E) == 0) { - printf("DMMU disabled\n"); + (*cpu_fprintf)(f, "DMMU disabled\n"); } else { - printf("DMMU dump:\n"); + (*cpu_fprintf)(f, "DMMU dump\n"); for (i = 0; i < 64; i++) { switch ((env->dtlb[i].tte >> 61) & 3) { default: @@ -651,24 +650,25 @@ void dump_mmu(CPUState *env) break; } if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) { - printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64 - ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", - i, - env->dtlb[i].tag & (uint64_t)~0x1fffULL, - env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL, - mask, - env->dtlb[i].tte & 0x4? "priv": "user", - env->dtlb[i].tte & 0x2? "RW": "RO", - env->dtlb[i].tte & 0x40? "locked": "unlocked", - env->dtlb[i].tag & (uint64_t)0x1fffULL, - TTE_IS_GLOBAL(env->dtlb[i].tte)? "global" : "local"); + (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64 + ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", + i, + env->dtlb[i].tag & (uint64_t)~0x1fffULL, + env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL, + mask, + env->dtlb[i].tte & 0x4? "priv": "user", + env->dtlb[i].tte & 0x2? "RW": "RO", + env->dtlb[i].tte & 0x40? "locked": "unlocked", + env->dtlb[i].tag & (uint64_t)0x1fffULL, + TTE_IS_GLOBAL(env->dtlb[i].tte)? + "global" : "local"); } } } if ((env->lsu & IMMU_E) == 0) { - printf("IMMU disabled\n"); + (*cpu_fprintf)(f, "IMMU disabled\n"); } else { - printf("IMMU dump:\n"); + (*cpu_fprintf)(f, "IMMU dump\n"); for (i = 0; i < 64; i++) { switch ((env->itlb[i].tte >> 61) & 3) { default: @@ -686,21 +686,21 @@ void dump_mmu(CPUState *env) break; } if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) { - printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64 - ", %s, %s, %s, ctx %" PRId64 " %s\n", - i, - env->itlb[i].tag & (uint64_t)~0x1fffULL, - env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL, - mask, - env->itlb[i].tte & 0x4? "priv": "user", - env->itlb[i].tte & 0x40? "locked": "unlocked", - env->itlb[i].tag & (uint64_t)0x1fffULL, - TTE_IS_GLOBAL(env->itlb[i].tte)? "global" : "local"); + (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64 + ", %s, %s, %s, ctx %" PRId64 " %s\n", + i, + env->itlb[i].tag & (uint64_t)~0x1fffULL, + env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL, + mask, + env->itlb[i].tte & 0x4? "priv": "user", + env->itlb[i].tte & 0x40? "locked": "unlocked", + env->itlb[i].tag & (uint64_t)0x1fffULL, + TTE_IS_GLOBAL(env->itlb[i].tte)? + "global" : "local"); } } } } -#endif /* DEBUG_MMU */ #endif /* TARGET_SPARC64 */ #endif /* !CONFIG_USER_ONLY */ diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index be3c1e051b..4f753ba379 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -180,7 +180,7 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, replace_tlb_entry(&tlb[i], 0, 0, env1); #ifdef DEBUG_MMU DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i); - dump_mmu(env1); + dump_mmu(stdout, fprintf, env1); #endif } } @@ -198,7 +198,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); #ifdef DEBUG_MMU DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i); - dump_mmu(env1); + dump_mmu(stdout, fprintf, env1); #endif return; } @@ -217,7 +217,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, #ifdef DEBUG_MMU DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n", strmmu, (replace_used?"used":"unused"), i); - dump_mmu(env1); + dump_mmu(stdout, fprintf, env1); #endif return; } @@ -1959,7 +1959,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) break; } #ifdef DEBUG_MMU - dump_mmu(env); + dump_mmu(stdout, fprintf, env); #endif } break; @@ -2011,7 +2011,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) reg, oldreg, env->mmuregs[reg]); } #ifdef DEBUG_MMU - dump_mmu(env); + dump_mmu(stdout, fprintf, env); #endif } break; @@ -2912,7 +2912,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu); #ifdef DEBUG_MMU - dump_mmu(env); + dump_mmu(stdout, fprintf, env1); #endif tlb_flush(env, 1); } @@ -2957,7 +2957,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) PRIx64 "\n", reg, oldreg, env->immuregs[reg]); } #ifdef DEBUG_MMU - dump_mmu(env); + dump_mmu(stdout, fprintf, env); #endif return; } @@ -2974,7 +2974,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) #ifdef DEBUG_MMU DPRINTF_MMU("immu data access replaced entry [%i]\n", i); - dump_mmu(env); + dump_mmu(stdout, fprintf, env); #endif return; } @@ -3030,7 +3030,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); } #ifdef DEBUG_MMU - dump_mmu(env); + dump_mmu(stdout, fprintf, env); #endif return; } @@ -3045,7 +3045,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) #ifdef DEBUG_MMU DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); - dump_mmu(env); + dump_mmu(stdout, fprintf, env); #endif return; } -- cgit v1.2.3 From 4fd37a98d1248bae54a9f71ee1c252d2b2f1efd5 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 19 Dec 2010 14:05:43 +0000 Subject: Avoid a warning from OpenBSD linker Avoid the warning below by using snprintf: ../libhw64/vl.o(.text+0x78d4): In function `get_boot_devices_list': /src/qemu/vl.c:763: warning: sprintf() is often misused, please use snprintf() Signed-off-by: Blue Swirl --- vl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index c4d3fc0d3d..768dbf48ad 100644 --- a/vl.c +++ b/vl.c @@ -759,8 +759,10 @@ char *get_boot_devices_list(uint32_t *size) } if (i->suffix && devpath) { - bootpath = qemu_malloc(strlen(devpath) + strlen(i->suffix) + 1); - sprintf(bootpath, "%s%s", devpath, i->suffix); + size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1; + + bootpath = qemu_malloc(bootpathlen); + snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix); qemu_free(devpath); } else if (devpath) { bootpath = devpath; -- cgit v1.2.3 From f5095c639fe2861b6401be6e26fa3ffb9d30eba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 19 Dec 2010 17:22:39 +0100 Subject: apic: Fix accidental use of SoftFloat uint32 type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit softfloat.h's uint32 type has least-width semantics. Surrounding code uses uint32_t, so use uint32_t here, too. v4: * Summary change. v3: * Split off. Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- hw/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/apic.c b/hw/apic.c index a5a53fb963..ff581f0787 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -765,7 +765,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) return val; } -static void apic_send_msi(target_phys_addr_t addr, uint32 data) +static void apic_send_msi(target_phys_addr_t addr, uint32_t data) { uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; -- cgit v1.2.3 From c910cf96dc8a2a1d3ee0a695979770d13538806f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 19 Dec 2010 17:22:40 +0100 Subject: wdt_ib700: Fix accidental use of SoftFloat int64 type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit softfloat.h's int64 type has least-width semantics. Since we're assigning an int64_t, use plain int64_t. v4: * Summary change. v3: * Split off. Signed-off-by: Andreas Färber Acked-by: Richard W.M. Jones Signed-off-by: Blue Swirl --- hw/wdt_ib700.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index b6235ebe52..1248464ff5 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -53,7 +53,7 @@ static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data) 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0 }; - int64 timeout; + int64_t timeout; ib700_debug("addr = %x, data = %x\n", addr, data); -- cgit v1.2.3 From ac6c41204fd33116b8943682bffe47e113c1cc6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 19 Dec 2010 17:22:41 +0100 Subject: target-i386: Fix accidental use of SoftFloat uint64 type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit softfloat.h's uint64 type has least-width semantics. Use uint64_t instead since that is used in helpers. v4: * Summary change. v3: * Split off. Signed-off-by: Andreas Färber Acked-by: Huang Ying Acked-by: Juan Quintela Signed-off-by: Blue Swirl --- target-i386/cpu.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 06e40f3e49..f0c07cde3b 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -737,10 +737,10 @@ typedef struct CPUX86State { user */ struct DeviceState *apic_state; - uint64 mcg_cap; - uint64 mcg_status; - uint64 mcg_ctl; - uint64 mce_banks[MCE_BANKS_DEF*4]; + uint64_t mcg_cap; + uint64_t mcg_status; + uint64_t mcg_ctl; + uint64_t mce_banks[MCE_BANKS_DEF*4]; uint64_t tsc_aux; -- cgit v1.2.3 From e0087e618552c7bc77485561ed96ec2a4f01404a Mon Sep 17 00:00:00 2001 From: Bob Breuer Date: Mon, 20 Dec 2010 11:55:33 -0600 Subject: sparc32: ledma extra registers need tracing too Also trace the extra registers, and update the comments with new info from Artyom Tarasenko. Signed-off-by: Bob Breuer Signed-off-by: Blue Swirl --- hw/sparc32_dma.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 56be8c8ad6..e75694bec2 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -44,7 +44,7 @@ /* We need the mask, because one instance of the device is not page aligned (ledma, start address 0x0010) */ #define DMA_MASK (DMA_SIZE - 1) -/* ledma has more than 4 registers, Solaris reads the 5th one */ +/* OBP says 0x20 bytes for ledma, the extras are aliased to espdma */ #define DMA_ETH_SIZE (8 * sizeof(uint32_t)) #define DMA_MAX_REG_OFFSET (2 * DMA_SIZE - 1) @@ -170,7 +170,10 @@ static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr) uint32_t saddr; if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) { - return 0; /* extra mystery register(s) */ + /* aliased to espdma, but we can't get there from here */ + /* buggy driver if using undocumented behavior, just return 0 */ + trace_sparc32_dma_mem_readl(addr, 0); + return 0; } saddr = (addr & DMA_MASK) >> 2; trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]); @@ -183,7 +186,9 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) uint32_t saddr; if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) { - return; /* extra mystery register(s) */ + /* aliased to espdma, but we can't get there from here */ + trace_sparc32_dma_mem_writel(addr, 0, val); + return; } saddr = (addr & DMA_MASK) >> 2; trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val); -- cgit v1.2.3 From fcd61af6631fb98c4c12e865572d4d81d73728d0 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 16 Dec 2010 19:33:22 +0100 Subject: qdev: sysbus_get_default must not return a NULL pointer (fix regression) Every system should have some sort of main system bus, so sysbus_get_default should always return a valid bus. Without this patch, at least mipssim and malta no longer start but raise a null pointer access exception (caused by commit ec990eb622ad46df5ddcb1e94c418c271894d416). Cc: Anthony Liguori Signed-off-by: Stefan Weil Signed-off-by: Aurelien Jarno --- hw/qdev.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index 10e28df7a1..6fc9b02a38 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -107,10 +107,7 @@ DeviceState *qdev_create(BusState *bus, const char *name) DeviceInfo *info; if (!bus) { - if (!main_system_bus) { - main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus"); - } - bus = main_system_bus; + bus = sysbus_get_default(); } info = qdev_find_info(bus->info, name); @@ -311,6 +308,10 @@ static int qdev_reset_one(DeviceState *dev, void *opaque) BusState *sysbus_get_default(void) { + if (!main_system_bus) { + main_system_bus = qbus_create(&system_bus_info, NULL, + "main-system-bus"); + } return main_system_bus; } -- cgit v1.2.3 From 4a1e19ae05a3f03fdd0896e8f26efe94b2ff60a2 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 21 Dec 2010 19:32:49 +0100 Subject: tcg-arm: fix __clear_cache() warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use __builtin___clear_cache() instead of __clear_cache() to avoid having to define the function as extern. Fix the following warning: | In file included from qemu/cpus.c:34: | qemu/exec-all.h: In function 'tb_set_jmp_target1': | qemu/exec-all.h:208: error: nested extern declaration of '__clear_cache' | make[1]: *** [cpus.o] Error 1 | make: *** [subdir-i386-softmmu] Error 2 Signed-off-by: Aurelien Jarno --- exec-all.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/exec-all.h b/exec-all.h index c4570587d7..6821b17943 100644 --- a/exec-all.h +++ b/exec-all.h @@ -204,9 +204,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr #elif defined(__arm__) static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { -#if QEMU_GNUC_PREREQ(4, 1) - void __clear_cache(char *beg, char *end); -#else +#if !QEMU_GNUC_PREREQ(4, 1) register unsigned long _beg __asm ("a1"); register unsigned long _end __asm ("a2"); register unsigned long _flg __asm ("a3"); @@ -218,7 +216,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr | (((addr - (jmp_addr + 8)) >> 2) & 0xffffff); #if QEMU_GNUC_PREREQ(4, 1) - __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); + __builtin___clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); #else /* flush icache */ _beg = jmp_addr; -- cgit v1.2.3 From 5f668643dc6ef3e59d5bc9b86fdf6778c59c98f2 Mon Sep 17 00:00:00 2001 From: Brad Date: Mon, 20 Dec 2010 21:23:15 -0500 Subject: Add support for OpenBSD to QEMU's tap driver. Signed-off-by: Brad Smith Signed-off-by: Blue Swirl --- net/tap-bsd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/tap-bsd.c b/net/tap-bsd.c index efccfe08a7..2f3efdee03 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -43,8 +43,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required char *dev; struct stat s; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - /* if no ifname is given, always start the search from tap0. */ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) + /* if no ifname is given, always start the search from tap0/tun0. */ int i; char dname[100]; @@ -52,7 +52,11 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required if (*ifname) { snprintf(dname, sizeof dname, "/dev/%s", ifname); } else { +#if defined(__OpenBSD__) + snprintf(dname, sizeof dname, "/dev/tun%d", i); +#else snprintf(dname, sizeof dname, "/dev/tap%d", i); +#endif } TFR(fd = open(dname, O_RDWR)); if (fd >= 0) { -- cgit v1.2.3 From 7ae63a517fb50fe32b8ce88bfc18a1a1ed056189 Mon Sep 17 00:00:00 2001 From: Brad Date: Mon, 20 Dec 2010 21:24:32 -0500 Subject: Add OpenBSD to ifdef list since it has CLOCK_MONOTONIC. Signed-off-by: Brad Smith Signed-off-by: Blue Swirl --- qemu-timer-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-timer-common.c b/qemu-timer-common.c index fff43996d8..755e300bc9 100644 --- a/qemu-timer-common.c +++ b/qemu-timer-common.c @@ -50,7 +50,8 @@ static void __attribute__((constructor)) init_get_clock(void) { use_rt_clock = 0; #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ - || defined(__DragonFly__) || defined(__FreeBSD_kernel__) + || defined(__DragonFly__) || defined(__FreeBSD_kernel__) \ + || defined(__OpenBSD__) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { -- cgit v1.2.3 From cbb608a5c8ff918188545edb28127f63db76bd1e Mon Sep 17 00:00:00 2001 From: Brad Date: Mon, 20 Dec 2010 21:25:40 -0500 Subject: Use mmap() within code_gen_alloc() for OpenBSD. Signed-off-by: Brad Smith Signed-off-by: Blue Swirl --- exec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index a3384958c7..49c28b160e 100644 --- a/exec.c +++ b/exec.c @@ -517,7 +517,8 @@ static void code_gen_alloc(unsigned long tb_size) exit(1); } } -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \ + || defined(__DragonFly__) || defined(__OpenBSD__) { int flags; void *addr = NULL; -- cgit v1.2.3 From 9ed5726c043958359b0f1fa44ab3e4f25f9d9a47 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 29 Oct 2010 07:48:46 -0700 Subject: target-mips: fix translation of MT instructions The translation of dmt/emt/dvpe/evpe was doing the moral equivalent of: int x; ... /* no initialization of x */ x = f (x); which confused later bits of TCG rather badly, leading to crashes. Fix the helpers to only return results (those instructions have no inputs), and fix the translation code accordingly. Signed-off-by: Nathan Froyd Signed-off-by: Aurelien Jarno --- target-mips/helper.h | 8 ++++---- target-mips/op_helper.c | 28 ++++++++-------------------- target-mips/translate.c | 8 ++++---- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/target-mips/helper.h b/target-mips/helper.h index cb13fb2352..297ab64bda 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -154,10 +154,10 @@ DEF_HELPER_2(mttlo, void, tl, i32) DEF_HELPER_2(mtthi, void, tl, i32) DEF_HELPER_2(mttacx, void, tl, i32) DEF_HELPER_1(mttdsp, void, tl) -DEF_HELPER_1(dmt, tl, tl) -DEF_HELPER_1(emt, tl, tl) -DEF_HELPER_1(dvpe, tl, tl) -DEF_HELPER_1(evpe, tl, tl) +DEF_HELPER_0(dmt, tl) +DEF_HELPER_0(emt, tl) +DEF_HELPER_0(dvpe, tl) +DEF_HELPER_0(evpe, tl) #endif /* !CONFIG_USER_ONLY */ /* microMIPS functions */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 41abd575f9..ec6864d903 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1554,40 +1554,28 @@ void helper_mttdsp(target_ulong arg1) } /* MIPS MT functions */ -target_ulong helper_dmt(target_ulong arg1) +target_ulong helper_dmt(void) { // TODO - arg1 = 0; - // rt = arg1 - - return arg1; + return 0; } -target_ulong helper_emt(target_ulong arg1) +target_ulong helper_emt(void) { // TODO - arg1 = 0; - // rt = arg1 - - return arg1; + return 0; } -target_ulong helper_dvpe(target_ulong arg1) +target_ulong helper_dvpe(void) { // TODO - arg1 = 0; - // rt = arg1 - - return arg1; + return 0; } -target_ulong helper_evpe(target_ulong arg1) +target_ulong helper_evpe(void) { // TODO - arg1 = 0; - // rt = arg1 - - return arg1; + return 0; } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-mips/translate.c b/target-mips/translate.c index ba45eb0e52..cce77be0d1 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12033,22 +12033,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch) switch (op2) { case OPC_DMT: check_insn(env, ctx, ASE_MT); - gen_helper_dmt(t0, t0); + gen_helper_dmt(t0); gen_store_gpr(t0, rt); break; case OPC_EMT: check_insn(env, ctx, ASE_MT); - gen_helper_emt(t0, t0); + gen_helper_emt(t0); gen_store_gpr(t0, rt); break; case OPC_DVPE: check_insn(env, ctx, ASE_MT); - gen_helper_dvpe(t0, t0); + gen_helper_dvpe(t0); gen_store_gpr(t0, rt); break; case OPC_EVPE: check_insn(env, ctx, ASE_MT); - gen_helper_evpe(t0, t0); + gen_helper_evpe(t0); gen_store_gpr(t0, rt); break; case OPC_DI: -- cgit v1.2.3 From 6c33286ad3a432627d763ee93aa42200cbb68269 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 17 Nov 2010 13:01:04 +0100 Subject: s390: compile fixes The s390 target doesn't compile out of the box anymore. This patch fixes all the obvious glitches that got introduced in the last few weeks. Signed-off-by: Alexander Graf Signed-off-by: Aurelien Jarno --- hw/s390-virtio-bus.h | 2 ++ hw/s390-virtio.c | 1 + target-s390x/kvm.c | 2 +- target-s390x/translate.c | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 41558c9c67..669b610a14 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -17,6 +17,8 @@ * License along with this library; if not, see . */ +#include "virtio-net.h" + #define VIRTIO_DEV_OFFS_TYPE 0 /* 8 bits */ #define VIRTIO_DEV_OFFS_NUM_VQ 1 /* 8 bits */ #define VIRTIO_DEV_OFFS_FEATURE_LEN 2 /* 8 bits */ diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index e7aec14fae..f29b624e41 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -19,6 +19,7 @@ #include "hw.h" #include "block.h" +#include "blockdev.h" #include "sysemu.h" #include "net.h" #include "boards.h" diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 9bf6abb213..adf4a9e1e5 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -119,7 +119,7 @@ int kvm_arch_put_registers(CPUState *env, int level) int kvm_arch_get_registers(CPUState *env) { - uint32_t ret; + int ret; struct kvm_regs regs; int i; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 881d8c4acf..d33bfb1f31 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -36,7 +36,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, } } for (i = 0; i < 16; i++) { - cpu_fprintf(f, "F%02d=%016lx", i, env->fregs[i]); + cpu_fprintf(f, "F%02d=%016lx", i, (long)env->fregs[i].i); if ((i % 4) == 3) { cpu_fprintf(f, "\n"); } else { -- cgit v1.2.3 From 4cdc1cd137e0b98766916a7cdf2d5a9b3c6632fa Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 25 Dec 2010 22:56:32 +0100 Subject: target-mips: fix host CPU consumption when guest is idle When the CPU is in wait state, do not wake-up if an interrupt can't be taken. This avoid host CPU running at 100% if a device (e.g. timer) has an interrupt line left enabled. Also factorize code to check if interrupts are enabled in cpu_mips_hw_interrupts_pending(). Based on a patch from Edgar E. Iglesias Signed-off-by: Aurelien Jarno Acked-by: Edgar E. Iglesias --- cpu-exec.c | 6 +----- target-mips/cpu.h | 8 ++++++++ target-mips/exec.h | 18 +++++++++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 39e5eeaa8f..8c9fb8b1a2 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -454,11 +454,7 @@ int cpu_exec(CPUState *env1) } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && - cpu_mips_hw_interrupts_pending(env) && - (env->CP0_Status & (1 << CP0St_IE)) && - !(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM)) { + cpu_mips_hw_interrupts_pending(env)) { /* Raise it */ env->exception_index = EXCP_EXT_INTERRUPT; env->error_code = 0; diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c1f211fc17..2419aa93d2 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -532,6 +532,14 @@ static inline int cpu_mips_hw_interrupts_pending(CPUState *env) int32_t status; int r; + if (!(env->CP0_Status & (1 << CP0St_IE)) || + (env->CP0_Status & (1 << CP0St_EXL)) || + (env->CP0_Status & (1 << CP0St_ERL)) || + (env->hflags & MIPS_HFLAG_DM)) { + /* Interrupts are disabled */ + return 0; + } + pending = env->CP0_Cause & CP0Ca_IP_mask; status = env->CP0_Status & CP0Ca_IP_mask; diff --git a/target-mips/exec.h b/target-mips/exec.h index af61b54dcf..12736543ac 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -19,10 +19,22 @@ register struct CPUMIPSState *env asm(AREG0); static inline int cpu_has_work(CPUState *env) { - return (env->interrupt_request & - (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)); -} + int has_work = 0; + + /* It is implementation dependent if non-enabled interrupts + wake-up the CPU, however most of the implementations only + check for interrupts that can be taken. */ + if ((env->interrupt_request & CPU_INTERRUPT_HARD) && + cpu_mips_hw_interrupts_pending(env)) { + has_work = 1; + } + if (env->interrupt_request & CPU_INTERRUPT_TIMER) { + has_work = 1; + } + + return has_work; +} static inline int cpu_halted(CPUState *env) { -- cgit v1.2.3 From 5697f6ae4183f3b3320a1fe677e3404a05e75783 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 27 Dec 2010 18:29:20 +0100 Subject: Fix a missing trailing newline Signed-off-by: Aurelien Jarno --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 768dbf48ad..c605347607 100644 --- a/vl.c +++ b/vl.c @@ -2603,7 +2603,7 @@ int main(int argc, char **argv, char **envp) if (p != NULL) { *p++ = 0; if (strncmp(p, "process=", 8)) { - fprintf(stderr, "Unknown subargument %s to -name", p); + fprintf(stderr, "Unknown subargument %s to -name\n", p); exit(1); } p += 8; -- cgit v1.2.3 From 1a855029af40df40144a322bba0e1e61c68eed2a Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 27 Dec 2010 19:54:49 +0100 Subject: target-arm: fix bug in translation of REVSH The translation of REVSH shifted the low byte 8 steps left before performing an 8-bit sign extend, causing this part of the expression to alwas be 0. Reported-by: Johan Bengtsson Signed-off-by: Aurelien Jarno --- target-arm/translate.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index d4a0666be5..24b4fb65ed 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -250,13 +250,9 @@ static void gen_rev16(TCGv var) /* Byteswap low halfword and sign extend. */ static void gen_revsh(TCGv var) { - TCGv tmp = new_tmp(); - tcg_gen_shri_i32(tmp, var, 8); - tcg_gen_andi_i32(tmp, tmp, 0x00ff); - tcg_gen_shli_i32(var, var, 8); - tcg_gen_ext8s_i32(var, var); - tcg_gen_or_i32(var, var, tmp); - dead_tmp(tmp); + tcg_gen_ext16u_i32(var, var); + tcg_gen_bswap16_i32(var, var); + tcg_gen_ext16s_i32(var, var); } /* Unsigned bitfield extract. */ -- cgit v1.2.3 From def126ce37b037afc55878197159d9ddcb24a9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= Date: Tue, 7 Dec 2010 14:13:41 +0000 Subject: target-arm: Fix arguments passed to VQSHL helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct the arguments passed when generating neon qshl_{u,s}64() helpers so that we use the correct registers. Signed-off-by: Juha Riihimäki Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 24b4fb65ed..8d494ec924 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -4236,9 +4236,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) case 9: /* VQSHL */ if (u) { gen_helper_neon_qshl_u64(cpu_V0, cpu_env, - cpu_V0, cpu_V0); + cpu_V1, cpu_V0); } else { - gen_helper_neon_qshl_s64(cpu_V1, cpu_env, + gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V1, cpu_V0); } break; -- cgit v1.2.3 From 4c9b70aeca70b3e0a68a771727f388551620b3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= Date: Tue, 7 Dec 2010 14:13:42 +0000 Subject: target-arm: Fix VQSHL of signed 64 bit values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a missing '-' which meant that we were misinterpreting the shift argument for VQSHL of 64 bit signed values and treating almost every shift value as if it were an extremely large right shift. Signed-off-by: Juha Riihimäki Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/neon_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 5e6452b9d9..d29b884614 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -610,7 +610,7 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) SET_QC(); val = (val >> 63) & ~SIGNBIT64; } - } else if (shift <= 64) { + } else if (shift <= -64) { val >>= 63; } else if (shift < 0) { val >>= -shift; -- cgit v1.2.3 From eb7a3d7964f748ba815200372d7ff403737c54d7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Dec 2010 14:13:43 +0000 Subject: target-arm: Fix VQSHL of signed 64 bit values by shift counts >= 64 VQSHL of a signed 64 bit non-zero value by a shift count >= 64 should saturate; return the correct value in this case. Signed-off-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/neon_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index d29b884614..2dc3d96dba 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -608,7 +608,7 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop) if (shift >= 64) { if (val) { SET_QC(); - val = (val >> 63) & ~SIGNBIT64; + val = (val >> 63) ^ ~SIGNBIT64; } } else if (shift <= -64) { val >>= 63; -- cgit v1.2.3 From 620d791e341fe0b36e6c2a5659b2cc9f7866948f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= Date: Tue, 7 Dec 2010 14:13:44 +0000 Subject: target-arm: remove pointless else clause in VQSHL of u64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove a pointless else clause in the neon_qshl_u64 helper. Signed-off-by: Juha Riihimäki Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/neon_helper.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 2dc3d96dba..48b9f5b5b5 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -560,8 +560,6 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) if (val) { val = ~(uint64_t)0; SET_QC(); - } else { - val = 0; } } else if (shift <= -64) { val = 0; -- cgit v1.2.3 From a5d88f3e030f9f83e63b0cb3c09a3293d8057f4a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Dec 2010 14:13:45 +0000 Subject: target-arm: Correct result in saturating cases for VQSHL of s8/16/32 Where VQSHL of a signed 8/16/32 bit value saturated, the result value was not being calculated correctly (it should be either the minimum or maximum value for the size of the signed type). Signed-off-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/neon_helper.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 48b9f5b5b5..dae063ea1a 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -580,9 +580,15 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) int8_t tmp; \ tmp = (int8_t)src2; \ if (tmp >= (ssize_t)sizeof(src1) * 8) { \ - if (src1) \ + if (src1) { \ SET_QC(); \ - dest = src1 >> 31; \ + dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \ + if (src1 > 0) { \ + dest--; \ + } \ + } else { \ + dest = src1; \ + } \ } else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \ dest = src1 >> 31; \ } else if (tmp < 0) { \ @@ -591,7 +597,10 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop) dest = src1 << tmp; \ if ((dest >> tmp) != src1) { \ SET_QC(); \ - dest = src2 >> 31; \ + dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \ + if (src1 > 0) { \ + dest--; \ + } \ } \ }} while (0) NEON_VOP_ENV(qshl_s8, neon_s8, 4) -- cgit v1.2.3 From c0034328090880621ad8f33e03ae03599e353865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= Date: Wed, 8 Dec 2010 13:15:16 +0200 Subject: target-arm: fix vmsav6 access control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Override access control checks (including execute) for mmu translation table descriptors assigned to manager domains. Signed-off-by: Juha Riihimäki Signed-off-by: Aurelien Jarno --- target-arm/helper.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 9ba2f4fe15..409a6c00ab 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1084,22 +1084,26 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, } code = 15; } - if (xn && access_type == 2) - goto do_fault; + if (domain == 3) { + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + } else { + if (xn && access_type == 2) + goto do_fault; - /* The simplified model uses AP[0] as an access control bit. */ - if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) { - /* Access flag fault. */ - code = (code == 15) ? 6 : 3; - goto do_fault; - } - *prot = check_ap(env, ap, domain, access_type, is_user); - if (!*prot) { - /* Access permission fault. */ - goto do_fault; - } - if (!xn) { - *prot |= PAGE_EXEC; + /* The simplified model uses AP[0] as an access control bit. */ + if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) { + /* Access flag fault. */ + code = (code == 15) ? 6 : 3; + goto do_fault; + } + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; + } + if (!xn) { + *prot |= PAGE_EXEC; + } } *phys_ptr = phys_addr; return 0; -- cgit v1.2.3 From 9c486ad6e4e4afcd582460b4c70b1e2be856dbfd Mon Sep 17 00:00:00 2001 From: Mattias Holm Date: Wed, 8 Dec 2010 13:15:17 +0200 Subject: target-arm: correct cp15 c1_sys reset value for cortex-a8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juha Riihimäki Signed-off-by: Aurelien Jarno --- target-arm/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index 409a6c00ab..e54fb27a87 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -109,6 +109,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */ env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */ env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */ + env->cp15.c1_sys = 0x00c50078; break; case ARM_CPUID_CORTEXA9: set_feature(env, ARM_FEATURE_V6); -- cgit v1.2.3 From 16440c5fa0a3ba87c7ea92218466673ede7c08f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= Date: Wed, 8 Dec 2010 13:15:18 +0200 Subject: target-arm: correct cp15 c1_sys reset value for arm1136 and cortex-a9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juha Riihimäki Signed-off-by: Aurelien Jarno --- target-arm/helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index e54fb27a87..50c1017c8a 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -76,6 +76,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t)); memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t)); env->cp15.c0_cachetype = 0x1dd20d2; + env->cp15.c1_sys = 0x00050078; break; case ARM_CPUID_ARM11MPCORE: set_feature(env, ARM_FEATURE_V6); @@ -131,6 +132,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id) env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3; env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */ env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */ + env->cp15.c1_sys = 0x00c50078; break; case ARM_CPUID_CORTEXM3: set_feature(env, ARM_FEATURE_V6); -- cgit v1.2.3 From 5569fd7c38ddc7482c9b05af0988779cd0027f6d Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 15 Dec 2010 17:56:18 -0200 Subject: Fix migrate set speed doc arg We used to ignore any fractional part in 0.13, but due to recent changes (started with 9f9b17a4f0865286391e4d3a0a735230122a2289) migrate_set_speed will reject the fractional part. We don't expect existing clients to be relying on this, but we need to update the documentation to reflect the change. Signed-off-by: Luiz Capitulino Signed-off-by: Aurelien Jarno --- qmp-commands.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmp-commands.hx b/qmp-commands.hx index 3486223517..164ecbcac0 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -510,7 +510,7 @@ Set maximum speed for migrations. Arguments: -- "value": maximum speed, in bytes per second (json-number) +- "value": maximum speed, in bytes per second (json-int) Example: -- cgit v1.2.3 From 4058fd98fd7e9c476774717adbd49698dd273166 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 27 Dec 2010 15:52:24 +0100 Subject: x86: Filter out garbage from segment flags dump Only bits 8..23 of the segment flags contain valid data, so only dump those when printing the CPU state. Signed-off-by: Jan Kiszka Signed-off-by: Aurelien Jarno --- target-i386/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index 26ea1e58e0..25a3e36138 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -175,12 +175,12 @@ cpu_x86_dump_seg_cache(CPUState *env, FILE *f, fprintf_function cpu_fprintf, #ifdef TARGET_X86_64 if (env->hflags & HF_CS64_MASK) { cpu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name, - sc->selector, sc->base, sc->limit, sc->flags); + sc->selector, sc->base, sc->limit, sc->flags & 0x00ffff00); } else #endif { cpu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector, - (uint32_t)sc->base, sc->limit, sc->flags); + (uint32_t)sc->base, sc->limit, sc->flags & 0x00ffff00); } if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK)) -- cgit v1.2.3 From 0fcec41eec0432c77645b4a407d3a3e030c4abc4 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 25 Dec 2010 23:25:47 +0100 Subject: target-sparc: fix udiv(cc) and sdiv(cc) Since commit 5a4bb580cdb10b066f9fd67658b31cac4a4ea5e5, Xorg crashes on a Debian Etch image. The commit itself is fine, but it triggers a bug due to wrong computation of flags for udiv(cc) and sdiv(cc). This patch only compute cc_src2 for the cc version of udiv/sdiv. It also moves the update of cc_dst and cc_op to the helper, as it is faster doing it here when there is already an helper. Signed-off-by: Aurelien Jarno Signed-off-by: Blue Swirl --- target-sparc/helper.h | 2 ++ target-sparc/op_helper.c | 54 +++++++++++++++++++++++++++++++++++++----------- target-sparc/translate.c | 12 +++++------ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/target-sparc/helper.h b/target-sparc/helper.h index 6f103e7697..e6d82f9eab 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -37,7 +37,9 @@ DEF_HELPER_0(save, void) DEF_HELPER_0(restore, void) DEF_HELPER_1(flush, void, tl) DEF_HELPER_2(udiv, tl, tl, tl) +DEF_HELPER_2(udiv_cc, tl, tl, tl) DEF_HELPER_2(sdiv, tl, tl, tl) +DEF_HELPER_2(sdiv_cc, tl, tl, tl) DEF_HELPER_2(stdf, void, tl, int) DEF_HELPER_2(lddf, void, tl, int) DEF_HELPER_2(ldqf, void, tl, int) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 4f753ba379..58f9f82f52 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -3300,8 +3300,9 @@ void helper_rett(void) } #endif -target_ulong helper_udiv(target_ulong a, target_ulong b) +static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc) { + int overflow = 0; uint64_t x0; uint32_t x1; @@ -3314,16 +3315,31 @@ target_ulong helper_udiv(target_ulong a, target_ulong b) x0 = x0 / x1; if (x0 > 0xffffffff) { - env->cc_src2 = 1; - return 0xffffffff; - } else { - env->cc_src2 = 0; - return x0; + x0 = 0xffffffff; + overflow = 1; + } + + if (cc) { + env->cc_dst = x0; + env->cc_src2 = overflow; + env->cc_op = CC_OP_DIV; } + return x0; } -target_ulong helper_sdiv(target_ulong a, target_ulong b) +target_ulong helper_udiv(target_ulong a, target_ulong b) +{ + return helper_udiv_common(a, b, 0); +} + +target_ulong helper_udiv_cc(target_ulong a, target_ulong b) +{ + return helper_udiv_common(a, b, 1); +} + +static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc) { + int overflow = 0; int64_t x0; int32_t x1; @@ -3336,12 +3352,26 @@ target_ulong helper_sdiv(target_ulong a, target_ulong b) x0 = x0 / x1; if ((int32_t) x0 != x0) { - env->cc_src2 = 1; - return x0 < 0? 0x80000000: 0x7fffffff; - } else { - env->cc_src2 = 0; - return x0; + x0 = x0 < 0 ? 0x80000000: 0x7fffffff; + overflow = 1; + } + + if (cc) { + env->cc_dst = x0; + env->cc_src2 = overflow; + env->cc_op = CC_OP_DIV; } + return x0; +} + +target_ulong helper_sdiv(target_ulong a, target_ulong b) +{ + return helper_sdiv_common(a, b, 0); +} + +target_ulong helper_sdiv_cc(target_ulong a, target_ulong b) +{ + return helper_sdiv_common(a, b, 1); } void helper_stdf(target_ulong addr, int mem_idx) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 23f95191ad..21c567562e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3162,20 +3162,20 @@ static void disas_sparc_insn(DisasContext * dc) #endif case 0xe: /* udiv */ CHECK_IU_FEATURE(dc, DIV); - gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_DIV); + gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2); dc->cc_op = CC_OP_DIV; + } else { + gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2); } break; case 0xf: /* sdiv */ CHECK_IU_FEATURE(dc, DIV); - gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) { - tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_DIV); + gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2); dc->cc_op = CC_OP_DIV; + } else { + gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2); } break; default: -- cgit v1.2.3 From 6d5c34fa027d1477c0572ea74421e21b0f733838 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Fri, 31 Dec 2010 21:17:53 +0100 Subject: Fix translation of unary PPC/SPE instructions (efdneg etc.). Signed-off-by: Mike Pall Signed-off-by: Aurelien Jarno --- target-ppc/translate.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index c82a4835d4..74e06d733d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -7751,10 +7751,10 @@ static inline void gen_evfsabs(DisasContext *ctx) return; } #if defined(TARGET_PPC64) - tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL); + tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL); #else - tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000); - tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000); + tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000); + tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000); #endif } static inline void gen_evfsnabs(DisasContext *ctx) @@ -7764,10 +7764,10 @@ static inline void gen_evfsnabs(DisasContext *ctx) return; } #if defined(TARGET_PPC64) - tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL); + tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL); #else - tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); - tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); + tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); + tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); #endif } static inline void gen_evfsneg(DisasContext *ctx) @@ -7777,10 +7777,10 @@ static inline void gen_evfsneg(DisasContext *ctx) return; } #if defined(TARGET_PPC64) - tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL); + tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL); #else - tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); - tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); + tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); + tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); #endif } @@ -7832,7 +7832,7 @@ static inline void gen_efsabs(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_APU); return; } - tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL); + tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL); } static inline void gen_efsnabs(DisasContext *ctx) { @@ -7840,7 +7840,7 @@ static inline void gen_efsnabs(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_APU); return; } - tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); + tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); } static inline void gen_efsneg(DisasContext *ctx) { @@ -7848,7 +7848,7 @@ static inline void gen_efsneg(DisasContext *ctx) gen_exception(ctx, POWERPC_EXCP_APU); return; } - tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); + tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000); } /* Conversion */ @@ -7901,9 +7901,10 @@ static inline void gen_efdabs(DisasContext *ctx) return; } #if defined(TARGET_PPC64) - tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL); + tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL); #else - tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000); #endif } static inline void gen_efdnabs(DisasContext *ctx) @@ -7913,9 +7914,10 @@ static inline void gen_efdnabs(DisasContext *ctx) return; } #if defined(TARGET_PPC64) - tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL); + tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL); #else - tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); #endif } static inline void gen_efdneg(DisasContext *ctx) @@ -7925,9 +7927,10 @@ static inline void gen_efdneg(DisasContext *ctx) return; } #if defined(TARGET_PPC64) - tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL); + tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL); #else - tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000); #endif } -- cgit v1.2.3 From 8aac08b10b2e8c131b9385d2dc37e4a02e1d12c1 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 31 Dec 2010 17:50:27 +0100 Subject: target-arm: fix UMAAL instruction UMAAL should use unsigned multiply instead of signed. This patch fixes this issue by handling UMAAL separately from UMULL/UMLAL/SMULL/SMLAL as these instructions are different enough. It also explicitly list instructions in case and catch nonexistent instruction as illegal. Also fixes a few style issues. This fixes the issues reported in https://bugs.launchpad.net/qemu/+bug/696015 Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/translate.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 8d494ec924..2598268405 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6637,26 +6637,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_logic_CC(tmp); store_reg(s, rd, tmp); break; - default: - /* 64 bit mul */ + case 4: + /* 64 bit mul double accumulate (UMAAL) */ + ARCH(6); tmp = load_reg(s, rs); tmp2 = load_reg(s, rm); - if (insn & (1 << 22)) + tmp64 = gen_mulu_i64_i32(tmp, tmp2); + gen_addq_lo(s, tmp64, rn); + gen_addq_lo(s, tmp64, rd); + gen_storeq_reg(s, rn, rd, tmp64); + tcg_temp_free_i64(tmp64); + break; + case 8: case 9: case 10: case 11: + case 12: case 13: case 14: case 15: + /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */ + tmp = load_reg(s, rs); + tmp2 = load_reg(s, rm); + if (insn & (1 << 22)) { tmp64 = gen_muls_i64_i32(tmp, tmp2); - else + } else { tmp64 = gen_mulu_i64_i32(tmp, tmp2); - if (insn & (1 << 21)) /* mult accumulate */ + } + if (insn & (1 << 21)) { /* mult accumulate */ gen_addq(s, tmp64, rn, rd); - if (!(insn & (1 << 23))) { /* double accumulate */ - ARCH(6); - gen_addq_lo(s, tmp64, rn); - gen_addq_lo(s, tmp64, rd); } - if (insn & (1 << 20)) + if (insn & (1 << 20)) { gen_logicq_cc(tmp64); + } gen_storeq_reg(s, rn, rd, tmp64); tcg_temp_free_i64(tmp64); break; + default: + goto illegal_op; } } else { rn = (insn >> 16) & 0xf; -- cgit v1.2.3 From f96a38347a0c6ab31fbb6200c13e684d1fee449c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 28 Dec 2010 17:46:59 +0100 Subject: TCG: Improve tb_phys_hash_func() Most of emulated CPU have instructions aligned on 16 or 32 bits, while on others GCC tries to align the target jump location. This means that 1/2 or 3/4 of tb_phys_hash entries are never used. Update the hash function tb_phys_hash_func() to ignore the two lowest bits of the address. This brings a 6% speed-up when booting a MIPS image. Signed-off-by: Aurelien Jarno --- exec-all.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec-all.h b/exec-all.h index 6821b17943..a4b75bdbcb 100644 --- a/exec-all.h +++ b/exec-all.h @@ -177,7 +177,7 @@ static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) static inline unsigned int tb_phys_hash_func(tb_page_addr_t pc) { - return pc & (CODE_GEN_PHYS_HASH_SIZE - 1); + return (pc >> 2) & (CODE_GEN_PHYS_HASH_SIZE - 1); } TranslationBlock *tb_alloc(target_ulong pc); -- cgit v1.2.3 From 185698715dfb18c82ad2a5dbc169908602d43e81 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 17 Dec 2010 15:56:06 +0000 Subject: softfloat: Rename float*_is_nan() functions to float*_is_quiet_nan() The softfloat functions float*_is_nan() were badly misnamed, because they return true only for quiet NaNs, not for all NaNs. Rename them to float*_is_quiet_nan() to more accurately reflect what they do. This change was produced by: perl -p -i -e 's/_is_nan/_is_quiet_nan/g' $(git grep -l is_nan) (with the results manually checked.) Signed-off-by: Peter Maydell Reviewed-by: Nathan Froyd Acked-by: Edgar E. Iglesias Signed-off-by: Aurelien Jarno --- fpu/softfloat-native.c | 6 ++-- fpu/softfloat-native.h | 6 ++-- fpu/softfloat-specialize.h | 24 ++++++++-------- fpu/softfloat.h | 8 +++--- linux-user/arm/nwfpe/fpa11_cprt.c | 14 +++++----- target-alpha/op_helper.c | 2 +- target-m68k/helper.c | 6 ++-- target-microblaze/op_helper.c | 2 +- target-mips/op_helper.c | 8 +++--- target-ppc/op_helper.c | 58 +++++++++++++++++++-------------------- 10 files changed, 67 insertions(+), 67 deletions(-) diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 049c8300f5..008bb53cec 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -254,7 +254,7 @@ int float32_is_signaling_nan( float32 a1) return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); } -int float32_is_nan( float32 a1 ) +int float32_is_quiet_nan( float32 a1 ) { float32u u; uint64_t a; @@ -411,7 +411,7 @@ int float64_is_signaling_nan( float64 a1) } -int float64_is_nan( float64 a1 ) +int float64_is_quiet_nan( float64 a1 ) { float64u u; uint64_t a; @@ -504,7 +504,7 @@ int floatx80_is_signaling_nan( floatx80 a1) && ( u.i.low == aLow ); } -int floatx80_is_nan( floatx80 a1 ) +int floatx80_is_quiet_nan( floatx80 a1 ) { floatx80u u; u.f = a1; diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 6da0bcbbea..80b5f288e3 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -242,7 +242,7 @@ INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); int float32_is_signaling_nan( float32 ); -int float32_is_nan( float32 ); +int float32_is_quiet_nan( float32 ); INLINE float32 float32_abs(float32 a) { @@ -351,7 +351,7 @@ INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM) int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); int float64_is_signaling_nan( float64 ); -int float64_is_nan( float64 ); +int float64_is_quiet_nan( float64 ); INLINE float64 float64_abs(float64 a) { @@ -455,7 +455,7 @@ INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_signaling_nan( floatx80 ); -int floatx80_is_nan( floatx80 ); +int floatx80_is_quiet_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) { diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 07468786f9..f382f7a00c 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -76,7 +76,7 @@ typedef struct { | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float32_is_nan( float32 a_ ) +int float32_is_quiet_nan( float32 a_ ) { uint32_t a = float32_val(a_); #if SNAN_BIT_IS_ONE @@ -166,9 +166,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) if ( STATUS(default_nan_mode) ) return float32_default_nan; - aIsNaN = float32_is_nan( a ); + aIsNaN = float32_is_quiet_nan( a ); aIsSignalingNaN = float32_is_signaling_nan( a ); - bIsNaN = float32_is_nan( b ); + bIsNaN = float32_is_quiet_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); av = float32_val(a); bv = float32_val(b); @@ -223,7 +223,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float64_is_nan( float64 a_ ) +int float64_is_quiet_nan( float64 a_ ) { bits64 a = float64_val(a_); #if SNAN_BIT_IS_ONE @@ -320,9 +320,9 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) if ( STATUS(default_nan_mode) ) return float64_default_nan; - aIsNaN = float64_is_nan( a ); + aIsNaN = float64_is_quiet_nan( a ); aIsSignalingNaN = float64_is_signaling_nan( a ); - bIsNaN = float64_is_nan( b ); + bIsNaN = float64_is_quiet_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); av = float64_val(a); bv = float64_val(b); @@ -377,7 +377,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) | quiet NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int floatx80_is_nan( floatx80 a ) +int floatx80_is_quiet_nan( floatx80 a ) { #if SNAN_BIT_IS_ONE bits64 aLow; @@ -462,9 +462,9 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) return a; } - aIsNaN = floatx80_is_nan( a ); + aIsNaN = floatx80_is_quiet_nan( a ); aIsSignalingNaN = floatx80_is_signaling_nan( a ); - bIsNaN = floatx80_is_nan( b ); + bIsNaN = floatx80_is_quiet_nan( b ); bIsSignalingNaN = floatx80_is_signaling_nan( b ); #if SNAN_BIT_IS_ONE a.low &= ~LIT64( 0xC000000000000000 ); @@ -511,7 +511,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float128_is_nan( float128 a ) +int float128_is_quiet_nan( float128 a ) { #if SNAN_BIT_IS_ONE return @@ -588,9 +588,9 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) return a; } - aIsNaN = float128_is_nan( a ); + aIsNaN = float128_is_quiet_nan( a ); aIsSignalingNaN = float128_is_signaling_nan( a ); - bIsNaN = float128_is_nan( b ); + bIsNaN = float128_is_quiet_nan( b ); bIsSignalingNaN = float128_is_signaling_nan( b ); #if SNAN_BIT_IS_ONE a.high &= ~LIT64( 0x0000800000000000 ); diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 1c1004de97..1f37877dbf 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -287,7 +287,7 @@ int float32_le_quiet( float32, float32 STATUS_PARAM ); int float32_lt_quiet( float32, float32 STATUS_PARAM ); int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); -int float32_is_nan( float32 ); +int float32_is_quiet_nan( float32 ); int float32_is_signaling_nan( float32 ); float32 float32_maybe_silence_nan( float32 ); float32 float32_scalbn( float32, int STATUS_PARAM ); @@ -367,7 +367,7 @@ int float64_le_quiet( float64, float64 STATUS_PARAM ); int float64_lt_quiet( float64, float64 STATUS_PARAM ); int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); -int float64_is_nan( float64 a ); +int float64_is_quiet_nan( float64 a ); int float64_is_signaling_nan( float64 ); float64 float64_maybe_silence_nan( float64 ); float64 float64_scalbn( float64, int STATUS_PARAM ); @@ -437,7 +437,7 @@ int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); -int floatx80_is_nan( floatx80 ); +int floatx80_is_quiet_nan( floatx80 ); int floatx80_is_signaling_nan( floatx80 ); floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM ); @@ -503,7 +503,7 @@ int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); int float128_compare( float128, float128 STATUS_PARAM ); int float128_compare_quiet( float128, float128 STATUS_PARAM ); -int float128_is_nan( float128 ); +int float128_is_quiet_nan( float128 ); int float128_is_signaling_nan( float128 ); float128 float128_scalbn( float128, int STATUS_PARAM ); diff --git a/linux-user/arm/nwfpe/fpa11_cprt.c b/linux-user/arm/nwfpe/fpa11_cprt.c index 5d64591251..0e61b585a0 100644 --- a/linux-user/arm/nwfpe/fpa11_cprt.c +++ b/linux-user/arm/nwfpe/fpa11_cprt.c @@ -199,21 +199,21 @@ static unsigned int PerformComparison(const unsigned int opcode) { case typeSingle: //printk("single.\n"); - if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) + if (float32_is_quiet_nan(fpa11->fpreg[Fn].fSingle)) goto unordered; rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeDouble: //printk("double.\n"); - if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) + if (float64_is_quiet_nan(fpa11->fpreg[Fn].fDouble)) goto unordered; rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; case typeExtended: //printk("extended.\n"); - if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) + if (floatx80_is_quiet_nan(fpa11->fpreg[Fn].fExtended)) goto unordered; rFn = fpa11->fpreg[Fn].fExtended; break; @@ -225,7 +225,7 @@ static unsigned int PerformComparison(const unsigned int opcode) { //printk("Fm is a constant: #%d.\n",Fm); rFm = getExtendedConstant(Fm); - if (floatx80_is_nan(rFm)) + if (floatx80_is_quiet_nan(rFm)) goto unordered; } else @@ -235,21 +235,21 @@ static unsigned int PerformComparison(const unsigned int opcode) { case typeSingle: //printk("single.\n"); - if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) + if (float32_is_quiet_nan(fpa11->fpreg[Fm].fSingle)) goto unordered; rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); break; case typeDouble: //printk("double.\n"); - if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) + if (float64_is_quiet_nan(fpa11->fpreg[Fm].fDouble)) goto unordered; rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; case typeExtended: //printk("extended.\n"); - if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) + if (floatx80_is_quiet_nan(fpa11->fpreg[Fm].fExtended)) goto unordered; rFm = fpa11->fpreg[Fm].fExtended; break; diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index ff5ae26abe..6c2ae2061f 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -904,7 +904,7 @@ uint64_t helper_cmptun (uint64_t a, uint64_t b) fa = t_to_float64(a); fb = t_to_float64(b); - if (float64_is_nan(fa) || float64_is_nan(fb)) + if (float64_is_quiet_nan(fa) || float64_is_quiet_nan(fb)) return 0x4000000000000000ULL; else return 0; diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 56de897c1d..514b03904f 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -614,10 +614,10 @@ float64 HELPER(sub_cmp_f64)(CPUState *env, float64 a, float64 b) /* ??? Should flush denormals to zero. */ float64 res; res = float64_sub(a, b, &env->fp_status); - if (float64_is_nan(res)) { + if (float64_is_quiet_nan(res)) { /* +/-inf compares equal against itself, but sub returns nan. */ - if (!float64_is_nan(a) - && !float64_is_nan(b)) { + if (!float64_is_quiet_nan(a) + && !float64_is_quiet_nan(b)) { res = float64_zero; if (float64_lt_quiet(a, res, &env->fp_status)) res = float64_chs(res); diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c index 3d2b313fb3..97461aed6e 100644 --- a/target-microblaze/op_helper.c +++ b/target-microblaze/op_helper.c @@ -308,7 +308,7 @@ uint32_t helper_fcmp_un(uint32_t a, uint32_t b) r = 1; } - if (float32_is_nan(fa.f) || float32_is_nan(fb.f)) { + if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) { r = 1; } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index ec6864d903..669faf17ae 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2877,10 +2877,10 @@ static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) { if (float64_is_signaling_nan(a) || float64_is_signaling_nan(b) || - (sig && (float64_is_nan(a) || float64_is_nan(b)))) { + (sig && (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)))) { float_raise(float_flag_invalid, status); return 1; - } else if (float64_is_nan(a) || float64_is_nan(b)) { + } else if (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)) { return 1; } else { return 0; @@ -2935,10 +2935,10 @@ static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) { if (float32_is_signaling_nan(a) || float32_is_signaling_nan(b) || - (sig && (float32_is_nan(a) || float32_is_nan(b)))) { + (sig && (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)))) { float_raise(float_flag_invalid, status); return 1; - } else if (float32_is_nan(a) || float32_is_nan(b)) { + } else if (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)) { return 1; } else { return 0; diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index f32a5fffd6..5ded1c133f 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -546,7 +546,7 @@ uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf) int ret; farg.ll = arg; isneg = float64_is_neg(farg.d); - if (unlikely(float64_is_nan(farg.d))) { + if (unlikely(float64_is_quiet_nan(farg.d))) { if (float64_is_signaling_nan(farg.d)) { /* Signaling NaN: flags are undefined */ ret = 0x00; @@ -1111,7 +1111,7 @@ uint64_t helper_fctiw (uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) { + } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1135,7 +1135,7 @@ uint64_t helper_fctiwz (uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) { + } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1168,7 +1168,7 @@ uint64_t helper_fctid (uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) { + } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1186,7 +1186,7 @@ uint64_t helper_fctidz (uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) { + } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity conversion */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1205,7 +1205,7 @@ static inline uint64_t do_fri(uint64_t arg, int rounding_mode) if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN round */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI); - } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) { + } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) { /* qNan / infinity round */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { @@ -1375,7 +1375,7 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status); #endif - if (likely(!float64_is_nan(farg1.d))) + if (likely(!float64_is_quiet_nan(farg1.d))) farg1.d = float64_chs(farg1.d); } return farg1.ll; @@ -1425,7 +1425,7 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status); #endif - if (likely(!float64_is_nan(farg1.d))) + if (likely(!float64_is_quiet_nan(farg1.d))) farg1.d = float64_chs(farg1.d); } return farg1.ll; @@ -1533,7 +1533,7 @@ uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg1.ll = arg1; - if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d)) + if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_quiet_nan(farg1.d)) return arg2; else return arg3; @@ -1546,8 +1546,8 @@ void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD) farg1.ll = arg1; farg2.ll = arg2; - if (unlikely(float64_is_nan(farg1.d) || - float64_is_nan(farg2.d))) { + if (unlikely(float64_is_quiet_nan(farg1.d) || + float64_is_quiet_nan(farg2.d))) { ret = 0x01UL; } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { ret = 0x08UL; @@ -1575,8 +1575,8 @@ void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD) farg1.ll = arg1; farg2.ll = arg2; - if (unlikely(float64_is_nan(farg1.d) || - float64_is_nan(farg2.d))) { + if (unlikely(float64_is_quiet_nan(farg1.d) || + float64_is_quiet_nan(farg2.d))) { ret = 0x01UL; } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { ret = 0x08UL; @@ -1938,7 +1938,7 @@ target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_ /* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise, * execute the following block. */ #define DO_HANDLE_NAN(result, x) \ - if (float32_is_nan(x) || float32_is_signaling_nan(x)) { \ + if (float32_is_quiet_nan(x) || float32_is_signaling_nan(x)) { \ CPU_FloatU __f; \ __f.f = x; \ __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \ @@ -2283,7 +2283,7 @@ void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) float_status s = env->vec_status; \ set_float_rounding_mode(float_round_to_zero, &s); \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - if (float32_is_nan(b->f[i]) || \ + if (float32_is_quiet_nan(b->f[i]) || \ float32_is_signaling_nan(b->f[i])) { \ r->element[i] = 0; \ } else { \ @@ -3132,7 +3132,7 @@ static inline int32_t efsctsi(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) return 0; return float32_to_int32(u.f, &env->vec_status); @@ -3144,7 +3144,7 @@ static inline uint32_t efsctui(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) return 0; return float32_to_uint32(u.f, &env->vec_status); @@ -3156,7 +3156,7 @@ static inline uint32_t efsctsiz(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) return 0; return float32_to_int32_round_to_zero(u.f, &env->vec_status); @@ -3168,7 +3168,7 @@ static inline uint32_t efsctuiz(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) return 0; return float32_to_uint32_round_to_zero(u.f, &env->vec_status); @@ -3205,7 +3205,7 @@ static inline uint32_t efsctsf(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) return 0; tmp = uint64_to_float32(1ULL << 32, &env->vec_status); u.f = float32_mul(u.f, tmp, &env->vec_status); @@ -3220,7 +3220,7 @@ static inline uint32_t efsctuf(uint32_t val) u.l = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float32_is_nan(u.f))) + if (unlikely(float32_is_quiet_nan(u.f))) return 0; tmp = uint64_to_float32(1ULL << 32, &env->vec_status); u.f = float32_mul(u.f, tmp, &env->vec_status); @@ -3474,7 +3474,7 @@ uint32_t helper_efdctsi (uint64_t val) u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_nan(u.d))) + if (unlikely(float64_is_quiet_nan(u.d))) return 0; return float64_to_int32(u.d, &env->vec_status); @@ -3486,7 +3486,7 @@ uint32_t helper_efdctui (uint64_t val) u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_nan(u.d))) + if (unlikely(float64_is_quiet_nan(u.d))) return 0; return float64_to_uint32(u.d, &env->vec_status); @@ -3498,7 +3498,7 @@ uint32_t helper_efdctsiz (uint64_t val) u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_nan(u.d))) + if (unlikely(float64_is_quiet_nan(u.d))) return 0; return float64_to_int32_round_to_zero(u.d, &env->vec_status); @@ -3510,7 +3510,7 @@ uint64_t helper_efdctsidz (uint64_t val) u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_nan(u.d))) + if (unlikely(float64_is_quiet_nan(u.d))) return 0; return float64_to_int64_round_to_zero(u.d, &env->vec_status); @@ -3522,7 +3522,7 @@ uint32_t helper_efdctuiz (uint64_t val) u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_nan(u.d))) + if (unlikely(float64_is_quiet_nan(u.d))) return 0; return float64_to_uint32_round_to_zero(u.d, &env->vec_status); @@ -3534,7 +3534,7 @@ uint64_t helper_efdctuidz (uint64_t val) u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_nan(u.d))) + if (unlikely(float64_is_quiet_nan(u.d))) return 0; return float64_to_uint64_round_to_zero(u.d, &env->vec_status); @@ -3571,7 +3571,7 @@ uint32_t helper_efdctsf (uint64_t val) u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_nan(u.d))) + if (unlikely(float64_is_quiet_nan(u.d))) return 0; tmp = uint64_to_float64(1ULL << 32, &env->vec_status); u.d = float64_mul(u.d, tmp, &env->vec_status); @@ -3586,7 +3586,7 @@ uint32_t helper_efdctuf (uint64_t val) u.ll = val; /* NaN are not treated the same way IEEE 754 does */ - if (unlikely(float64_is_nan(u.d))) + if (unlikely(float64_is_quiet_nan(u.d))) return 0; tmp = uint64_to_float64(1ULL << 32, &env->vec_status); u.d = float64_mul(u.d, tmp, &env->vec_status); -- cgit v1.2.3 From 354f211b1a49a7387929e22d6e63849fcba48f8a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 16 Dec 2010 11:51:17 +0000 Subject: softfloat: abstract out target-specific NaN propagation rules IEEE754 doesn't specify precisely what NaN should be returned as the result of an operation on two input NaNs. This is therefore target-specific. Abstract out the code in propagateFloat*NaN() which was implementing the x87 propagation rules, so that it can be easily replaced on a per-target basis. Signed-off-by: Peter Maydell Signed-off-by: Aurelien Jarno --- fpu/softfloat-specialize.h | 160 ++++++++++++++++++++++++++++----------------- 1 file changed, 100 insertions(+), 60 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index f382f7a00c..8dcf469ee6 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -152,6 +152,52 @@ static float32 commonNaNToFloat32( commonNaNT a ) return float32_default_nan; } +/*---------------------------------------------------------------------------- +| Select which NaN to propagate for a two-input operation. +| IEEE754 doesn't specify all the details of this, so the +| algorithm is target-specific. +| The routine is passed various bits of information about the +| two NaNs and should return 0 to select NaN a and 1 for NaN b. +| Note that signalling NaNs are always squashed to quiet NaNs +| by the caller, by flipping the SNaN bit before returning them. +| +| aIsLargerSignificand is only valid if both a and b are NaNs +| of some kind, and is true if a has the larger significand, +| or if both a and b have the same significand but a is +| positive but b is negative. It is only needed for the x87 +| tie-break rule. +*----------------------------------------------------------------------------*/ + +static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, + flag aIsLargerSignificand) +{ + /* This implements x87 NaN propagation rules: + * SNaN + QNaN => return the QNaN + * two SNaNs => return the one with the larger significand, silenced + * two QNaNs => return the one with the larger significand + * SNaN and a non-NaN => return the SNaN, silenced + * QNaN and a non-NaN => return the QNaN + * + * If we get down to comparing significands and they are the same, + * return the NaN with the positive sign bit (if any). + */ + if (aIsSNaN) { + if (bIsSNaN) { + return aIsLargerSignificand ? 0 : 1; + } + return bIsQNaN ? 1 : 0; + } + else if (aIsQNaN) { + if (bIsSNaN || !bIsQNaN) + return 0; + else { + return aIsLargerSignificand ? 0 : 1; + } + } else { + return 1; + } +} + /*---------------------------------------------------------------------------- | Takes two single-precision floating-point values `a' and `b', one of which | is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a @@ -160,7 +206,7 @@ static float32 commonNaNToFloat32( commonNaNT a ) static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand; bits32 av, bv, res; if ( STATUS(default_nan_mode) ) @@ -180,26 +226,22 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) bv |= 0x00400000; #endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); - if ( aIsSignalingNaN ) { - if ( bIsSignalingNaN ) goto returnLargerSignificand; - res = bIsNaN ? bv : av; - } - else if ( aIsNaN ) { - if ( bIsSignalingNaN || ! bIsNaN ) - res = av; - else { - returnLargerSignificand: - if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) ) - res = bv; - else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) ) - res = av; - else - res = ( av < bv ) ? av : bv; - } + + if ((bits32)(av<<1) < (bits32)(bv<<1)) { + aIsLargerSignificand = 0; + } else if ((bits32)(bv<<1) < (bits32)(av<<1)) { + aIsLargerSignificand = 1; + } else { + aIsLargerSignificand = (av < bv) ? 1 : 0; } - else { + + if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, + aIsLargerSignificand)) { res = bv; + } else { + res = av; } + return make_float32(res); } @@ -314,7 +356,7 @@ static float64 commonNaNToFloat64( commonNaNT a ) static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand; bits64 av, bv, res; if ( STATUS(default_nan_mode) ) @@ -334,26 +376,22 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) bv |= LIT64( 0x0008000000000000 ); #endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); - if ( aIsSignalingNaN ) { - if ( bIsSignalingNaN ) goto returnLargerSignificand; - res = bIsNaN ? bv : av; - } - else if ( aIsNaN ) { - if ( bIsSignalingNaN || ! bIsNaN ) - res = av; - else { - returnLargerSignificand: - if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) ) - res = bv; - else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) ) - res = av; - else - res = ( av < bv ) ? av : bv; - } + + if ((bits64)(av<<1) < (bits64)(bv<<1)) { + aIsLargerSignificand = 0; + } else if ((bits64)(bv<<1) < (bits64)(av<<1)) { + aIsLargerSignificand = 1; + } else { + aIsLargerSignificand = (av < bv) ? 1 : 0; } - else { + + if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, + aIsLargerSignificand)) { res = bv; + } else { + res = av; } + return make_float64(res); } @@ -454,7 +492,7 @@ static floatx80 commonNaNToFloatx80( commonNaNT a ) static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand; if ( STATUS(default_nan_mode) ) { a.low = floatx80_default_nan_low; @@ -474,19 +512,20 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) b.low |= LIT64( 0xC000000000000000 ); #endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); - if ( aIsSignalingNaN ) { - if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; - } - else if ( aIsNaN ) { - if ( bIsSignalingNaN || ! bIsNaN ) return a; - returnLargerSignificand: - if ( a.low < b.low ) return b; - if ( b.low < a.low ) return a; - return ( a.high < b.high ) ? a : b; + + if (a.low < b.low) { + aIsLargerSignificand = 0; + } else if (b.low < a.low) { + aIsLargerSignificand = 1; + } else { + aIsLargerSignificand = (a.high < b.high) ? 1 : 0; } - else { + + if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, + aIsLargerSignificand)) { return b; + } else { + return a; } } @@ -580,7 +619,7 @@ static float128 commonNaNToFloat128( commonNaNT a ) static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand; if ( STATUS(default_nan_mode) ) { a.low = float128_default_nan_low; @@ -600,19 +639,20 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) b.high |= LIT64( 0x0000800000000000 ); #endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); - if ( aIsSignalingNaN ) { - if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; - } - else if ( aIsNaN ) { - if ( bIsSignalingNaN || ! bIsNaN ) return a; - returnLargerSignificand: - if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b; - if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a; - return ( a.high < b.high ) ? a : b; + + if (lt128(a.high<<1, a.low, b.high<<1, b.low)) { + aIsLargerSignificand = 0; + } else if (lt128(b.high<<1, b.low, a.high<<1, a.low)) { + aIsLargerSignificand = 1; + } else { + aIsLargerSignificand = (a.high < b.high) ? 1 : 0; } - else { + + if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, + aIsLargerSignificand)) { return b; + } else { + return a; } } -- cgit v1.2.3 From 011da610ba6416df54feed46bcde1955211a2149 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 16 Dec 2010 11:51:18 +0000 Subject: target-arm: Implement correct NaN propagation rules Implement the correct NaN propagation rules for ARM targets by providing an appropriate pickNaN function. Signed-off-by: Peter Maydell Signed-off-by: Aurelien Jarno --- fpu/softfloat-specialize.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 8dcf469ee6..f43f2d0ace 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -168,6 +168,28 @@ static float32 commonNaNToFloat32( commonNaNT a ) | tie-break rule. *----------------------------------------------------------------------------*/ +#if defined(TARGET_ARM) +static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, + flag aIsLargerSignificand) +{ + /* ARM mandated NaN propagation rules: take the first of: + * 1. A if it is signaling + * 2. B if it is signaling + * 3. A (quiet) + * 4. B (quiet) + * A signaling NaN is always quietened before returning it. + */ + if (aIsSNaN) { + return 0; + } else if (bIsSNaN) { + return 1; + } else if (aIsQNaN) { + return 0; + } else { + return 1; + } +} +#else static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, flag aIsLargerSignificand) { @@ -197,6 +219,7 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, return 1; } } +#endif /*---------------------------------------------------------------------------- | Takes two single-precision floating-point values `a' and `b', one of which -- cgit v1.2.3 From 8a7d0890acd03f45f1d86e12449938891ae18ed9 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 4 Jan 2011 01:48:55 +0100 Subject: noaudio: correctly account acquired samples This will fix the return value of the function which otherwise returns too many samples because sw->total_hw_samples_acquired isn't correctly accounted. Signed-off-by: Michael Walle Signed-off-by: malc --- audio/noaudio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/audio/noaudio.c b/audio/noaudio.c index 80158583b2..0304094a6e 100644 --- a/audio/noaudio.c +++ b/audio/noaudio.c @@ -117,9 +117,12 @@ static int no_run_in (HWVoiceIn *hw) static int no_read (SWVoiceIn *sw, void *buf, int size) { + /* use custom code here instead of audio_pcm_sw_read() to avoid + * useless resampling/mixing */ int samples = size >> sw->info.shift; int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; int to_clear = audio_MIN (samples, total); + sw->total_hw_samples_acquired += total; audio_pcm_info_clear_buf (&sw->info, buf, to_clear); return to_clear << sw->info.shift; } -- cgit v1.2.3 From 9ae19b657ee20f4d03bdca8dbf367b932801ac93 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 4 Jan 2011 21:58:24 +0100 Subject: Fix curses on big endian hosts On big endian hosts, the curses interface is unusable: the emulated graphic card only displays garbage, while the monitor interface displays nothing (or rather only spaces). The curses interface is waiting for data in native endianness, so console_write_ch() should not do any conversion. The conversion should be done when reading the video buffer in hw/vga.c. I supposed this buffer is in little endian mode, though it's not impossible that the data is actually in guest endianness. I currently have no big endian guest to way (they all switch to graphic mode immediately). Signed-off-by: Aurelien Jarno --- console.h | 2 +- hw/vga.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/console.h b/console.h index b2fc908549..3157330eb2 100644 --- a/console.h +++ b/console.h @@ -329,7 +329,7 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch) { if (!(ch & 0xff)) ch |= ' '; - cpu_to_le32wu((uint32_t *) dest, ch); + *dest = ch; } typedef void (*vga_hw_update_ptr)(void *); diff --git a/hw/vga.c b/hw/vga.c index c632fd77e1..e2151a2458 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -2073,14 +2073,14 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) if (full_update) { for (i = 0; i < size; src ++, dst ++, i ++) - console_write_ch(dst, VMEM2CHTYPE(*src)); + console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src))); dpy_update(s->ds, 0, 0, width, height); } else { c_max = 0; for (i = 0; i < size; src ++, dst ++, i ++) { - console_write_ch(&val, VMEM2CHTYPE(*src)); + console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src))); if (*dst != val) { *dst = val; c_max = i; @@ -2089,7 +2089,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) } c_min = i; for (; i < size; src ++, dst ++, i ++) { - console_write_ch(&val, VMEM2CHTYPE(*src)); + console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src))); if (*dst != val) { *dst = val; c_max = i; -- cgit v1.2.3 From 92d675d1c1f23f3617e24b63c825074a1d1da44b Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 4 Jan 2011 21:58:24 +0100 Subject: cirrus_vga: fix division by 0 for color expansion rop Commit d85d0d3883f5a567fa2969a0396e42e0a662b3fa introduces a regression with Windows ME that leads to a division by 0 and a crash. It uses the color expansion rop with the source pitch set to 0. This is something allowed, as the manual explicitely says "When the source of color-expand data is display memory, the source pitch is ignored.". This patch fixes this regression by computing sx, sy and others variables only if they are going to be used later, that is for a plain copy ROP. It basically consists in moving code. Signed-off-by: Aurelien Jarno --- hw/cirrus_vga.c | 65 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 4f5040cf4b..199136ce7d 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -675,43 +675,44 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) { int sx, sy; int dx, dy; - int width, height; int depth; int notify = 0; - depth = s->vga.get_bpp(&s->vga) / 8; - s->vga.get_resolution(&s->vga, &width, &height); - - /* extra x, y */ - sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth; - sy = (src / ABS(s->cirrus_blt_srcpitch)); - dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth; - dy = (dst / ABS(s->cirrus_blt_dstpitch)); - - /* normalize width */ - w /= depth; - - /* if we're doing a backward copy, we have to adjust - our x/y to be the upper left corner (instead of the lower - right corner) */ - if (s->cirrus_blt_dstpitch < 0) { - sx -= (s->cirrus_blt_width / depth) - 1; - dx -= (s->cirrus_blt_width / depth) - 1; - sy -= s->cirrus_blt_height - 1; - dy -= s->cirrus_blt_height - 1; - } + /* make sure to only copy if it's a plain copy ROP */ + if (*s->cirrus_rop == cirrus_bitblt_rop_fwd_src || + *s->cirrus_rop == cirrus_bitblt_rop_bkwd_src) { - /* are we in the visible portion of memory? */ - if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 && - (sx + w) <= width && (sy + h) <= height && - (dx + w) <= width && (dy + h) <= height) { - notify = 1; - } + int width, height; + + depth = s->vga.get_bpp(&s->vga) / 8; + s->vga.get_resolution(&s->vga, &width, &height); + + /* extra x, y */ + sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth; + sy = (src / ABS(s->cirrus_blt_srcpitch)); + dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth; + dy = (dst / ABS(s->cirrus_blt_dstpitch)); - /* make to sure only copy if it's a plain copy ROP */ - if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src && - *s->cirrus_rop != cirrus_bitblt_rop_bkwd_src) - notify = 0; + /* normalize width */ + w /= depth; + + /* if we're doing a backward copy, we have to adjust + our x/y to be the upper left corner (instead of the lower + right corner) */ + if (s->cirrus_blt_dstpitch < 0) { + sx -= (s->cirrus_blt_width / depth) - 1; + dx -= (s->cirrus_blt_width / depth) - 1; + sy -= s->cirrus_blt_height - 1; + dy -= s->cirrus_blt_height - 1; + } + + /* are we in the visible portion of memory? */ + if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 && + (sx + w) <= width && (sy + h) <= height && + (dx + w) <= width && (dy + h) <= height) { + notify = 1; + } + } /* we have to flush all pending changes so that the copy is generated at the appropriate moment in time */ -- cgit v1.2.3 From 23979dc5411befabe9049e37075b2b6320debc4e Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 5 Jan 2011 02:21:19 +0100 Subject: microblaze: Use more TB chaining For some workloads with tight loops this ~doubles the emulation speed. Signed-off-by: Edgar E. Iglesias --- target-microblaze/translate.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 1ada15e19d..c018c99826 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -752,9 +752,8 @@ static void dec_bit(DisasContext *dc) static inline void sync_jmpstate(DisasContext *dc) { if (dc->jmp == JMP_DIRECT) { - dc->jmp = JMP_INDIRECT; - tcg_gen_movi_tl(env_btaken, 1); - tcg_gen_movi_tl(env_btarget, dc->jmp_pc); + dc->jmp = JMP_INDIRECT; + tcg_gen_movi_tl(env_btarget, dc->jmp_pc); } } @@ -976,11 +975,13 @@ static void dec_bcc(DisasContext *dc) int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */ tcg_gen_movi_tl(env_btarget, dc->pc + offset); + dc->jmp = JMP_DIRECT; + dc->jmp_pc = dc->pc + offset; } else { + dc->jmp = JMP_INDIRECT; tcg_gen_movi_tl(env_btarget, dc->pc); tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc))); } - dc->jmp = JMP_INDIRECT; eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0)); } @@ -1028,6 +1029,7 @@ static void dec_br(DisasContext *dc) if (dec_alu_op_b_is_small_imm(dc)) { dc->jmp = JMP_DIRECT; dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm); + tcg_gen_movi_tl(env_btaken, 1); } else { tcg_gen_movi_tl(env_btaken, 1); tcg_gen_movi_tl(env_btarget, dc->pc); @@ -1130,6 +1132,7 @@ static void dec_rts(DisasContext *dc) } else LOG_DIS("rts ir=%x\n", dc->ir); + dc->jmp = JMP_INDIRECT; tcg_gen_movi_tl(env_btaken, 1); tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc))); } @@ -1370,6 +1373,9 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, dc->is_jmp = DISAS_NEXT; dc->jmp = 0; dc->delayed_branch = !!(dc->tb_flags & D_FLAG); + if (dc->delayed_branch) { + dc->jmp = JMP_INDIRECT; + } dc->pc = pc_start; dc->singlestep_enabled = env->singlestep_enabled; dc->cpustate_changed = 0; @@ -1441,9 +1447,21 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, /* Clear the delay slot flag. */ dc->tb_flags &= ~D_FLAG; /* If it is a direct jump, try direct chaining. */ - if (dc->jmp != JMP_DIRECT) { + if (dc->jmp == JMP_INDIRECT) { eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc)); dc->is_jmp = DISAS_JUMP; + } else if (dc->jmp == JMP_DIRECT) { + int l1; + + t_sync_flags(dc); + l1 = gen_new_label(); + /* Conditional jmp. */ + tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1); + gen_goto_tb(dc, 1, dc->pc); + gen_set_label(l1); + gen_goto_tb(dc, 0, dc->jmp_pc); + + dc->is_jmp = DISAS_TB_JUMP; } break; } -- cgit v1.2.3 From dd94ad96e51457d8d9562a73659734b559d2f4b1 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:18 +0100 Subject: target-ppc: remove PRECISE_EMULATION define The PRECISE_EMULATION is "hardcoded" to one in target-ppc/exec.h and not something easily tunable. Remove it and non-precise emulation code as it doesn't make a noticeable difference in speed. People wanting speed improvement should use softfloat-native instead. Acked-by: Alexander Graf Signed-off-by: Aurelien Jarno --- target-ppc/exec.h | 3 --- target-ppc/op_helper.c | 58 ++++++++++---------------------------------------- 2 files changed, 11 insertions(+), 50 deletions(-) diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 44cc5e987e..4688ef5710 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -26,9 +26,6 @@ #include "cpu.h" #include "exec-all.h" -/* Precise emulation is needed to correctly emulate exception flags */ -#define USE_PRECISE_EMULATION 1 - register struct CPUPPCState *env asm(AREG0); #if !defined(CONFIG_USER_ONLY) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5ded1c133f..31520ab639 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -974,7 +974,7 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2) farg1.ll = arg1; farg2.ll = arg2; -#if USE_PRECISE_EMULATION + if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d))) { /* sNaN addition */ @@ -986,9 +986,7 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2) } else { farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); } -#else - farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); -#endif + return farg1.ll; } @@ -999,8 +997,7 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2) farg1.ll = arg1; farg2.ll = arg2; -#if USE_PRECISE_EMULATION -{ + if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d))) { /* sNaN subtraction */ @@ -1012,10 +1009,7 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2) } else { farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); } -} -#else - farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); -#endif + return farg1.ll; } @@ -1026,7 +1020,7 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2) farg1.ll = arg1; farg2.ll = arg2; -#if USE_PRECISE_EMULATION + if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d))) { /* sNaN multiplication */ @@ -1038,9 +1032,7 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2) } else { farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); } -#else - farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); -#endif + return farg1.ll; } @@ -1051,7 +1043,7 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2) farg1.ll = arg1; farg2.ll = arg2; -#if USE_PRECISE_EMULATION + if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d))) { /* sNaN division */ @@ -1065,9 +1057,7 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2) } else { farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); } -#else - farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); -#endif + return farg1.ll; } @@ -1116,12 +1106,10 @@ uint64_t helper_fctiw (uint64_t arg) farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { farg.ll = float64_to_int32(farg.d, &env->fp_status); -#if USE_PRECISE_EMULATION /* XXX: higher bits are not supposed to be significant. * to make tests easier, return the same as a real PowerPC 750 */ farg.ll |= 0xFFF80000ULL << 32; -#endif } return farg.ll; } @@ -1140,12 +1128,10 @@ uint64_t helper_fctiwz (uint64_t arg) farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI); } else { farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status); -#if USE_PRECISE_EMULATION /* XXX: higher bits are not supposed to be significant. * to make tests easier, return the same as a real PowerPC 750 */ farg.ll |= 0xFFF80000ULL << 32; -#endif } return farg.ll; } @@ -1245,7 +1231,7 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg1.ll = arg1; farg2.ll = arg2; farg3.ll = arg3; -#if USE_PRECISE_EMULATION + if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d) || float64_is_signaling_nan(farg3.d))) { @@ -1277,10 +1263,7 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg1.d = (farg1.d * farg2.d) + farg3.d; #endif } -#else - farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); - farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status); -#endif + return farg1.ll; } @@ -1292,7 +1275,7 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg1.ll = arg1; farg2.ll = arg2; farg3.ll = arg3; -#if USE_PRECISE_EMULATION + if (unlikely(float64_is_signaling_nan(farg1.d) || float64_is_signaling_nan(farg2.d) || float64_is_signaling_nan(farg3.d))) { @@ -1324,10 +1307,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) farg1.d = (farg1.d * farg2.d) - farg3.d; #endif } -#else - farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); - farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status); -#endif return farg1.ll; } @@ -1350,7 +1329,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { -#if USE_PRECISE_EMULATION #ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1370,10 +1348,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3) #else /* This is OK on x86 hosts */ farg1.d = (farg1.d * farg2.d) + farg3.d; -#endif -#else - farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); - farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status); #endif if (likely(!float64_is_quiet_nan(farg1.d))) farg1.d = float64_chs(farg1.d); @@ -1400,7 +1374,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) /* Multiplication of zero by infinity */ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ); } else { -#if USE_PRECISE_EMULATION #ifdef FLOAT128 /* This is the way the PowerPC specification defines it */ float128 ft0_128, ft1_128; @@ -1420,10 +1393,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3) #else /* This is OK on x86 hosts */ farg1.d = (farg1.d * farg2.d) - farg3.d; -#endif -#else - farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); - farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status); #endif if (likely(!float64_is_quiet_nan(farg1.d))) farg1.d = float64_chs(farg1.d); @@ -1438,7 +1407,6 @@ uint64_t helper_frsp (uint64_t arg) float32 f32; farg.ll = arg; -#if USE_PRECISE_EMULATION if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN square root */ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN); @@ -1446,10 +1414,6 @@ uint64_t helper_frsp (uint64_t arg) f32 = float64_to_float32(farg.d, &env->fp_status); farg.d = float32_to_float64(f32, &env->fp_status); } -#else - f32 = float64_to_float32(farg.d, &env->fp_status); - farg.d = float32_to_float64(f32, &env->fp_status); -#endif return farg.ll; } -- cgit v1.2.3 From 3eb28bbd472c0d4e3182421c4af7043afa059903 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:18 +0100 Subject: target-ppc: fix default qNaN On PPC the default qNaN doesn't have the sign bit set. Acked-by: Alexander Graf Signed-off-by: Aurelien Jarno --- target-ppc/op_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 31520ab639..c69ffc96b1 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -643,7 +643,7 @@ static inline uint64_t fload_invalid_op_excp(int op) env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); if (ve == 0) { /* Set the result to quiet NaN */ - ret = 0xFFF8000000000000ULL; + ret = 0x7FF8000000000000ULL; env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr |= 0x11 << FPSCR_FPCC; } @@ -654,7 +654,7 @@ static inline uint64_t fload_invalid_op_excp(int op) env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); if (ve == 0) { /* Set the result to quiet NaN */ - ret = 0xFFF8000000000000ULL; + ret = 0x7FF8000000000000ULL; env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr |= 0x11 << FPSCR_FPCC; } -- cgit v1.2.3 From 82b323cd296a079caf818c8c97eab3b4673cad29 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:18 +0100 Subject: target-ppc: use float32_is_any_nan() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new function float32_is_any_nan() instead of float32_is_quiet_nan() || float32_is_signaling_nan(). Acked-by: Alexander Graf Signed-off-by: Aurelien Jarno --- target-ppc/op_helper.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index c69ffc96b1..279f345593 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1902,7 +1902,7 @@ target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_ /* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise, * execute the following block. */ #define DO_HANDLE_NAN(result, x) \ - if (float32_is_quiet_nan(x) || float32_is_signaling_nan(x)) { \ + if (float32_is_any_nan(x)) { \ CPU_FloatU __f; \ __f.f = x; \ __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \ @@ -2247,8 +2247,7 @@ void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) float_status s = env->vec_status; \ set_float_rounding_mode(float_round_to_zero, &s); \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - if (float32_is_quiet_nan(b->f[i]) || \ - float32_is_signaling_nan(b->f[i])) { \ + if (float32_is_any_nan(b->f[i])) { \ r->element[i] = 0; \ } else { \ float64 t = float32_to_float64(b->f[i], &s); \ -- cgit v1.2.3 From 34d23861989a2901fa76385940817cc94072c721 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:19 +0100 Subject: softfloat: remove HPPA specific code We don't have any HPPA target, so let's remove HPPA specific code. It can be re-added when someone adds an HPPA target. This has been blessed by Stuart Brady , author of the target-hppa fork. Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- fpu/softfloat-specialize.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index f43f2d0ace..5da3a85355 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -30,7 +30,7 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) +#if defined(TARGET_MIPS) #define SNAN_BIT_IS_ONE 1 #else #define SNAN_BIT_IS_ONE 0 @@ -63,8 +63,6 @@ typedef struct { #define float32_default_nan make_float32(0x7FFFFFFF) #elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) #define float32_default_nan make_float32(0x7FC00000) -#elif defined(TARGET_HPPA) -#define float32_default_nan make_float32(0x7FA00000) #elif SNAN_BIT_IS_ONE #define float32_default_nan make_float32(0x7FBFFFFF) #else @@ -275,8 +273,6 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) #define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) #elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) #define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) -#elif defined(TARGET_HPPA) -#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 )) #elif SNAN_BIT_IS_ONE #define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) #else -- cgit v1.2.3 From d735d695e7b547272412f63433e023496c4d36ed Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:19 +0100 Subject: softfloat: rename *IsNaN variables to *IsQuietNaN Similarly to what has been done in commit 185698715dfb18c82ad2a5dbc169908602d43e81 rename the misnamed *IsNaN variables into *IsQuietNaN. Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- fpu/softfloat-specialize.h | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 5da3a85355..33930f99ed 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -227,15 +227,16 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand; + flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; + flag aIsLargerSignificand; bits32 av, bv, res; if ( STATUS(default_nan_mode) ) return float32_default_nan; - aIsNaN = float32_is_quiet_nan( a ); + aIsQuietNaN = float32_is_quiet_nan( a ); aIsSignalingNaN = float32_is_signaling_nan( a ); - bIsNaN = float32_is_quiet_nan( b ); + bIsQuietNaN = float32_is_quiet_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); av = float32_val(a); bv = float32_val(b); @@ -256,7 +257,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) aIsLargerSignificand = (av < bv) ? 1 : 0; } - if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, + if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, aIsLargerSignificand)) { res = bv; } else { @@ -375,15 +376,16 @@ static float64 commonNaNToFloat64( commonNaNT a ) static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand; + flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; + flag aIsLargerSignificand; bits64 av, bv, res; if ( STATUS(default_nan_mode) ) return float64_default_nan; - aIsNaN = float64_is_quiet_nan( a ); + aIsQuietNaN = float64_is_quiet_nan( a ); aIsSignalingNaN = float64_is_signaling_nan( a ); - bIsNaN = float64_is_quiet_nan( b ); + bIsQuietNaN = float64_is_quiet_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); av = float64_val(a); bv = float64_val(b); @@ -404,7 +406,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) aIsLargerSignificand = (av < bv) ? 1 : 0; } - if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, + if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, aIsLargerSignificand)) { res = bv; } else { @@ -511,7 +513,8 @@ static floatx80 commonNaNToFloatx80( commonNaNT a ) static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand; + flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; + flag aIsLargerSignificand; if ( STATUS(default_nan_mode) ) { a.low = floatx80_default_nan_low; @@ -519,9 +522,9 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) return a; } - aIsNaN = floatx80_is_quiet_nan( a ); + aIsQuietNaN = floatx80_is_quiet_nan( a ); aIsSignalingNaN = floatx80_is_signaling_nan( a ); - bIsNaN = floatx80_is_quiet_nan( b ); + bIsQuietNaN = floatx80_is_quiet_nan( b ); bIsSignalingNaN = floatx80_is_signaling_nan( b ); #if SNAN_BIT_IS_ONE a.low &= ~LIT64( 0xC000000000000000 ); @@ -540,7 +543,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) aIsLargerSignificand = (a.high < b.high) ? 1 : 0; } - if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, + if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, aIsLargerSignificand)) { return b; } else { @@ -638,7 +641,8 @@ static float128 commonNaNToFloat128( commonNaNT a ) static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, aIsLargerSignificand; + flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; + flag aIsLargerSignificand; if ( STATUS(default_nan_mode) ) { a.low = float128_default_nan_low; @@ -646,9 +650,9 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) return a; } - aIsNaN = float128_is_quiet_nan( a ); + aIsQuietNaN = float128_is_quiet_nan( a ); aIsSignalingNaN = float128_is_signaling_nan( a ); - bIsNaN = float128_is_quiet_nan( b ); + bIsQuietNaN = float128_is_quiet_nan( b ); bIsSignalingNaN = float128_is_signaling_nan( b ); #if SNAN_BIT_IS_ONE a.high &= ~LIT64( 0x0000800000000000 ); @@ -667,7 +671,7 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) aIsLargerSignificand = (a.high < b.high) ? 1 : 0; } - if (pickNaN(aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN, + if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, aIsLargerSignificand)) { return b; } else { -- cgit v1.2.3 From 93ae1c6fea6433bca732c907d7c3ee9be4f8a2ab Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:19 +0100 Subject: softfloat: fix float{32,64}_maybe_silence_nan() for MIPS On targets that define sNaN with the sNaN bit as one, simply clearing this bit may correspond to an infinite value. Convert it to a default NaN if SNAN_BIT_IS_ONE, as it corresponds to the MIPS implementation, the only emulated CPU with SNAN_BIT_IS_ONE. When other CPU of this type are added, this might be updated to include more cases. Acked-by: Alexander Graf Signed-off-by: Aurelien Jarno --- fpu/softfloat-specialize.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 33930f99ed..bc6f0c1e5b 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -107,13 +107,17 @@ int float32_is_signaling_nan( float32 a_ ) float32 float32_maybe_silence_nan( float32 a_ ) { if (float32_is_signaling_nan(a_)) { - uint32_t a = float32_val(a_); #if SNAN_BIT_IS_ONE - a &= ~(1 << 22); +# if defined(TARGET_MIPS) + return float32_default_nan; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif #else + bits32 a = float32_val(a_); a |= (1 << 22); -#endif return make_float32(a); +#endif } return a_; } @@ -322,13 +326,17 @@ int float64_is_signaling_nan( float64 a_ ) float64 float64_maybe_silence_nan( float64 a_ ) { if (float64_is_signaling_nan(a_)) { - bits64 a = float64_val(a_); #if SNAN_BIT_IS_ONE - a &= ~LIT64( 0x0008000000000000 ); +# if defined(TARGET_MIPS) + return float64_default_nan; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif #else + bits64 a = float64_val(a_); a |= LIT64( 0x0008000000000000 ); -#endif return make_float64(a); +#endif } return a_; } -- cgit v1.2.3 From f6a7d92aed30964b6096d921e3c0df0487bb7b22 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:19 +0100 Subject: softfloat: add float{x80,128}_maybe_silence_nan() Add float{x80,128}_maybe_silence_nan() functions, they will be need by propagateFloat{x80,128}NaN(). Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- fpu/softfloat-specialize.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ fpu/softfloat.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index bc6f0c1e5b..b1acc45aba 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -479,6 +479,29 @@ int floatx80_is_signaling_nan( floatx80 a ) #endif } +/*---------------------------------------------------------------------------- +| Returns a quiet NaN if the extended double-precision floating point value +| `a' is a signaling NaN; otherwise returns `a'. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_maybe_silence_nan( floatx80 a ) +{ + if (floatx80_is_signaling_nan(a)) { +#if SNAN_BIT_IS_ONE +# if defined(TARGET_MIPS) + a.low = floatx80_default_nan_low; + a.high = floatx80_default_nan_high; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif +#else + a.low |= LIT64( 0xC000000000000000 ); + return a; +#endif + } + return a; +} + /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the @@ -611,6 +634,29 @@ int float128_is_signaling_nan( float128 a ) #endif } +/*---------------------------------------------------------------------------- +| Returns a quiet NaN if the quadruple-precision floating point value `a' is +| a signaling NaN; otherwise returns `a'. +*----------------------------------------------------------------------------*/ + +float128 float128_maybe_silence_nan( float128 a ) +{ + if (float128_is_signaling_nan(a)) { +#if SNAN_BIT_IS_ONE +# if defined(TARGET_MIPS) + a.low = float128_default_nan_low; + a.high = float128_default_nan_high; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif +#else + a.high |= LIT64( 0x0000800000000000 ); + return a; +#endif + } + return a; +} + /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point NaN | `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 1f37877dbf..f2104c6c89 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -439,6 +439,7 @@ int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_quiet_nan( floatx80 ); int floatx80_is_signaling_nan( floatx80 ); +floatx80 floatx80_maybe_silence_nan( floatx80 ); floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM ); INLINE floatx80 floatx80_abs(floatx80 a) @@ -505,6 +506,7 @@ int float128_compare( float128, float128 STATUS_PARAM ); int float128_compare_quiet( float128, float128 STATUS_PARAM ); int float128_is_quiet_nan( float128 ); int float128_is_signaling_nan( float128 ); +float128 float128_maybe_silence_nan( float128 ); float128 float128_scalbn( float128, int STATUS_PARAM ); INLINE float128 float128_abs(float128 a) -- cgit v1.2.3 From 1f398e0825b3365746ac3a3f6f5a9954b0064f28 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:19 +0100 Subject: softfloat: use float{32,64,x80,128}_maybe_silence_nan() Use float{32,64,x80,128}_maybe_silence_nan() instead of toggling the sNaN bit manually. This allow per target implementation of sNaN to qNaN conversion. Signed-off-by: Aurelien Jarno Reviewed-by: Peter Maydell --- fpu/softfloat-specialize.h | 59 +++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 43 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index b1acc45aba..3ce5bb53bf 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -161,7 +161,8 @@ static float32 commonNaNToFloat32( commonNaNT a ) | The routine is passed various bits of information about the | two NaNs and should return 0 to select NaN a and 1 for NaN b. | Note that signalling NaNs are always squashed to quiet NaNs -| by the caller, by flipping the SNaN bit before returning them. +| by the caller, by calling floatXX_maybe_silence_nan() before +| returning them. | | aIsLargerSignificand is only valid if both a and b are NaNs | of some kind, and is true if a has the larger significand, @@ -233,7 +234,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) { flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; flag aIsLargerSignificand; - bits32 av, bv, res; + bits32 av, bv; if ( STATUS(default_nan_mode) ) return float32_default_nan; @@ -244,13 +245,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) bIsSignalingNaN = float32_is_signaling_nan( b ); av = float32_val(a); bv = float32_val(b); -#if SNAN_BIT_IS_ONE - av &= ~0x00400000; - bv &= ~0x00400000; -#else - av |= 0x00400000; - bv |= 0x00400000; -#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ((bits32)(av<<1) < (bits32)(bv<<1)) { @@ -263,12 +258,10 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, aIsLargerSignificand)) { - res = bv; + return float32_maybe_silence_nan(b); } else { - res = av; + return float32_maybe_silence_nan(a); } - - return make_float32(res); } /*---------------------------------------------------------------------------- @@ -386,7 +379,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) { flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; flag aIsLargerSignificand; - bits64 av, bv, res; + bits64 av, bv; if ( STATUS(default_nan_mode) ) return float64_default_nan; @@ -397,13 +390,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) bIsSignalingNaN = float64_is_signaling_nan( b ); av = float64_val(a); bv = float64_val(b); -#if SNAN_BIT_IS_ONE - av &= ~LIT64( 0x0008000000000000 ); - bv &= ~LIT64( 0x0008000000000000 ); -#else - av |= LIT64( 0x0008000000000000 ); - bv |= LIT64( 0x0008000000000000 ); -#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ((bits64)(av<<1) < (bits64)(bv<<1)) { @@ -416,12 +403,10 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, aIsLargerSignificand)) { - res = bv; + return float64_maybe_silence_nan(b); } else { - res = av; + return float64_maybe_silence_nan(a); } - - return make_float64(res); } #ifdef FLOATX80 @@ -557,13 +542,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) aIsSignalingNaN = floatx80_is_signaling_nan( a ); bIsQuietNaN = floatx80_is_quiet_nan( b ); bIsSignalingNaN = floatx80_is_signaling_nan( b ); -#if SNAN_BIT_IS_ONE - a.low &= ~LIT64( 0xC000000000000000 ); - b.low &= ~LIT64( 0xC000000000000000 ); -#else - a.low |= LIT64( 0xC000000000000000 ); - b.low |= LIT64( 0xC000000000000000 ); -#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if (a.low < b.low) { @@ -576,9 +555,9 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, aIsLargerSignificand)) { - return b; + return floatx80_maybe_silence_nan(b); } else { - return a; + return floatx80_maybe_silence_nan(a); } } @@ -708,13 +687,7 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) aIsSignalingNaN = float128_is_signaling_nan( a ); bIsQuietNaN = float128_is_quiet_nan( b ); bIsSignalingNaN = float128_is_signaling_nan( b ); -#if SNAN_BIT_IS_ONE - a.high &= ~LIT64( 0x0000800000000000 ); - b.high &= ~LIT64( 0x0000800000000000 ); -#else - a.high |= LIT64( 0x0000800000000000 ); - b.high |= LIT64( 0x0000800000000000 ); -#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if (lt128(a.high<<1, a.low, b.high<<1, b.low)) { @@ -727,9 +700,9 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, aIsLargerSignificand)) { - return b; + return float128_maybe_silence_nan(b); } else { - return a; + return float128_maybe_silence_nan(a); } } -- cgit v1.2.3 From 084d19ba718a08d434dc44a83ff01f3152d59635 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:19 +0100 Subject: target-mips: Implement correct NaN propagation rules Implement the correct NaN propagation rules for MIPS targets by providing an appropriate pickNaN function. Signed-off-by: Aurelien Jarno --- fpu/softfloat-specialize.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 3ce5bb53bf..acdd299f51 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -192,6 +192,33 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, return 1; } } +#elif defined(TARGET_MIPS) +static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, + flag aIsLargerSignificand) +{ + /* According to MIPS specifications, if one of the two operands is + * a sNaN, a new qNaN has to be generated. This is done in + * floatXX_maybe_silence_nan(). For qNaN inputs the specifications + * says: "When possible, this QNaN result is one of the operand QNaN + * values." In practice it seems that most implementations choose + * the first operand if both operands are qNaN. In short this gives + * the following rules: + * 1. A if it is signaling + * 2. B if it is signaling + * 3. A (quiet) + * 4. B (quiet) + * A signaling NaN is always silenced before returning it. + */ + if (aIsSNaN) { + return 0; + } else if (bIsSNaN) { + return 1; + } else if (aIsQNaN) { + return 0; + } else { + return 1; + } +} #else static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, flag aIsLargerSignificand) -- cgit v1.2.3 From e024e881bb1a8b5085026589360d26ed97acdd64 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 15:38:19 +0100 Subject: target-ppc: Implement correct NaN propagation rules Implement the correct NaN propagation rules for PowerPC targets by providing an appropriate pickNaN function. Also fix the #ifdef tests for default NaN definition, the correct name is TARGET_PPC instead of TARGET_POWERPC. Reviewed-by: Nathan Froyd Signed-off-by: Aurelien Jarno --- fpu/softfloat-specialize.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index acdd299f51..f293f24356 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -61,7 +61,7 @@ typedef struct { *----------------------------------------------------------------------------*/ #if defined(TARGET_SPARC) #define float32_default_nan make_float32(0x7FFFFFFF) -#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) #define float32_default_nan make_float32(0x7FC00000) #elif SNAN_BIT_IS_ONE #define float32_default_nan make_float32(0x7FBFFFFF) @@ -219,6 +219,21 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, return 1; } } +#elif defined(TARGET_PPC) +static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, + flag aIsLargerSignificand) +{ + /* PowerPC propagation rules: + * 1. A if it sNaN or qNaN + * 2. B if it sNaN or qNaN + * A signaling NaN is always silenced before returning it. + */ + if (aIsSNaN || aIsQNaN) { + return 0; + } else { + return 1; + } +} #else static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, flag aIsLargerSignificand) @@ -296,7 +311,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) *----------------------------------------------------------------------------*/ #if defined(TARGET_SPARC) #define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) -#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) #define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) #elif SNAN_BIT_IS_ONE #define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) -- cgit v1.2.3 From 4b78a802ffaabb325a0f7b773031da92d173bde1 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Thu, 6 Jan 2011 18:24:35 +0000 Subject: pc: move port 92 stuff back to pc.c from pckbd.c 956a3e6bb7386de48b642d4fee11f7f86a2fcf9a introduced a bug concerning reset bit for port 92. Since the keyboard output port and port 92 are not compatible anyway, let's separate them. Reported-by: Peter Lieven Signed-off-by: Blue Swirl -- v2: added reset handler and VMState --- hw/pc.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/pckbd.c | 19 ++------------ 2 files changed, 88 insertions(+), 20 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 18a4a9f6c7..fface7dec9 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -411,11 +411,92 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, qemu_register_reset(pc_cmos_init_late, &arg); } +/* port 92 stuff: could be split off */ +typedef struct Port92State { + ISADevice dev; + uint8_t outport; + qemu_irq *a20_out; +} Port92State; + +static void port92_write(void *opaque, uint32_t addr, uint32_t val) +{ + Port92State *s = opaque; + + DPRINTF("port92: write 0x%02x\n", val); + s->outport = val; + qemu_set_irq(*s->a20_out, (val >> 1) & 1); + if (val & 1) { + qemu_system_reset_request(); + } +} + +static uint32_t port92_read(void *opaque, uint32_t addr) +{ + Port92State *s = opaque; + uint32_t ret; + + ret = s->outport; + DPRINTF("port92: read 0x%02x\n", ret); + return ret; +} + +static void port92_init(ISADevice *dev, qemu_irq *a20_out) +{ + Port92State *s = DO_UPCAST(Port92State, dev, dev); + + s->a20_out = a20_out; +} + +static const VMStateDescription vmstate_port92_isa = { + .name = "port92", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT8(outport, Port92State), + VMSTATE_END_OF_LIST() + } +}; + +static void port92_reset(DeviceState *d) +{ + Port92State *s = container_of(d, Port92State, dev.qdev); + + s->outport &= ~1; +} + +static int port92_initfn(ISADevice *dev) +{ + Port92State *s = DO_UPCAST(Port92State, dev, dev); + + register_ioport_read(0x92, 1, 1, port92_read, s); + register_ioport_write(0x92, 1, 1, port92_write, s); + isa_init_ioport(dev, 0x92); + s->outport = 0; + return 0; +} + +static ISADeviceInfo port92_info = { + .qdev.name = "port92", + .qdev.size = sizeof(Port92State), + .qdev.vmsd = &vmstate_port92_isa, + .qdev.no_user = 1, + .qdev.reset = port92_reset, + .init = port92_initfn, +}; + +static void port92_register(void) +{ + isa_qdev_register(&port92_info); +} +device_init(port92_register) + static void handle_a20_line_change(void *opaque, int irq, int level) { CPUState *cpu = opaque; /* XXX: send to all CPUs ? */ + /* XXX: add logic to handle multiple A20 line sources */ cpu_x86_set_a20(cpu, level); } @@ -1027,7 +1108,7 @@ void pc_basic_device_init(qemu_irq *isa_irq, PITState *pit; qemu_irq rtc_irq = NULL; qemu_irq *a20_line; - ISADevice *i8042; + ISADevice *i8042, *port92; qemu_irq *cpu_exit_irq; register_ioport_write(0x80, 1, 1, ioport80_write, NULL); @@ -1061,10 +1142,12 @@ void pc_basic_device_init(qemu_irq *isa_irq, } } - a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 1); + a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); i8042 = isa_create_simple("i8042"); - i8042_setup_a20_line(i8042, a20_line); + i8042_setup_a20_line(i8042, &a20_line[0]); vmmouse_init(i8042); + port92 = isa_create_simple("port92"); + port92_init(port92, &a20_line[1]); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); DMA_init(0, cpu_exit_irq); diff --git a/hw/pckbd.c b/hw/pckbd.c index 863b485db5..ae65c04da1 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -211,10 +211,8 @@ static void kbd_queue(KBDState *s, int b, int aux) ps2_queue(s->kbd, b); } -static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) +static void outport_write(KBDState *s, uint32_t val) { - KBDState *s = opaque; - DPRINTF("kbd: write outport=0x%02x\n", val); s->outport = val; if (s->a20_out) { @@ -225,16 +223,6 @@ static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t ioport92_read(void *opaque, uint32_t addr) -{ - KBDState *s = opaque; - uint32_t ret; - - ret = s->outport; - DPRINTF("kbd: read outport=0x%02x\n", ret); - return ret; -} - static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) { KBDState *s = opaque; @@ -357,7 +345,7 @@ static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) kbd_queue(s, val, 1); break; case KBD_CCMD_WRITE_OUTPORT: - ioport92_write(s, 0, val); + outport_write(s, val); break; case KBD_CCMD_WRITE_MOUSE: ps2_write_mouse(s->mouse, val); @@ -489,9 +477,6 @@ static int i8042_initfn(ISADevice *dev) register_ioport_read(0x64, 1, 1, kbd_read_status, s); register_ioport_write(0x64, 1, 1, kbd_write_command, s); isa_init_ioport(dev, 0x64); - register_ioport_read(0x92, 1, 1, ioport92_read, s); - register_ioport_write(0x92, 1, 1, ioport92_write, s); - isa_init_ioport(dev, 0x92); s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); -- cgit v1.2.3 From 3fbb33d08d63908849a037ad6432cb12c763dd12 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Thu, 6 Jan 2011 18:25:26 +0000 Subject: cirrus_vga: Declare as little endian This patch replaces explicit bswaps with endianness hints to the mmio layer. CC: Alexander Graf Signed-off-by: Blue Swirl --- hw/cirrus_vga.c | 112 ++++++-------------------------------------------------- 1 file changed, 12 insertions(+), 100 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 199136ce7d..833a2eb4be 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2004,30 +2004,20 @@ static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr) static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr) { uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_vga_mem_readb(opaque, addr) << 8; - v |= cirrus_vga_mem_readb(opaque, addr + 1); -#else + v = cirrus_vga_mem_readb(opaque, addr); v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8; -#endif return v; } static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr) { uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_vga_mem_readb(opaque, addr) << 24; - v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16; - v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8; - v |= cirrus_vga_mem_readb(opaque, addr + 3); -#else + v = cirrus_vga_mem_readb(opaque, addr); v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8; v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16; v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24; -#endif return v; } @@ -2098,28 +2088,16 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff); -#else cirrus_vga_mem_writeb(opaque, addr, val & 0xff); cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif } static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff); -#else cirrus_vga_mem_writeb(opaque, addr, val & 0xff); cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif } static CPUReadMemoryFunc * const cirrus_vga_mem_read[3] = { @@ -2341,30 +2319,20 @@ static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr) static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr) { uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_linear_readb(opaque, addr) << 8; - v |= cirrus_linear_readb(opaque, addr + 1); -#else + v = cirrus_linear_readb(opaque, addr); v |= cirrus_linear_readb(opaque, addr + 1) << 8; -#endif return v; } static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr) { uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_linear_readb(opaque, addr) << 24; - v |= cirrus_linear_readb(opaque, addr + 1) << 16; - v |= cirrus_linear_readb(opaque, addr + 2) << 8; - v |= cirrus_linear_readb(opaque, addr + 3); -#else + v = cirrus_linear_readb(opaque, addr); v |= cirrus_linear_readb(opaque, addr + 1) << 8; v |= cirrus_linear_readb(opaque, addr + 2) << 16; v |= cirrus_linear_readb(opaque, addr + 3) << 24; -#endif return v; } @@ -2412,29 +2380,17 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr, static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_linear_writeb(opaque, addr + 1, val & 0xff); -#else cirrus_linear_writeb(opaque, addr, val & 0xff); cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif } static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_linear_writeb(opaque, addr + 3, val & 0xff); -#else cirrus_linear_writeb(opaque, addr, val & 0xff); cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff); cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff); cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif } @@ -2469,30 +2425,20 @@ static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr) { uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_linear_bitblt_readb(opaque, addr) << 8; - v |= cirrus_linear_bitblt_readb(opaque, addr + 1); -#else + v = cirrus_linear_bitblt_readb(opaque, addr); v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8; -#endif return v; } static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr) { uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_linear_bitblt_readb(opaque, addr) << 24; - v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 16; - v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 8; - v |= cirrus_linear_bitblt_readb(opaque, addr + 3); -#else + v = cirrus_linear_bitblt_readb(opaque, addr); v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8; v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16; v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24; -#endif return v; } @@ -2513,29 +2459,17 @@ static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr, static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_linear_bitblt_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 1, val & 0xff); -#else cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff); cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif } static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_linear_bitblt_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 3, val & 0xff); -#else cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff); cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff); cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff); cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif } @@ -2842,30 +2776,20 @@ static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr) static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr) { uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_mmio_readb(opaque, addr) << 8; - v |= cirrus_mmio_readb(opaque, addr + 1); -#else + v = cirrus_mmio_readb(opaque, addr); v |= cirrus_mmio_readb(opaque, addr + 1) << 8; -#endif return v; } static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr) { uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_mmio_readb(opaque, addr) << 24; - v |= cirrus_mmio_readb(opaque, addr + 1) << 16; - v |= cirrus_mmio_readb(opaque, addr + 2) << 8; - v |= cirrus_mmio_readb(opaque, addr + 3); -#else + v = cirrus_mmio_readb(opaque, addr); v |= cirrus_mmio_readb(opaque, addr + 1) << 8; v |= cirrus_mmio_readb(opaque, addr + 2) << 16; v |= cirrus_mmio_readb(opaque, addr + 3) << 24; -#endif return v; } @@ -2886,29 +2810,17 @@ static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr, static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, val & 0xff); -#else cirrus_mmio_writeb(opaque, addr, val & 0xff); cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif } static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_mmio_writeb(opaque, addr + 3, val & 0xff); -#else cirrus_mmio_writeb(opaque, addr, val & 0xff); cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff); cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif } @@ -3078,7 +2990,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) s->vga.vga_io_memory = cpu_register_io_memory(cirrus_vga_mem_read, cirrus_vga_mem_write, s, - DEVICE_NATIVE_ENDIAN); + DEVICE_LITTLE_ENDIAN); cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, s->vga.vga_io_memory); qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000); @@ -3086,18 +2998,18 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) /* I/O handler for LFB */ s->cirrus_linear_io_addr = cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s, - DEVICE_NATIVE_ENDIAN); + DEVICE_LITTLE_ENDIAN); /* I/O handler for LFB */ s->cirrus_linear_bitblt_io_addr = cpu_register_io_memory(cirrus_linear_bitblt_read, cirrus_linear_bitblt_write, s, - DEVICE_NATIVE_ENDIAN); + DEVICE_LITTLE_ENDIAN); /* I/O handler for memory-mapped I/O */ s->cirrus_mmio_io_addr = cpu_register_io_memory(cirrus_mmio_read, cirrus_mmio_write, s, - DEVICE_NATIVE_ENDIAN); + DEVICE_LITTLE_ENDIAN); s->real_vram_size = (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024; -- cgit v1.2.3 From 71df0eeb98a1ecff7770aa486faf08a8c1049745 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Thu, 6 Jan 2011 18:25:37 +0000 Subject: block: delete a write-only variable Avoid a warning with GCC 4.6.0: /src/qemu/block.c: In function 'bdrv_img_create': /src/qemu/block.c:2862:25: error: variable 'fmt' set but not used [-Werror=unused-but-set-variable] CC: Kevin Wolf Signed-off-by: Blue Swirl --- block.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/block.c b/block.c index 9b5e9e11fe..ff2795b1e9 100644 --- a/block.c +++ b/block.c @@ -2859,13 +2859,8 @@ int bdrv_img_create(const char *filename, const char *fmt, if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) { if (backing_file && backing_file->value.s) { uint64_t size; - const char *fmt = NULL; char buf[32]; - if (backing_fmt && backing_fmt->value.s) { - fmt = backing_fmt->value.s; - } - bs = bdrv_new(""); ret = bdrv_open(bs, backing_file->value.s, flags, drv); -- cgit v1.2.3 From 838fa72d0b721766616e94a0f7dc76b15146cd82 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 19:53:56 +0100 Subject: target-arm: fix SMMLA/SMMLS instructions SMMLA and SMMLS are broken on both in normal and thumb mode, that is both (different) implementations are wrong. They try to avoid a 64-bit add for the rounding, which is not trivial if you want to support both SMMLA and SMMLS with the same code. The code below uses the same implementation for both modes, using the code from the ARM manual. It also fixes the thumb decoding that was a mix between normal and thumb mode. This fixes the issues reported in https://bugs.launchpad.net/qemu/+bug/629298 Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/translate.c | 96 +++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 2598268405..2ce82f3bbb 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -287,11 +287,32 @@ static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask) tcg_gen_or_i32(dest, base, val); } -/* Round the top 32 bits of a 64-bit value. */ -static void gen_roundqd(TCGv a, TCGv b) +/* Return (b << 32) + a. Mark inputs as dead */ +static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b) { - tcg_gen_shri_i32(a, a, 31); - tcg_gen_add_i32(a, a, b); + TCGv_i64 tmp64 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(tmp64, b); + dead_tmp(b); + tcg_gen_shli_i64(tmp64, tmp64, 32); + tcg_gen_add_i64(a, tmp64, a); + + tcg_temp_free_i64(tmp64); + return a; +} + +/* Return (b << 32) - a. Mark inputs as dead. */ +static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b) +{ + TCGv_i64 tmp64 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(tmp64, b); + dead_tmp(b); + tcg_gen_shli_i64(tmp64, tmp64, 32); + tcg_gen_sub_i64(a, tmp64, a); + + tcg_temp_free_i64(tmp64); + return a; } /* FIXME: Most targets have native widening multiplication. @@ -325,22 +346,6 @@ static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b) return tmp1; } -/* Signed 32x32->64 multiply. */ -static void gen_imull(TCGv a, TCGv b) -{ - TCGv_i64 tmp1 = tcg_temp_new_i64(); - TCGv_i64 tmp2 = tcg_temp_new_i64(); - - tcg_gen_ext_i32_i64(tmp1, a); - tcg_gen_ext_i32_i64(tmp2, b); - tcg_gen_mul_i64(tmp1, tmp1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_trunc_i64_i32(a, tmp1); - tcg_gen_shri_i64(tmp1, tmp1, 32); - tcg_gen_trunc_i64_i32(b, tmp1); - tcg_temp_free_i64(tmp1); -} - /* Swap low and high halfwords. */ static void gen_swap_half(TCGv var) { @@ -6953,23 +6958,25 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) tmp = load_reg(s, rm); tmp2 = load_reg(s, rs); if (insn & (1 << 20)) { - /* Signed multiply most significant [accumulate]. */ + /* Signed multiply most significant [accumulate]. + (SMMUL, SMMLA, SMMLS) */ tmp64 = gen_muls_i64_i32(tmp, tmp2); - if (insn & (1 << 5)) - tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u); - tcg_gen_shri_i64(tmp64, tmp64, 32); - tmp = new_tmp(); - tcg_gen_trunc_i64_i32(tmp, tmp64); - tcg_temp_free_i64(tmp64); + if (rd != 15) { - tmp2 = load_reg(s, rd); + tmp = load_reg(s, rd); if (insn & (1 << 6)) { - tcg_gen_sub_i32(tmp, tmp, tmp2); + tmp64 = gen_subq_msw(tmp64, tmp); } else { - tcg_gen_add_i32(tmp, tmp, tmp2); + tmp64 = gen_addq_msw(tmp64, tmp); } - dead_tmp(tmp2); } + if (insn & (1 << 5)) { + tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u); + } + tcg_gen_shri_i64(tmp64, tmp64, 32); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); store_reg(s, rn, tmp); } else { if (insn & (1 << 5)) @@ -7840,24 +7847,23 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) dead_tmp(tmp2); } break; - case 5: case 6: /* 32 * 32 -> 32msb */ - gen_imull(tmp, tmp2); - if (insn & (1 << 5)) { - gen_roundqd(tmp, tmp2); - dead_tmp(tmp2); - } else { - dead_tmp(tmp); - tmp = tmp2; - } + case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */ + tmp64 = gen_muls_i64_i32(tmp, tmp2); if (rs != 15) { - tmp2 = load_reg(s, rs); - if (insn & (1 << 21)) { - tcg_gen_add_i32(tmp, tmp, tmp2); + tmp = load_reg(s, rs); + if (insn & (1 << 20)) { + tmp64 = gen_addq_msw(tmp64, tmp); } else { - tcg_gen_sub_i32(tmp, tmp2, tmp); + tmp64 = gen_subq_msw(tmp64, tmp); } - dead_tmp(tmp2); } + if (insn & (1 << 4)) { + tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u); + } + tcg_gen_shri_i64(tmp64, tmp64, 32); + tmp = new_tmp(); + tcg_gen_trunc_i64_i32(tmp, tmp64); + tcg_temp_free_i64(tmp64); break; case 7: /* Unsigned sum of absolute differences. */ gen_helper_usad8(tmp, tmp, tmp2); -- cgit v1.2.3 From 37d18660bbb1d60b4e59bf407b4b301749e0c3b9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 Jan 2011 19:37:53 +0000 Subject: softfloat: Implement flushing input denormals to zero Add support to softfloat for flushing input denormal float32 and float64 to zero. softfloat's existing 'flush_to_zero' flag only flushes denormals to zero on output. Some CPUs need input denormals to be flushed before processing as well. Implement this, using a new status flag to enable it and a new exception status bit to indicate when it has happened. Existing CPUs should be unaffected as there is no behaviour change unless the mode is enabled. Signed-off-by: Peter Maydell Acked-by: Aurelien Jarno Signed-off-by: Aurelien Jarno --- fpu/softfloat.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- fpu/softfloat.h | 22 +++++++++++- 2 files changed, 123 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 6f5b05d5fe..17842f43da 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -30,8 +30,6 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ -/* FIXME: Flush-To-Zero only effects results. Denormal inputs should also - be flushed to zero. */ #include "softfloat.h" /*---------------------------------------------------------------------------- @@ -203,6 +201,21 @@ INLINE flag extractFloat32Sign( float32 a ) } +/*---------------------------------------------------------------------------- +| If `a' is denormal and we are in flush-to-zero mode then set the +| input-denormal exception and return zero. Otherwise just return the value. +*----------------------------------------------------------------------------*/ +static float32 float32_squash_input_denormal(float32 a STATUS_PARAM) +{ + if (STATUS(flush_inputs_to_zero)) { + if (extractFloat32Exp(a) == 0 && extractFloat32Frac(a) != 0) { + float_raise(float_flag_input_denormal STATUS_VAR); + return make_float32(float32_val(a) & 0x80000000); + } + } + return a; +} + /*---------------------------------------------------------------------------- | Normalizes the subnormal single-precision floating-point value represented | by the denormalized significand `aSig'. The normalized exponent and @@ -367,6 +380,21 @@ INLINE flag extractFloat64Sign( float64 a ) } +/*---------------------------------------------------------------------------- +| If `a' is denormal and we are in flush-to-zero mode then set the +| input-denormal exception and return zero. Otherwise just return the value. +*----------------------------------------------------------------------------*/ +static float64 float64_squash_input_denormal(float64 a STATUS_PARAM) +{ + if (STATUS(flush_inputs_to_zero)) { + if (extractFloat64Exp(a) == 0 && extractFloat64Frac(a) != 0) { + float_raise(float_flag_input_denormal STATUS_VAR); + return make_float64(float64_val(a) & (1ULL << 63)); + } + } + return a; +} + /*---------------------------------------------------------------------------- | Normalizes the subnormal double-precision floating-point value represented | by the denormalized significand `aSig'. The normalized exponent and @@ -1298,6 +1326,7 @@ int32 float32_to_int32( float32 a STATUS_PARAM ) bits32 aSig; bits64 aSig64; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); @@ -1327,6 +1356,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM ) int16 aExp, shiftCount; bits32 aSig; int32 z; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1418,6 +1448,7 @@ int64 float32_to_int64( float32 a STATUS_PARAM ) int16 aExp, shiftCount; bits32 aSig; bits64 aSig64, aSigExtra; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1455,6 +1486,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) bits32 aSig; bits64 aSig64; int64 z; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1496,6 +1528,7 @@ float64 float32_to_float64( float32 a STATUS_PARAM ) flag aSign; int16 aExp; bits32 aSig; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1528,6 +1561,7 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM ) int16 aExp; bits32 aSig; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); @@ -1561,6 +1595,7 @@ float128 float32_to_float128( float32 a STATUS_PARAM ) int16 aExp; bits32 aSig; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); @@ -1593,6 +1628,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) bits32 lastBitMask, roundBitsMask; int8 roundingMode; bits32 z; + a = float32_squash_input_denormal(a STATUS_VAR); aExp = extractFloat32Exp( a ); if ( 0x96 <= aExp ) { @@ -1796,6 +1832,8 @@ static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) float32 float32_add( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); @@ -1817,6 +1855,8 @@ float32 float32_add( float32 a, float32 b STATUS_PARAM ) float32 float32_sub( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); @@ -1843,6 +1883,9 @@ float32 float32_mul( float32 a, float32 b STATUS_PARAM ) bits64 zSig64; bits32 zSig; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); + aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); @@ -1900,6 +1943,8 @@ float32 float32_div( float32 a, float32 b STATUS_PARAM ) flag aSign, bSign, zSign; int16 aExp, bExp, zExp; bits32 aSig, bSig, zSig; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1966,6 +2011,8 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM ) bits64 aSig64, bSig64, q64; bits32 alternateASig; sbits32 sigMean; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -2062,6 +2109,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) int16 aExp, zExp; bits32 aSig, zSig; bits64 rem, term; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -2148,6 +2196,7 @@ float32 float32_exp2( float32 a STATUS_PARAM ) bits32 aSig; float64 r, x, xn; int i; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -2194,6 +2243,7 @@ float32 float32_log2( float32 a STATUS_PARAM ) int16 aExp; bits32 aSig, zSig, i; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); @@ -2238,6 +2288,8 @@ float32 float32_log2( float32 a STATUS_PARAM ) int float32_eq( float32 a, float32 b STATUS_PARAM ) { + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2263,6 +2315,8 @@ int float32_le( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; bits32 av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2289,6 +2343,8 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; bits32 av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2315,6 +2371,8 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) { bits32 av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2339,6 +2397,8 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; bits32 av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2368,6 +2428,8 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; bits32 av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2401,6 +2463,7 @@ int32 float64_to_int32( float64 a STATUS_PARAM ) flag aSign; int16 aExp, shiftCount; bits64 aSig; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -2429,6 +2492,7 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM ) int16 aExp, shiftCount; bits64 aSig, savedASig; int32 z; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -2525,6 +2589,7 @@ int64 float64_to_int64( float64 a STATUS_PARAM ) flag aSign; int16 aExp, shiftCount; bits64 aSig, aSigExtra; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -2568,6 +2633,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM ) int16 aExp, shiftCount; bits64 aSig; int64 z; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -2617,6 +2683,7 @@ float32 float64_to_float32( float64 a STATUS_PARAM ) int16 aExp; bits64 aSig; bits32 zSig; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -2694,6 +2761,7 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM) bits32 mask; bits32 increment; int8 roundingMode; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -2788,6 +2856,7 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM ) int16 aExp; bits64 aSig; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); @@ -2822,6 +2891,7 @@ float128 float64_to_float128( float64 a STATUS_PARAM ) int16 aExp; bits64 aSig, zSig0, zSig1; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); @@ -2855,6 +2925,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) bits64 lastBitMask, roundBitsMask; int8 roundingMode; bits64 z; + a = float64_squash_input_denormal(a STATUS_VAR); aExp = extractFloat64Exp( a ); if ( 0x433 <= aExp ) { @@ -3071,6 +3142,8 @@ static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) float64 float64_add( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); @@ -3092,6 +3165,8 @@ float64 float64_add( float64 a, float64 b STATUS_PARAM ) float64 float64_sub( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); @@ -3116,6 +3191,9 @@ float64 float64_mul( float64 a, float64 b STATUS_PARAM ) int16 aExp, bExp, zExp; bits64 aSig, bSig, zSig0, zSig1; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); + aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); @@ -3175,6 +3253,8 @@ float64 float64_div( float64 a, float64 b STATUS_PARAM ) bits64 aSig, bSig, zSig; bits64 rem0, rem1; bits64 term0, term1; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3246,6 +3326,8 @@ float64 float64_rem( float64 a, float64 b STATUS_PARAM ) bits64 q, alternateASig; sbits64 sigMean; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); @@ -3328,6 +3410,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) int16 aExp, zExp; bits64 aSig, zSig, doubleZSig; bits64 rem0, rem1, term0, term1; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3377,6 +3460,7 @@ float64 float64_log2( float64 a STATUS_PARAM ) flag aSign, zSign; int16 aExp; bits64 aSig, aSig0, aSig1, zSig, i; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3422,6 +3506,8 @@ float64 float64_log2( float64 a STATUS_PARAM ) int float64_eq( float64 a, float64 b STATUS_PARAM ) { bits64 av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3448,6 +3534,8 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; bits64 av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3475,6 +3563,8 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) flag aSign, bSign; bits64 av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { @@ -3500,6 +3590,8 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) { bits64 av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3524,6 +3616,8 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; bits64 av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3553,6 +3647,8 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; bits64 av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -5833,6 +5929,8 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ { \ flag aSign, bSign; \ bits ## s av, bv; \ + a = float ## s ## _squash_input_denormal(a STATUS_VAR); \ + b = float ## s ## _squash_input_denormal(b STATUS_VAR); \ \ if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \ extractFloat ## s ## Frac( a ) ) || \ @@ -5929,6 +6027,7 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) int16 aExp; bits32 aSig; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); @@ -5952,6 +6051,7 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) int16 aExp; bits64 aSig; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); diff --git a/fpu/softfloat.h b/fpu/softfloat.h index f2104c6c89..15052cc470 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -180,7 +180,8 @@ enum { float_flag_divbyzero = 4, float_flag_overflow = 8, float_flag_underflow = 16, - float_flag_inexact = 32 + float_flag_inexact = 32, + float_flag_input_denormal = 64 }; typedef struct float_status { @@ -190,7 +191,10 @@ typedef struct float_status { #ifdef FLOATX80 signed char floatx80_rounding_precision; #endif + /* should denormalised results go to zero and set the inexact flag? */ flag flush_to_zero; + /* should denormalised inputs go to zero and set the input_denormal flag? */ + flag flush_inputs_to_zero; flag default_nan_mode; } float_status; @@ -200,6 +204,10 @@ INLINE void set_flush_to_zero(flag val STATUS_PARAM) { STATUS(flush_to_zero) = val; } +INLINE void set_flush_inputs_to_zero(flag val STATUS_PARAM) +{ + STATUS(flush_inputs_to_zero) = val; +} INLINE void set_default_nan_mode(flag val STATUS_PARAM) { STATUS(default_nan_mode) = val; @@ -294,11 +302,17 @@ float32 float32_scalbn( float32, int STATUS_PARAM ); INLINE float32 float32_abs(float32 a) { + /* Note that abs does *not* handle NaN specially, nor does + * it flush denormal inputs to zero. + */ return make_float32(float32_val(a) & 0x7fffffff); } INLINE float32 float32_chs(float32 a) { + /* Note that chs does *not* handle NaN specially, nor does + * it flush denormal inputs to zero. + */ return make_float32(float32_val(a) ^ 0x80000000); } @@ -374,11 +388,17 @@ float64 float64_scalbn( float64, int STATUS_PARAM ); INLINE float64 float64_abs(float64 a) { + /* Note that abs does *not* handle NaN specially, nor does + * it flush denormal inputs to zero. + */ return make_float64(float64_val(a) & 0x7fffffffffffffffLL); } INLINE float64 float64_chs(float64 a) { + /* Note that chs does *not* handle NaN specially, nor does + * it flush denormal inputs to zero. + */ return make_float64(float64_val(a) ^ 0x8000000000000000LL); } -- cgit v1.2.3 From b12c390b9108d44cb0b05900d6c11a73ee0e9cae Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 Jan 2011 19:37:54 +0000 Subject: target-arm: Set softfloat cumulative exc flags from correct FPSCR bits When handling a write to the ARM FPSCR, set the softfloat cumulative exception flags from the cumulative flags in the FPSCR, not the exception-enable bits. Also don't apply a mask: vfp_exceptbits_to_host will only look at the correct bits anyway. Signed-off-by: Peter Maydell Acked-by: Aurelien Jarno Signed-off-by: Aurelien Jarno --- target-arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 50c1017c8a..05684a2f45 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2315,7 +2315,7 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) if (changed & (1 << 25)) set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status); - i = vfp_exceptbits_to_host((val >> 8) & 0x1f); + i = vfp_exceptbits_to_host(val); set_float_exception_flags(i, &env->vfp.fp_status); } -- cgit v1.2.3 From cecd8504b80148b66cdc1ce32046429bc3549090 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 Jan 2011 19:37:55 +0000 Subject: target-arm: wire up the softfloat flush_input_to_zero flag Wire up the new softfloat support for flushing input denormals to zero on ARM. The FPSCR FZ bit enables flush-to-zero for both inputs and outputs, but the reporting of when inputs are flushed to zero is via a separate IDC bit rather than the UFC (underflow) bit used when output denormals are flushed to zero. Signed-off-by: Peter Maydell Acked-by: Aurelien Jarno Signed-off-by: Aurelien Jarno --- target-arm/helper.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 05684a2f45..705b99f9cb 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2242,6 +2242,8 @@ static inline int vfp_exceptbits_from_host(int host_bits) target_bits |= 8; if (host_bits & float_flag_inexact) target_bits |= 0x10; + if (host_bits & float_flag_input_denormal) + target_bits |= 0x80; return target_bits; } @@ -2278,6 +2280,8 @@ static inline int vfp_exceptbits_to_host(int target_bits) host_bits |= float_flag_underflow; if (target_bits & 0x10) host_bits |= float_flag_inexact; + if (target_bits & 0x80) + host_bits |= float_flag_input_denormal; return host_bits; } @@ -2310,8 +2314,10 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) } set_float_rounding_mode(i, &env->vfp.fp_status); } - if (changed & (1 << 24)) + if (changed & (1 << 24)) { set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status); + set_flush_inputs_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status); + } if (changed & (1 << 25)) set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status); -- cgit v1.2.3 From 78935c4a4bfec8ef2f4f924cfc35ac09a963e81e Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 22:28:33 +0100 Subject: cirrus: delete GCC 4.6 warnings Commit 92d675d1c1f23f3617e24b63c825074a1d1da44b triggered uninitialized variables warning with GCC 4.6. Fix them by adding zero initializers. Acked-by: Blue Swirl Signed-off-by: Aurelien Jarno --- hw/cirrus_vga.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 833a2eb4be..75d1cc6f57 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -673,9 +673,9 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) { - int sx, sy; - int dx, dy; - int depth; + int sx = 0, sy = 0; + int dx = 0, dy = 0; + int depth = 0; int notify = 0; /* make sure to only copy if it's a plain copy ROP */ -- cgit v1.2.3 From 2a704b137f1acfbd972aa6e9f031c5015c7e28cb Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Fri, 7 Jan 2011 12:50:38 +0100 Subject: cris: Avoid useless tmp in t_gen_cc_jmp() Signed-off-by: Edgar E. Iglesias --- target-cris/translate.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/target-cris/translate.c b/target-cris/translate.c index 4e4606cb25..57d85328db 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -577,20 +577,15 @@ static inline void t_gen_swapr(TCGv d, TCGv s) static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false) { - TCGv btaken; int l1; l1 = gen_new_label(); - btaken = tcg_temp_new(); /* Conditional jmp. */ - tcg_gen_mov_tl(btaken, env_btaken); tcg_gen_mov_tl(env_pc, pc_false); - tcg_gen_brcondi_tl(TCG_COND_EQ, btaken, 0, l1); + tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1); tcg_gen_mov_tl(env_pc, pc_true); gen_set_label(l1); - - tcg_temp_free(btaken); } static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) -- cgit v1.2.3 From c727f47d59641c43ce171126232fd8049296adf6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 Jan 2011 11:05:10 +0000 Subject: linux-user: Implement sync_file_range{,2} syscalls Implement the missing syscalls sync_file_range and sync_file_range2. The latter in particular is used by newer versions of apt on Ubuntu for ARM. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- configure | 18 ++++++++++++++++++ linux-user/strace.list | 6 ++++++ linux-user/syscall.c | 23 +++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/configure b/configure index 47e4cf04c0..831a741c74 100755 --- a/configure +++ b/configure @@ -2075,6 +2075,21 @@ if compile_prog "$ARCH_CFLAGS" "" ; then fallocate=yes fi +# check for sync_file_range +sync_file_range=no +cat > $TMPC << EOF +#include + +int main(void) +{ + sync_file_range(0, 0, 0, 0); + return 0; +} +EOF +if compile_prog "$ARCH_CFLAGS" "" ; then + sync_file_range=yes +fi + # check for dup3 dup3=no cat > $TMPC << EOF @@ -2613,6 +2628,9 @@ fi if test "$fallocate" = "yes" ; then echo "CONFIG_FALLOCATE=y" >> $config_host_mak fi +if test "$sync_file_range" = "yes" ; then + echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak +fi if test "$dup3" = "yes" ; then echo "CONFIG_DUP3=y" >> $config_host_mak fi diff --git a/linux-user/strace.list b/linux-user/strace.list index 97b7f7691d..d7be0e7a68 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1518,3 +1518,9 @@ #ifdef TARGET_NR_utimensat { TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL }, #endif +#ifdef TARGET_NR_sync_file_range +{ TARGET_NR_sync_file_range, "sync_file_range", NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_sync_file_range2 +{ TARGET_NR_sync_file_range2, "sync_file_range2", NULL, NULL, NULL }, +#endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c3e870654d..1939a5f0ec 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7364,6 +7364,29 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_fallocate: ret = get_errno(fallocate(arg1, arg2, arg3, arg4)); break; +#endif +#if defined(CONFIG_SYNC_FILE_RANGE) +#if defined(TARGET_NR_sync_file_range) + case TARGET_NR_sync_file_range: +#if TARGET_ABI_BITS == 32 + ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3), + target_offset64(arg4, arg5), arg6)); +#else + ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4)); +#endif + break; +#endif +#if defined(TARGET_NR_sync_file_range2) + case TARGET_NR_sync_file_range2: + /* This is like sync_file_range but the arguments are reordered */ +#if TARGET_ABI_BITS == 32 + ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4), + target_offset64(arg5, arg6), arg2)); +#else + ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2)); +#endif + break; +#endif #endif default: unimplemented: -- cgit v1.2.3 From cb752a608c514c1f493144f25828b3ff15049f5e Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Fri, 7 Jan 2011 16:18:13 +0100 Subject: cris: Allow more TB chaning Signed-off-by: Edgar E. Iglesias --- target-cris/translate.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/target-cris/translate.c b/target-cris/translate.c index 57d85328db..5184155302 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -1129,7 +1129,7 @@ static void cris_store_direct_jmp(DisasContext *dc) /* Store the direct jmp state into the cpu-state. */ if (dc->jmp == JMP_DIRECT) { tcg_gen_movi_tl(env_btarget, dc->jmp_pc); - tcg_gen_movi_tl(env_btaken, 1); + dc->jmp = JMP_INDIRECT; } } @@ -1139,17 +1139,11 @@ static void cris_prepare_cc_branch (DisasContext *dc, /* 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; dc->jmp_pc = dc->pc + offset; - if (cond != CC_A) - { - dc->jmp = JMP_INDIRECT; - gen_tst_cc (dc, env_btaken, cond); - tcg_gen_movi_tl(env_btarget, dc->jmp_pc); - } else { - /* Allow chaining. */ - dc->jmp = JMP_DIRECT; - } + gen_tst_cc (dc, env_btaken, cond); + tcg_gen_movi_tl(env_btarget, dc->jmp_pc); } @@ -1161,8 +1155,7 @@ static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type) before the actual jump. */ dc->delayed_branch = 2; dc->jmp = type; - if (type == JMP_INDIRECT) - tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_movi_tl(env_btaken, 1); } static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr) @@ -3315,8 +3308,24 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, 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->jmp == JMP_DIRECT) { - dc->is_jmp = DISAS_NEXT; + int l1; + + l1 = gen_new_label(); + cris_evaluate_flags(dc); + + /* Conditional jmp. */ + tcg_gen_brcondi_tl(TCG_COND_EQ, + env_btaken, 0, l1); + gen_goto_tb(dc, 1, dc->jmp_pc); + gen_set_label(l1); + gen_goto_tb(dc, 0, dc->pc); + dc->is_jmp = DISAS_TB_JUMP; + dc->jmp = JMP_NOJMP; } else { t_gen_cc_jmp(env_btarget, tcg_const_tl(dc->pc)); @@ -3336,16 +3345,10 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, && (dc->pc < next_page_start) && num_insns < max_insns); - if (dc->tb_flags != orig_flags) { - dc->cpustate_changed = 1; - } - if (dc->clear_locked_irq) t_gen_mov_env_TN(locked_irq, tcg_const_tl(0)); npc = dc->pc; - if (dc->jmp == JMP_DIRECT && !dc->delayed_branch) - npc = dc->jmp_pc; if (tb->cflags & CF_LAST_IO) gen_io_end(); -- cgit v1.2.3 From d2ef05bb44e044e30f779ed9c4882c3c8299350d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 Jan 2011 15:04:17 +0000 Subject: linux-user: Support ioctls whose parameter size is not constant Some ioctls (for example FS_IOC_FIEMAP) use structures whose size is not constant. The generic argument conversion code in do_ioctl() cannot handle this, so add support for implementing a special-case handler for a particular ioctl which does the conversion itself. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1939a5f0ec..970efe3bdc 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2965,13 +2965,19 @@ enum { #undef STRUCT #undef STRUCT_SPECIAL -typedef struct IOCTLEntry { +typedef struct IOCTLEntry IOCTLEntry; + +typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, abi_long cmd, abi_long arg); + +struct IOCTLEntry { unsigned int target_cmd; unsigned int host_cmd; const char *name; int access; + do_ioctl_fn *do_ioctl; const argtype arg_type[5]; -} IOCTLEntry; +}; #define IOC_R 0x0001 #define IOC_W 0x0002 @@ -2981,7 +2987,9 @@ typedef struct IOCTLEntry { static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ - { TARGET_ ## cmd, cmd, #cmd, access, { __VA_ARGS__ } }, + { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, +#define IOCTL_SPECIAL(cmd, access, dofn, ...) \ + { TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } }, #include "ioctls.h" { 0, 0, }, }; @@ -3011,6 +3019,10 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg) #if defined(DEBUG) gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name); #endif + if (ie->do_ioctl) { + return ie->do_ioctl(ie, buf_temp, fd, cmd, arg); + } + switch(arg_type[0]) { case TYPE_NULL: /* no argument */ -- cgit v1.2.3 From 285da2b9a83353703d07e141fdb447e82944146c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 Jan 2011 15:04:18 +0000 Subject: linux-user: Implement FS_IOC_FIEMAP ioctl Implement the FS_IOC_FIEMAP ioctl using the new support for custom handling of ioctls; this is needed because the struct that is passed includes a variable-length array. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/ioctls.h | 4 +++ linux-user/syscall.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 1 + linux-user/syscall_types.h | 16 +++++++++ 4 files changed, 109 insertions(+) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 769e1bcb81..538e2572bb 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -76,6 +76,10 @@ #ifdef FIGETBSZ IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG)) #endif +#ifdef FS_IOC_FIEMAP + IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap, + MK_PTR(MK_STRUCT(STRUCT_fiemap))) +#endif IOCTL(SIOCATMARK, 0, TYPE_NULL) IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 970efe3bdc..f10e17ae23 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -83,6 +83,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include +#include #include #include #include "linux_loop.h" @@ -2985,6 +2986,93 @@ struct IOCTLEntry { #define MAX_STRUCT_SIZE 4096 +/* So fiemap access checks don't overflow on 32 bit systems. + * This is very slightly smaller than the limit imposed by + * the underlying kernel. + */ +#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \ + / sizeof(struct fiemap_extent)) + +static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, abi_long cmd, abi_long arg) +{ + /* The parameter for this ioctl is a struct fiemap followed + * by an array of struct fiemap_extent whose size is set + * in fiemap->fm_extent_count. The array is filled in by the + * ioctl. + */ + int target_size_in, target_size_out; + struct fiemap *fm; + const argtype *arg_type = ie->arg_type; + const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) }; + void *argptr, *p; + abi_long ret; + int i, extent_size = thunk_type_size(extent_arg_type, 0); + uint32_t outbufsz; + int free_fm = 0; + + assert(arg_type[0] == TYPE_PTR); + assert(ie->access == IOC_RW); + arg_type++; + target_size_in = thunk_type_size(arg_type, 0); + argptr = lock_user(VERIFY_READ, arg, target_size_in, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + fm = (struct fiemap *)buf_temp; + if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) { + return -TARGET_EINVAL; + } + + outbufsz = sizeof (*fm) + + (sizeof(struct fiemap_extent) * fm->fm_extent_count); + + if (outbufsz > MAX_STRUCT_SIZE) { + /* We can't fit all the extents into the fixed size buffer. + * Allocate one that is large enough and use it instead. + */ + fm = malloc(outbufsz); + if (!fm) { + return -TARGET_ENOMEM; + } + memcpy(fm, buf_temp, sizeof(struct fiemap)); + free_fm = 1; + } + ret = get_errno(ioctl(fd, ie->host_cmd, fm)); + if (!is_error(ret)) { + target_size_out = target_size_in; + /* An extent_count of 0 means we were only counting the extents + * so there are no structs to copy + */ + if (fm->fm_extent_count != 0) { + target_size_out += fm->fm_mapped_extents * extent_size; + } + argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0); + if (!argptr) { + ret = -TARGET_EFAULT; + } else { + /* Convert the struct fiemap */ + thunk_convert(argptr, fm, arg_type, THUNK_TARGET); + if (fm->fm_extent_count != 0) { + p = argptr + target_size_in; + /* ...and then all the struct fiemap_extents */ + for (i = 0; i < fm->fm_mapped_extents; i++) { + thunk_convert(p, &fm->fm_extents[i], extent_arg_type, + THUNK_TARGET); + p += extent_size; + } + } + unlock_user(argptr, arg, target_size_out); + } + } + if (free_fm) { + free(fm); + } + return ret; +} + static IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 20c93d0f7f..d02a9bf401 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -783,6 +783,7 @@ struct target_pollfd { #define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */ #define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ #define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ +#define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap) /* cdrom commands */ #define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */ diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 340dbd367f..0e67cd8f30 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -165,3 +165,19 @@ STRUCT(vt_stat, TYPE_SHORT, /* v_active */ TYPE_SHORT, /* v_signal */ TYPE_SHORT) /* v_state */ + +STRUCT(fiemap_extent, + TYPE_ULONGLONG, /* fe_logical */ + TYPE_ULONGLONG, /* fe_physical */ + TYPE_ULONGLONG, /* fe_length */ + MK_ARRAY(TYPE_ULONGLONG, 2), /* fe_reserved64[2] */ + TYPE_INT, /* fe_flags */ + MK_ARRAY(TYPE_INT, 3)) /* fe_reserved[3] */ + +STRUCT(fiemap, + TYPE_ULONGLONG, /* fm_start */ + TYPE_ULONGLONG, /* fm_length */ + TYPE_INT, /* fm_flags */ + TYPE_INT, /* fm_mapped_extents */ + TYPE_INT, /* fm_extent_count */ + TYPE_INT) /* fm_reserved */ -- cgit v1.2.3 From 2bed652fc596dee09f27dd7ab20528cf5eaf9203 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 Jan 2011 18:34:43 +0000 Subject: softfloat: Implement floatx80_is_any_nan() and float128_is_any_nan() Implement versions of float*_is_any_nan() for the floatx80 and float128 types. Acked-by: Aurelien Jarno Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- fpu/softfloat.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 15052cc470..a6d0f16b42 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -489,6 +489,11 @@ INLINE int floatx80_is_zero(floatx80 a) return (a.high & 0x7fff) == 0 && a.low == 0; } +INLINE int floatx80_is_any_nan(floatx80 a) +{ + return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); +} + #endif #ifdef FLOAT128 @@ -556,6 +561,12 @@ INLINE int float128_is_zero(float128 a) return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0; } +INLINE int float128_is_any_nan(float128 a) +{ + return ((a.high >> 48) & 0x7fff) == 0x7fff && + ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0)); +} + #endif #else /* CONFIG_SOFTFLOAT */ -- cgit v1.2.3 From 3ebe80c2993205ad6ad7ee0e800068f08932775c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 Jan 2011 18:34:44 +0000 Subject: linux-user: Fix incorrect NaN detection in ARM nwfpe emulation The code in the linux-user ARM nwfpe emulation was incorrectly checking only for quiet NaNs when it should have been checking for any kind of NaN. This is probably because the code in question was taken from the Linux kernel, whose copy of the softfloat library had been modified so that float*_is_nan() returned true for all NaNs, not just quiet ones. The qemu equivalent function is float*_is_any_nan(), so use that. NB that this code is really obsolete since nobody uses FPE for actual arithmetic now; this is just cleanup following the recent renaming of the NaN related functions. Acked-by: Aurelien Jarno Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/arm/nwfpe/fpa11_cprt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/linux-user/arm/nwfpe/fpa11_cprt.c b/linux-user/arm/nwfpe/fpa11_cprt.c index 0e61b585a0..be54e9515d 100644 --- a/linux-user/arm/nwfpe/fpa11_cprt.c +++ b/linux-user/arm/nwfpe/fpa11_cprt.c @@ -199,21 +199,21 @@ static unsigned int PerformComparison(const unsigned int opcode) { case typeSingle: //printk("single.\n"); - if (float32_is_quiet_nan(fpa11->fpreg[Fn].fSingle)) + if (float32_is_any_nan(fpa11->fpreg[Fn].fSingle)) goto unordered; rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); break; case typeDouble: //printk("double.\n"); - if (float64_is_quiet_nan(fpa11->fpreg[Fn].fDouble)) + if (float64_is_any_nan(fpa11->fpreg[Fn].fDouble)) goto unordered; rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); break; case typeExtended: //printk("extended.\n"); - if (floatx80_is_quiet_nan(fpa11->fpreg[Fn].fExtended)) + if (floatx80_is_any_nan(fpa11->fpreg[Fn].fExtended)) goto unordered; rFn = fpa11->fpreg[Fn].fExtended; break; @@ -225,7 +225,7 @@ static unsigned int PerformComparison(const unsigned int opcode) { //printk("Fm is a constant: #%d.\n",Fm); rFm = getExtendedConstant(Fm); - if (floatx80_is_quiet_nan(rFm)) + if (floatx80_is_any_nan(rFm)) goto unordered; } else @@ -235,21 +235,21 @@ static unsigned int PerformComparison(const unsigned int opcode) { case typeSingle: //printk("single.\n"); - if (float32_is_quiet_nan(fpa11->fpreg[Fm].fSingle)) + if (float32_is_any_nan(fpa11->fpreg[Fm].fSingle)) goto unordered; rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); break; case typeDouble: //printk("double.\n"); - if (float64_is_quiet_nan(fpa11->fpreg[Fm].fDouble)) + if (float64_is_any_nan(fpa11->fpreg[Fm].fDouble)) goto unordered; rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); break; case typeExtended: //printk("extended.\n"); - if (floatx80_is_quiet_nan(fpa11->fpreg[Fm].fExtended)) + if (floatx80_is_any_nan(fpa11->fpreg[Fm].fExtended)) goto unordered; rFm = fpa11->fpreg[Fm].fExtended; break; -- cgit v1.2.3 From 2e8785acc601f72dd10ce19929c455689fc2649d Mon Sep 17 00:00:00 2001 From: Wolfgang Schildbach Date: Mon, 6 Dec 2010 15:06:05 +0000 Subject: Fix commandline handling for ARM semihosted executables Use the copy of the command line that loader_build_argptr() sets up in guest memory as the command line to return from the ARM SYS_GET_CMDLINE semihosting call. Previously we were using a pointer to memory which had already been freed before the guest program started. This fixes https://bugs.launchpad.net/qemu/+bug/673613 . Signed-off-by: Wolfgang Schildbach Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- arm-semi.c | 79 ++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/arm-semi.c b/arm-semi.c index 0687b03006..1d5179b601 100644 --- a/arm-semi.c +++ b/arm-semi.c @@ -373,45 +373,64 @@ uint32_t do_arm_semihosting(CPUState *env) #ifdef CONFIG_USER_ONLY /* Build a commandline from the original argv. */ { - char **arg = ts->info->host_argv; - int len = ARG(1); - /* lock the buffer on the ARM side */ - char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0); + char *arm_cmdline_buffer; + const char *host_cmdline_buffer; - if (!cmdline_buffer) - /* FIXME - should this error code be -TARGET_EFAULT ? */ - return (uint32_t)-1; + unsigned int i; + unsigned int arm_cmdline_len = ARG(1); + unsigned int host_cmdline_len = + ts->info->arg_end-ts->info->arg_start; + + if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) { + return -1; /* not enough space to store command line */ + } - s = cmdline_buffer; - while (*arg && len > 2) { - int n = strlen(*arg); + if (!host_cmdline_len) { + /* We special-case the "empty command line" case (argc==0). + Just provide the terminating 0. */ + arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0); + arm_cmdline_buffer[0] = 0; + unlock_user(arm_cmdline_buffer, ARG(0), 1); - if (s != cmdline_buffer) { - *(s++) = ' '; - len--; - } - if (n >= len) - n = len - 1; - memcpy(s, *arg, n); - s += n; - len -= n; - arg++; + /* Adjust the commandline length argument. */ + SET_ARG(1, 0); + return 0; } - /* Null terminate the string. */ - *s = 0; - len = s - cmdline_buffer; - /* Unlock the buffer on the ARM side. */ - unlock_user(cmdline_buffer, ARG(0), len); + /* lock the buffers on the ARM side */ + arm_cmdline_buffer = + lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0); + host_cmdline_buffer = + lock_user(VERIFY_READ, ts->info->arg_start, + host_cmdline_len, 1); - /* Adjust the commandline length argument. */ - SET_ARG(1, len); + if (arm_cmdline_buffer && host_cmdline_buffer) + { + /* the last argument is zero-terminated; + no need for additional termination */ + memcpy(arm_cmdline_buffer, host_cmdline_buffer, + host_cmdline_len); - /* Return success if commandline fit into buffer. */ - return *arg ? -1 : 0; + /* separate arguments by white spaces */ + for (i = 0; i < host_cmdline_len-1; i++) { + if (arm_cmdline_buffer[i] == 0) { + arm_cmdline_buffer[i] = ' '; + } + } + + /* Adjust the commandline length argument. */ + SET_ARG(1, host_cmdline_len-1); + } + + /* Unlock the buffers on the ARM side. */ + unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len); + unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0); + + /* Return success if we could return a commandline. */ + return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1; } #else - return -1; + return -1; #endif case SYS_HEAPINFO: { -- cgit v1.2.3 From 67af42ac5a6227d61a8ef4ba7289ada9418f2fb8 Mon Sep 17 00:00:00 2001 From: Wolfgang Schildbach Date: Mon, 6 Dec 2010 15:06:06 +0000 Subject: Remove dead code for ARM semihosting commandline handling There are some bits in the code which were used to store the commandline for the semihosting call. These bits are now write-only and can be removed. Signed-off-by: Wolfgang Schildbach Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- bsd-user/bsdload.c | 2 -- bsd-user/qemu.h | 1 - linux-user/linuxload.c | 2 -- linux-user/qemu.h | 1 - 4 files changed, 6 deletions(-) diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index 14a93bf39b..6d9bb6fb4e 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -176,8 +176,6 @@ int loader_exec(const char * filename, char ** argv, char ** envp, retval = prepare_binprm(&bprm); - infop->host_argv = argv; - if(retval>=0) { if (bprm.buf[0] == 0x7f && bprm.buf[1] == 'E' diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 976361622d..e343894ab1 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -50,7 +50,6 @@ struct image_info { abi_ulong entry; abi_ulong code_offset; abi_ulong data_offset; - char **host_argv; int personality; }; diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 9ee27c3558..ac8c486c5f 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -174,8 +174,6 @@ int loader_exec(const char * filename, char ** argv, char ** envp, retval = prepare_binprm(bprm); - infop->host_argv = argv; - if(retval>=0) { if (bprm->buf[0] == 0x7f && bprm->buf[1] == 'E' diff --git a/linux-user/qemu.h b/linux-user/qemu.h index e66a02bce3..32de2413f8 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -50,7 +50,6 @@ struct image_info { abi_ulong saved_auxv; abi_ulong arg_start; abi_ulong arg_end; - char **host_argv; int personality; }; -- cgit v1.2.3 From c69806ab82760a2e5ca880d41e8786276c838152 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 22:43:13 +0100 Subject: tcg/arm: fix branch target change during code retranslation QEMU uses code retranslation to restore the CPU state when an exception happens. For it to work the retranslation must not modify the generated code. This is what is currently implemented in ARM TCG. However on CPU that don't have icache/dcache/memory synchronised like ARM, this requirement is stronger and code retranslation must not modify the generated code "atomically", as the cache line might be flushed at any moment (interrupt, exception, task switching), even if not triggered by QEMU. The probability for this to happen is very low, and depends on cache size and associativiy, machine load, interrupts, so the symptoms are might happen randomly. This requirement is currently not followed in tcg/arm, for the load/store code, which basically has the following structure: 1) tlb access code is written 2) conditional fast path code is written 3) branch is written with a temporary target 4) slow path code is written 5) branch target is updated The cache lines corresponding to the retranslated code is not flushed after code retranslation as the generated code is supposed to be the same. However if the cache line corresponding to the branch instruction is flushed between step 3 and 5, and is not flushed again before the code is executed again, the branch target is wrong. In the guest, the symptoms are MMU page fault at a random addresses, which leads to kernel page fault or segmentation faults. The patch fixes this issue by avoiding writing the branch target until it is known, that is by writing only the branch instruction first, and later only the offset. This fixes booting linux guests on ARM hosts (tested: arm, i386, mips, mipsel, sh4, sparc). Acked-by: Edgar E. Iglesias Signed-off-by: Aurelien Jarno --- tcg/arm/tcg-target.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index a3af5b222e..9def2e58fb 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -113,12 +113,25 @@ static const int tcg_target_call_oarg_regs[2] = { TCG_REG_R0, TCG_REG_R1 }; +static inline void reloc_abs32(void *code_ptr, tcg_target_long target) +{ + *(uint32_t *) code_ptr = target; +} + +static inline void reloc_pc24(void *code_ptr, tcg_target_long target) +{ + uint32_t offset = ((target - ((tcg_target_long) code_ptr + 8)) >> 2); + + *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & ~0xffffff) + | (offset & 0xffffff); +} + static void patch_reloc(uint8_t *code_ptr, int type, tcg_target_long value, tcg_target_long addend) { switch (type) { case R_ARM_ABS32: - *(uint32_t *) code_ptr = value; + reloc_abs32(code_ptr, value); break; case R_ARM_CALL: @@ -127,8 +140,7 @@ static void patch_reloc(uint8_t *code_ptr, int type, tcg_abort(); case R_ARM_PC24: - *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & 0xff000000) | - (((value - ((tcg_target_long) code_ptr + 8)) >> 2) & 0xffffff); + reloc_pc24(code_ptr, value); break; } } @@ -1031,7 +1043,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) } label_ptr = (void *) s->code_ptr; - tcg_out_b(s, COND_EQ, 8); + tcg_out_b_noaddr(s, COND_EQ); /* TODO: move this code to where the constants pool will be */ if (addr_reg != TCG_REG_R0) { @@ -1076,7 +1088,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) break; } - *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; + reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr); #else /* !CONFIG_SOFTMMU */ if (GUEST_BASE) { uint32_t offset = GUEST_BASE; @@ -1245,7 +1257,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) } label_ptr = (void *) s->code_ptr; - tcg_out_b(s, COND_EQ, 8); + tcg_out_b_noaddr(s, COND_EQ); /* TODO: move this code to where the constants pool will be */ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, @@ -1317,7 +1329,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) if (opc == 3) tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10); - *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; + reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr); #else /* !CONFIG_SOFTMMU */ if (GUEST_BASE) { uint32_t offset = GUEST_BASE; @@ -1399,7 +1411,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, /* Direct jump method */ #if defined(USE_DIRECT_JUMP) s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; - tcg_out_b(s, COND_AL, 8); + tcg_out_b_noaddr(s, COND_AL); #else tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4); s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; -- cgit v1.2.3 From 9a3abc21a61f95799c1f301b0b480a98a29fa0ff Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 22:43:13 +0100 Subject: tcg/arm: fix qemu_st64 for big endian targets Due to a typo, qemu_st64 doesn't properly byteswap the 32-bit low word of a 64 bit word before saving it. This patch fixes that. Acked-by: Andrzej Zaborowski Signed-off-by: Aurelien Jarno --- tcg/arm/tcg-target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 9def2e58fb..08c44c1123 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -1248,7 +1248,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg2); tcg_out_st32_rwb(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, addr_reg); tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg); - tcg_out_st32_12(s, COND_EQ, data_reg, TCG_REG_R1, 4); + tcg_out_st32_12(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, 4); } else { tcg_out_st32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg); tcg_out_st32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4); -- cgit v1.2.3 From d43ffce14023df871d6065eb864d1f41eb441f37 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 22:43:14 +0100 Subject: tcg/mips: fix branch target change during code retranslation TCG on MIPS was trying to avoid changing the branch offset, but didn't due to a stupid typo. Fix it. Signed-off-by: Aurelien Jarno --- tcg/mips/tcg-target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 2af7a2e818..4e92a50e6f 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -352,7 +352,7 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int i static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs) { /* We need to keep the offset unchanged for retranslation */ - uint16_t offset = (uint16_t)(*(uint32_t *) &s->code_ptr); + uint16_t offset = (uint16_t)(*(uint32_t *) s->code_ptr); tcg_out_opc_imm(s, opc, rt, rs, offset); } -- cgit v1.2.3 From b6c9c9401c2f9eaf3ef93770c258d819ede7e11a Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Sat, 8 Jan 2011 17:53:29 +0100 Subject: ossaudio: add endianness support for VoiceIn Signed-off-by: Michael Walle Signed-off-by: malc --- audio/ossaudio.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 42bffaeafd..d7a55e5441 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -161,7 +161,7 @@ static int oss_write (SWVoiceOut *sw, void *buf, int len) return audio_pcm_sw_write (sw, buf, len); } -static int aud_to_ossfmt (audfmt_e fmt) +static int aud_to_ossfmt (audfmt_e fmt, int endianness) { switch (fmt) { case AUD_FMT_S8: @@ -171,10 +171,20 @@ static int aud_to_ossfmt (audfmt_e fmt) return AFMT_U8; case AUD_FMT_S16: - return AFMT_S16_LE; + if (endianness) { + return AFMT_S16_BE; + } + else { + return AFMT_S16_LE; + } case AUD_FMT_U16: - return AFMT_U16_LE; + if (endianness) { + return AFMT_U16_BE; + } + else { + return AFMT_U16_LE; + } default: dolog ("Internal logic error: Bad audio format %d\n", fmt); @@ -516,7 +526,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as) oss->fd = -1; - req.fmt = aud_to_ossfmt (as->fmt); + req.fmt = aud_to_ossfmt (as->fmt, as->endianness); req.freq = as->freq; req.nchannels = as->nchannels; req.fragsize = conf.fragsize; @@ -682,7 +692,7 @@ static int oss_init_in (HWVoiceIn *hw, struct audsettings *as) oss->fd = -1; - req.fmt = aud_to_ossfmt (as->fmt); + req.fmt = aud_to_ossfmt (as->fmt, as->endianness); req.freq = as->freq; req.nchannels = as->nchannels; req.fragsize = conf.fragsize; -- cgit v1.2.3 From d66bddd7a4535cca3fc9e98c3195a7411779693c Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Sat, 8 Jan 2011 17:53:30 +0100 Subject: alsaaudio: add endianness support for VoiceIn Signed-off-by: Michael Walle Signed-off-by: malc --- audio/alsaaudio.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index 07412030c2..727b9f84c3 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -318,7 +318,7 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len) return audio_pcm_sw_write (sw, buf, len); } -static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt) +static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness) { switch (fmt) { case AUD_FMT_S8: @@ -328,16 +328,36 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt) return SND_PCM_FORMAT_U8; case AUD_FMT_S16: - return SND_PCM_FORMAT_S16_LE; + if (endianness) { + return SND_PCM_FORMAT_S16_BE; + } + else { + return SND_PCM_FORMAT_S16_LE; + } case AUD_FMT_U16: - return SND_PCM_FORMAT_U16_LE; + if (endianness) { + return SND_PCM_FORMAT_U16_BE; + } + else { + return SND_PCM_FORMAT_U16_LE; + } case AUD_FMT_S32: - return SND_PCM_FORMAT_S32_LE; + if (endianness) { + return SND_PCM_FORMAT_S32_BE; + } + else { + return SND_PCM_FORMAT_S32_LE; + } case AUD_FMT_U32: - return SND_PCM_FORMAT_U32_LE; + if (endianness) { + return SND_PCM_FORMAT_U32_BE; + } + else { + return SND_PCM_FORMAT_U32_LE; + } default: dolog ("Internal logic error: Bad audio format %d\n", fmt); @@ -809,7 +829,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as) snd_pcm_t *handle; struct audsettings obt_as; - req.fmt = aud_to_alsafmt (as->fmt); + req.fmt = aud_to_alsafmt (as->fmt, as->endianness); req.freq = as->freq; req.nchannels = as->nchannels; req.period_size = conf.period_size_out; @@ -918,7 +938,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as) snd_pcm_t *handle; struct audsettings obt_as; - req.fmt = aud_to_alsafmt (as->fmt); + req.fmt = aud_to_alsafmt (as->fmt, as->endianness); req.freq = as->freq; req.nchannels = as->nchannels; req.period_size = conf.period_size_in; -- cgit v1.2.3 From 1a20a032ccbb5800bfdfc75accfcff2ac67f5bcb Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 9 Jan 2011 14:43:33 +0000 Subject: usb-bsd: fix a file descriptor leak Fix a file descriptor leak reported by cppcheck: [/src/qemu/usb-bsd.c:392]: (error) Resource leak: bfd [/src/qemu/usb-bsd.c:388]: (error) Resource leak: dfd Rearrange the code to avoid descriptor leaks. Also add braces as needed. Signed-off-by: Blue Swirl --- usb-bsd.c | 71 +++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/usb-bsd.c b/usb-bsd.c index 48567a3bae..abcb60c6f1 100644 --- a/usb-bsd.c +++ b/usb-bsd.c @@ -306,14 +306,15 @@ USBDevice *usb_host_device_open(const char *devname) { struct usb_device_info bus_info, dev_info; USBDevice *d = NULL; - USBHostDevice *dev; + USBHostDevice *dev, *ret = NULL; char ctlpath[PATH_MAX + 1]; char buspath[PATH_MAX + 1]; int bfd, dfd, bus, address, i; int ugendebug = UGEN_DEBUG_LEVEL; - if (usb_host_find_device(&bus, &address, devname) < 0) - return NULL; + if (usb_host_find_device(&bus, &address, devname) < 0) { + goto fail; + } snprintf(buspath, PATH_MAX, "/dev/usb%d", bus); @@ -323,7 +324,7 @@ USBDevice *usb_host_device_open(const char *devname) printf("usb_host_device_open: failed to open usb bus - %s\n", strerror(errno)); #endif - return NULL; + goto fail; } bus_info.udi_addr = address; @@ -332,7 +333,7 @@ USBDevice *usb_host_device_open(const char *devname) printf("usb_host_device_open: failed to grab bus information - %s\n", strerror(errno)); #endif - return NULL; + goto fail_bfd; } #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) @@ -350,46 +351,52 @@ USBDevice *usb_host_device_open(const char *devname) ctlpath, strerror(errno)); #endif } + goto fail_dfd; } - if (dfd >= 0) { - if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) { + if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) { #ifdef DEBUG - printf("usb_host_device_open: failed to grab device info - %s\n", - strerror(errno)); + printf("usb_host_device_open: failed to grab device info - %s\n", + strerror(errno)); #endif - goto fail; - } + goto fail_dfd; + } - d = usb_create(NULL /* FIXME */, "usb-host"); - dev = DO_UPCAST(USBHostDevice, dev, d); + d = usb_create(NULL /* FIXME */, "usb-host"); + dev = DO_UPCAST(USBHostDevice, dev, d); - if (dev_info.udi_speed == 1) - dev->dev.speed = USB_SPEED_LOW - 1; - else - dev->dev.speed = USB_SPEED_FULL - 1; + if (dev_info.udi_speed == 1) { + dev->dev.speed = USB_SPEED_LOW - 1; + } else { + dev->dev.speed = USB_SPEED_FULL - 1; + } - if (strncmp(dev_info.udi_product, "product", 7) != 0) - pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc), - dev_info.udi_product); - else - snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc), - "host:%s", devname); + if (strncmp(dev_info.udi_product, "product", 7) != 0) { + pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc), + dev_info.udi_product); + } else { + snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc), + "host:%s", devname); + } - pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/"); - pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]); + pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/"); + pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]); - /* Mark the endpoints as not yet open */ - for (i = 0; i < USB_MAX_ENDPOINTS; i++) - dev->ep_fd[i] = -1; + /* Mark the endpoints as not yet open */ + for (i = 0; i < USB_MAX_ENDPOINTS; i++) { + dev->ep_fd[i] = -1; + } - ioctl(dfd, USB_SETDEBUG, &ugendebug); + ioctl(dfd, USB_SETDEBUG, &ugendebug); - return (USBDevice *)dev; - } + ret = (USBDevice *)dev; +fail_dfd: + close(dfd); +fail_bfd: + close(bfd); fail: - return NULL; + return ret; } static struct USBDeviceInfo usb_host_dev_info = { -- cgit v1.2.3 From 0d6753e5b3115c09313114afcdf554c34670359a Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 7 Jan 2011 18:59:13 +0100 Subject: qemu-doc: Clean whitespace Remove blanks at line endings. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- qemu-doc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 7ce8999e81..21d8a82956 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -832,7 +832,7 @@ Standard USB keyboard. Will override the PS/2 keyboard (if present). Serial converter. This emulates an FTDI FT232BM chip connected to host character device @var{dev}. The available character devices are the same as for the @code{-serial} option. The @code{vendorid} and @code{productid} options can be -used to override the default 0403:6001. For instance, +used to override the default 0403:6001. For instance, @example usb_add serial:productid=FA00:tcp:192.168.0.2:4444 @end example @@ -2201,7 +2201,7 @@ the address region required by guest applications is reserved on the host. This option is currently only supported on some hosts. @item -R size Pre-allocate a guest virtual address space of the given size (in bytes). -"G", "M", and "k" suffixes may be used when specifying the size. +"G", "M", and "k" suffixes may be used when specifying the size. @end table Debug options: -- cgit v1.2.3 From 576fd0a1cb07f6ee325f70d69ae3a4e2f0b283fc Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 7 Jan 2011 18:59:14 +0100 Subject: qemu-doc: Add missing menu entry Each @section should have a menu entry and a @node entry. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- qemu-doc.texi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 21d8a82956..744ba731e5 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -162,6 +162,7 @@ TODO (no longer available) * pcsys_monitor:: QEMU Monitor * disk_images:: Disk Images * pcsys_network:: Network emulation +* pcsys_other_devs:: Other Devices * direct_linux_boot:: Direct Linux Boot * pcsys_usb:: USB emulation * vnc_security:: VNC security @@ -715,6 +716,7 @@ Using the @option{-net socket} option, it is possible to make VLANs that span several QEMU instances. See @ref{sec_invocation} to have a basic example. +@node pcsys_other_devs @section Other Devices @subsection Inter-VM Shared Memory device -- cgit v1.2.3 From 2d983446ff853490f63eeefeabd7e352843cf856 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 7 Jan 2011 18:59:15 +0100 Subject: qemu-doc: Add missing blanks Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- qemu-doc.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 744ba731e5..a1e6130785 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -203,7 +203,7 @@ Intel 82801AA AC97 Audio compatible sound card @item Intel HD Audio Controller and HDA codec @item -Adlib(OPL2) - Yamaha YM3812 compatible chip +Adlib (OPL2) - Yamaha YM3812 compatible chip @item Gravis Ultrasound GF1 sound card @item @@ -223,7 +223,7 @@ VGA BIOS. QEMU uses YM3812 emulation by Tatsuyuki Satoh. -QEMU uses GUS emulation(GUSEMU32 @url{http://www.deinmeister.de/gusemu/}) +QEMU uses GUS emulation (GUSEMU32 @url{http://www.deinmeister.de/gusemu/}) by Tibor "TS" Schütz. Not that, by default, GUS shares IRQ(7) with parallel ports and so -- cgit v1.2.3 From 40c5c6cd2bb2b6cc2e15fbd071dab956811f3266 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 7 Jan 2011 18:59:16 +0100 Subject: qemu-doc: Spelling fixes neccessary -> necessary Keberos -> Kerberos emuilated -> emulated transciever -> transceiver emulaton -> emulation inital -> initial MingGW -> MinGW Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- qemu-doc.texi | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index a1e6130785..45190f6d3b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -1049,7 +1049,7 @@ qemu [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio The GNU TLS packages provides a command called @code{certtool} which can be used to generate certificates and keys in PEM format. At a minimum it -is neccessary to setup a certificate authority, and issue certificates to +is necessary to setup a certificate authority, and issue certificates to each server. If using certificates for authentication, then each client will also need to be issued a certificate. The recommendation is for the server to keep its certificates in either @code{/etc/pki/qemu} or for @@ -1192,7 +1192,7 @@ keytab: /etc/qemu/krb5.tab For this to work the administrator of your KDC must generate a Kerberos principal for the server, with a name of 'qemu/somehost.example.com@@EXAMPLE.COM' replacing 'somehost.example.com' with the fully qualified host name of the -machine running QEMU, and 'EXAMPLE.COM' with the Keberos Realm. +machine running QEMU, and 'EXAMPLE.COM' with the Kerberos Realm. Other configurations will be left as an exercise for the reader. It should be noted that only Digest-MD5 and GSSAPI provides a SSF layer for data @@ -1774,7 +1774,7 @@ enabled in the kernel, and expect 512M RAM. Kernels for The PBX-A9 board should have CONFIG_SPARSEMEM enabled, CONFIG_REALVIEW_HIGH_PHYS_OFFSET disabled and expect 1024M RAM. -The following devices are emuilated: +The following devices are emulated: @itemize @minus @item @@ -1874,7 +1874,7 @@ Secure Digital card connected to OMAP MMC/SD host @item Three OMAP on-chip UARTs and on-chip STI debugging console @item -A Bluetooth(R) transciever and HCI connected to an UART +A Bluetooth(R) transceiver and HCI connected to an UART @item Mentor Graphics "Inventra" dual-role USB controller embedded in a TI TUSB6010 chip - only USB host mode is supported @@ -1936,7 +1936,7 @@ MV88W8618 audio controller, WM8750 CODEC and mixer @end itemize The Siemens SX1 models v1 and v2 (default) basic emulation. -The emulaton includes the following elements: +The emulation includes the following elements: @itemize @minus @item @@ -2192,7 +2192,7 @@ Set the x86 stack size in bytes (default=524288) Select CPU model (-cpu ? for list and additional feature selection) @item -ignore-environment Start with an empty environment. Without this option, -the inital environment is a copy of the caller's environment. +the initial environment is a copy of the caller's environment. @item -E @var{var}=@var{value} Set environment @var{var} to @var{value}. @item -U @var{var} @@ -2422,7 +2422,7 @@ Set the library root path (default=/) Set the stack size in bytes (default=524288) @item -ignore-environment Start with an empty environment. Without this option, -the inital environment is a copy of the caller's environment. +the initial environment is a copy of the caller's environment. @item -E @var{var}=@var{value} Set environment @var{var} to @var{value}. @item -U @var{var} @@ -2495,7 +2495,7 @@ correct SDL directory when invoked. @item Install the MinGW version of zlib and make sure @file{zlib.h} and @file{libz.dll.a} are in -MingGW's default header and linker search paths. +MinGW's default header and linker search paths. @item Extract the current version of QEMU. @@ -2530,7 +2530,7 @@ the QEMU configuration script. @item Install the MinGW version of zlib and make sure @file{zlib.h} and @file{libz.dll.a} are in -MingGW's default header and linker search paths. +MinGW's default header and linker search paths. @item Configure QEMU for Windows cross compilation: @@ -2539,7 +2539,7 @@ PATH=/usr/i686-pc-mingw32/sys-root/mingw/bin:$PATH ./configure --cross-prefix='i @end example The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-mingw32/sys-root/mingw/bin} and MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}. -We set the @code{PATH} environment variable to ensure the MingW version of @file{sdl-config} is used and +We set the @code{PATH} environment variable to ensure the MinGW version of @file{sdl-config} is used and use --cross-prefix to specify the name of the cross compiler. You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/Qemu}. -- cgit v1.2.3 From e8dc09382289fee771999e135c05e8938900c410 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 7 Jan 2011 21:31:39 +0100 Subject: qemu-tech: Spelling fixes Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- qemu-tech.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-tech.texi b/qemu-tech.texi index 2e2a081d92..138e3ce9ad 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -516,7 +516,7 @@ timers, especially together with the use of bottom halves (BHs). @section Hardware interrupts In order to be faster, QEMU does not check at every basic block if an -hardware interrupt is pending. Instead, the user must asynchrously +hardware interrupt is pending. Instead, the user must asynchronously call a specific function to tell that an interrupt is pending. This function resets the chaining of the currently executing basic block. It ensures that the execution will return soon in the main loop @@ -548,7 +548,7 @@ Linux kernel does. The @code{sigreturn()} system call is emulated to return from the virtual signal handler. Some signals (such as SIGALRM) directly come from the host. Other -signals are synthetized from the virtual CPU exceptions such as SIGFPE +signals are synthesized from the virtual CPU exceptions such as SIGFPE when a division by zero is done (see @code{main.c:cpu_loop()}). The blocked signal mask is still handled by the host Linux kernel so -- cgit v1.2.3 From aa95e3a57fe4c9485c7540ab64c6d4883e4cd01d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 7 Jan 2011 21:34:50 +0100 Subject: tcg/README: Spelling fixes Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- tcg/README | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tcg/README b/tcg/README index 68d27ffa6d..a2b69ddf88 100644 --- a/tcg/README +++ b/tcg/README @@ -75,11 +75,11 @@ destroyed, but local temporaries and globals are preserved. * Helpers: Using the tcg_gen_helper_x_y it is possible to call any function -taking i32, i64 or pointer types. By default, before calling an helper, +taking i32, i64 or pointer types. By default, before calling a helper, all globals are stored at their canonical location and it is assumed -that the function can modify them. This can be overriden by the +that the function can modify them. This can be overridden by the TCG_CALL_CONST function modifier. By default, the helper is allowed to -modify the CPU state or raise an exception. This can be overriden by +modify the CPU state or raise an exception. This can be overridden by the TCG_CALL_PURE function modifier, in which case the call to the function is removed if the return value is not used. @@ -488,7 +488,7 @@ register. the speed of the translation. - Don't hesitate to use helpers for complicated or seldom used target - intructions. There is little performance advantage in using TCG to + instructions. There is little performance advantage in using TCG to implement target instructions taking more than about twenty TCG instructions. -- cgit v1.2.3 From 759c90ba3d4f8dcb748d7719f7ea82b181ffd590 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 9 Jan 2011 03:45:45 -0500 Subject: tcg: fix typo in readme Signed-off-by: Mike Frysinger Signed-off-by: Blue Swirl --- tcg/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/README b/tcg/README index a2b69ddf88..a18a87ffcd 100644 --- a/tcg/README +++ b/tcg/README @@ -364,7 +364,7 @@ formed from two 32-bit arguments. The result is a 32-bit value. ********* QEMU specific operations -* tb_exit t0 +* exit_tb t0 Exit the current TB and return the value t0 (word type). -- cgit v1.2.3 From c0f809c46aa271f29a9e6268cdeda1f21301a8ef Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 9 Jan 2011 23:53:45 +0100 Subject: target-sh4: implement writes to mmaped ITLB Some Linux kernels seems to implement ITLB/UTLB flushing through by writing all TLB entries through the memory mapped interface instead of writing one to MMUCR.TI. Implement memory mapped ITLB write interface so that such kernels can boot. This fixes https://bugs.launchpad.net/bugs/700774 . Signed-off-by: Aurelien Jarno --- hw/sh7750.c | 2 ++ target-sh4/cpu.h | 2 ++ target-sh4/helper.c | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/hw/sh7750.c b/hw/sh7750.c index 9e54ad1904..36b702f628 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -670,6 +670,8 @@ static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr, /* do nothing */ break; case MM_ITLB_ADDR: + cpu_sh4_write_mmaped_itlb_addr(s->cpu, addr, mem_value); + break; case MM_ITLB_DATA: /* XXXXX */ abort(); diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index e19776643b..8ccf25cafb 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -172,6 +172,8 @@ void do_interrupt(CPUSH4State * env); void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf); #if !defined(CONFIG_USER_ONLY) void cpu_sh4_invalidate_tlb(CPUSH4State *s); +void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr, + uint32_t mem_value); void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, uint32_t mem_value); #endif diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 9e70352311..863886b89e 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -544,6 +544,25 @@ void cpu_load_tlb(CPUSH4State * env) tlb_flush(s, 1); } +void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr, + uint32_t mem_value) +{ + uint32_t vpn = (mem_value & 0xfffffc00) >> 10; + uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); + uint8_t asid = (uint8_t)(mem_value & 0x000000ff); + + int index = (addr & 0x00003f00) >> 8; + tlb_t * entry = &s->itlb[index]; + if (entry->v) { + /* Overwriting valid entry in itlb. */ + target_ulong address = entry->vpn << 10; + tlb_flush_page(s, address); + } + entry->asid = asid; + entry->vpn = vpn; + entry->v = v; +} + void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, uint32_t mem_value) { -- cgit v1.2.3 From 829a49274f6741c0f3d3a2ba4698baf381a7e264 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 9 Jan 2011 23:53:45 +0100 Subject: target-sh4: improve TLB SH4 is using 16-bit instructions which means most of the constants are loaded through a constant pool at the end of the subroutine. The same memory page is therefore accessed in exec and read mode. With the current implementation, a QEMU TLB entry is set to read or read/write mode after an UTLB search and to exec mode after an ITLB search, which causes a lot of TLB exceptions to switch from read or read/write to exec and vice versa. This patch optimizes that by already setting the QEMU TLB entry in read or read/write mode when an UTLB entry is copied into ITLB (during an ITLB miss). This improve the emulation speed by about 14%. Signed-off-by: Aurelien Jarno --- target-sh4/helper.c | 65 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 863886b89e..2343366762 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -280,35 +280,40 @@ static void increment_urc(CPUState * env) env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); } -/* Find itlb entry - update itlb from utlb if necessary and asked for +/* Copy and utlb entry into itlb + Return entry +*/ +static int copy_utlb_entry_itlb(CPUState *env, int utlb) +{ + int itlb; + + tlb_t * ientry; + itlb = itlb_replacement(env); + ientry = &env->itlb[itlb]; + if (ientry->v) { + tlb_flush_page(env, ientry->vpn << 10); + } + *ientry = env->utlb[utlb]; + update_itlb_use(env, itlb); + return itlb; +} + +/* Find itlb entry Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE - Update the itlb from utlb if update is not 0 */ static int find_itlb_entry(CPUState * env, target_ulong address, - int use_asid, int update) + int use_asid) { - int e, n; + int e; e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid); - if (e == MMU_DTLB_MULTIPLE) + if (e == MMU_DTLB_MULTIPLE) { e = MMU_ITLB_MULTIPLE; - else if (e == MMU_DTLB_MISS && update) { - e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); - if (e >= 0) { - tlb_t * ientry; - n = itlb_replacement(env); - ientry = &env->itlb[n]; - if (ientry->v) { - tlb_flush_page(env, ientry->vpn << 10); - } - *ientry = env->utlb[e]; - e = n; - } else if (e == MMU_DTLB_MISS) - e = MMU_ITLB_MISS; - } else if (e == MMU_DTLB_MISS) + } else if (e == MMU_DTLB_MISS) { e = MMU_ITLB_MISS; - if (e >= 0) + } else if (e >= 0) { update_itlb_use(env, e); + } return e; } @@ -340,13 +345,31 @@ static int get_mmu_address(CPUState * env, target_ulong * physical, use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0; if (rw == 2) { - n = find_itlb_entry(env, address, use_asid, 1); + n = find_itlb_entry(env, address, use_asid); if (n >= 0) { matching = &env->itlb[n]; if (!(env->sr & SR_MD) && !(matching->pr & 2)) n = MMU_ITLB_VIOLATION; else *prot = PAGE_EXEC; + } else { + n = find_utlb_entry(env, address, use_asid); + if (n >= 0) { + n = copy_utlb_entry_itlb(env, n); + matching = &env->itlb[n]; + if (!(env->sr & SR_MD) && !(matching->pr & 2)) { + n = MMU_ITLB_VIOLATION; + } else { + *prot = PAGE_READ | PAGE_EXEC; + if ((matching->pr & 1) && matching->d) { + *prot |= PAGE_WRITE; + } + } + } else if (n == MMU_DTLB_MULTIPLE) { + n = MMU_ITLB_MULTIPLE; + } else if (n == MMU_DTLB_MISS) { + n = MMU_ITLB_MISS; + } } } else { n = find_utlb_entry(env, address, use_asid); -- cgit v1.2.3 From a3e28aa5c748958e5719451aaff88a4d78e09a80 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 10 Jan 2011 01:39:49 +0100 Subject: tcg/ia64: remove an unnecessary stop bit Spotted by Richard Henderson. Signed-off-by: Aurelien Jarno --- tcg/ia64/tcg-target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 3ddf434571..e2e44f7d76 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -1329,7 +1329,7 @@ static inline void tcg_out_bswap32(TCGContext *s, TCGArg ret, TCGArg arg) static inline void tcg_out_bswap64(TCGContext *s, TCGArg ret, TCGArg arg) { - tcg_out_bundle(s, mII, + tcg_out_bundle(s, miI, tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, arg, 0xb)); -- cgit v1.2.3 From 0f11f25a001f6adca18689192182d415ff3dbb7c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 22:43:13 +0100 Subject: tcg/arm: improve constant loading Improve constant loading in two ways: - On all ARM versions, it's possible to load 0xffffff00 = -0x100 using the mvn rd, #0. Fix the conditions. - On <= ARMv6 versions, where movw and movt are not available, load the constants using mov and orr with rotations depending on the constant to load. This is very useful for example to load constants where the low byte is 0. This reduce the generated code size by about 7%. Also fix the coding style at the same time. Cc: Andrzej Zaborowski Signed-off-by: Aurelien Jarno --- tcg/arm/tcg-target.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 08c44c1123..1eb5605f8c 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -406,35 +406,38 @@ static inline void tcg_out_dat_imm(TCGContext *s, } static inline void tcg_out_movi32(TCGContext *s, - int cond, int rd, int32_t arg) + int cond, int rd, uint32_t arg) { /* TODO: This is very suboptimal, we can easily have a constant * pool somewhere after all the instructions. */ - - if (arg < 0 && arg > -0x100) - return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff); - - if (use_armv7_instructions) { + if ((int)arg < 0 && (int)arg >= -0x100) { + tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff); + } else if (use_armv7_instructions) { /* use movw/movt */ /* movw */ tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12) | ((arg << 4) & 0x000f0000) | (arg & 0xfff)); - if (arg & 0xffff0000) + if (arg & 0xffff0000) { /* movt */ tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12) | ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff)); - } else { - tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff); - if (arg & 0x0000ff00) - tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, - ((arg >> 8) & 0xff) | 0xc00); - if (arg & 0x00ff0000) - tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, - ((arg >> 16) & 0xff) | 0x800); - if (arg & 0xff000000) - tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, - ((arg >> 24) & 0xff) | 0x400); } + } else { + int opc = ARITH_MOV; + int rn = 0; + + do { + int i, rot; + + i = ctz32(arg) & ~1; + rot = ((32 - i) << 7) & 0xf00; + tcg_out_dat_imm(s, cond, opc, rd, rn, ((arg >> i) & 0xff) | rot); + arg &= ~(0xff << i); + + opc = ARITH_ORR; + rn = rd; + } while (arg); + } } static inline void tcg_out_mul32(TCGContext *s, -- cgit v1.2.3 From 102c29769fa7cd564053ea41735395f428b6f197 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 22:43:13 +0100 Subject: bswap.h: add cpu_to_be64wu() Signed-off-by: Aurelien Jarno --- bswap.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bswap.h b/bswap.h index 20caae63ea..82a79517db 100644 --- a/bswap.h +++ b/bswap.h @@ -144,6 +144,7 @@ CPU_CONVERT(le, 64, uint64_t) #define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) #define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) +#define cpu_to_be64wu(p, v) cpu_to_be64w(p, v) #else @@ -201,6 +202,20 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) p1[3] = v & 0xff; } +static inline void cpu_to_be64wu(uint64_t *p, uint64_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 56; + p1[1] = v >> 48; + p1[2] = v >> 40; + p1[3] = v >> 32; + p1[4] = v >> 24; + p1[5] = v >> 16; + p1[6] = v >> 8; + p1[7] = v & 0xff; +} + #endif #ifdef HOST_WORDS_BIGENDIAN -- cgit v1.2.3 From 8aaf42ed0f203da63860b0a3ab3ff2bdfe9b4cb0 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 6 Jan 2011 22:43:13 +0100 Subject: slirp: fix unaligned access in bootp code Slirp code tries to be smart an avoid data copy by using pointer to the data. This solution leads to unaligned access, in this case preq_addr, which is a 32-bit long structure. There is no real point of avoiding data copy in a such case, as the value itself is smaller or the same size as a pointer. The patch replaces pointers to the preq_addr structure by the strcture itself, and use the address 0.0.0.0 if no address has been requested (this is not a valid address in such a request). It compares it with htonl(0L) for correctness reasons, in case a code checker look for such mistakes. It also uses memcpy() for copying the data, which takes care of alignement issues. This fixes an unaligned access on IA64 host while requesting a DHCP address. Signed-off-by: Aurelien Jarno --- slirp/bootp.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/slirp/bootp.c b/slirp/bootp.c index 41460ffaa5..0905c6d1be 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -92,13 +92,13 @@ static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr, } static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, - const struct in_addr **preq_addr) + struct in_addr *preq_addr) { const uint8_t *p, *p_end; int len, tag; *pmsg_type = 0; - *preq_addr = NULL; + preq_addr->s_addr = htonl(0L); p = bp->bp_vend; p_end = p + DHCP_OPT_LEN; @@ -124,8 +124,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, *pmsg_type = p[0]; break; case RFC2132_REQ_ADDR: - if (len >= 4) - *preq_addr = (struct in_addr *)p; + if (len >= 4) { + memcpy(&(preq_addr->s_addr), p, 4); + } break; default: break; @@ -133,8 +134,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, p += len; } } - if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr.s_addr) { - *preq_addr = &bp->bp_ciaddr; + if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) && + bp->bp_ciaddr.s_addr) { + memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4); } } @@ -144,15 +146,15 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) struct mbuf *m; struct bootp_t *rbp; struct sockaddr_in saddr, daddr; - const struct in_addr *preq_addr; + struct in_addr preq_addr; int dhcp_msg_type, val; uint8_t *q; /* extract exact DHCP msg type */ dhcp_decode(bp, &dhcp_msg_type, &preq_addr); DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type); - if (preq_addr) - DPRINTF(" req_addr=%08x\n", ntohl(preq_addr->s_addr)); + if (preq_addr.s_addr != htonl(0L)) + DPRINTF(" req_addr=%08x\n", ntohl(preq_addr.s_addr)); else DPRINTF("\n"); @@ -175,10 +177,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) memset(rbp, 0, sizeof(struct bootp_t)); if (dhcp_msg_type == DHCPDISCOVER) { - if (preq_addr) { - bc = request_addr(slirp, preq_addr, slirp->client_ethaddr); + if (preq_addr.s_addr != htonl(0L)) { + bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr); if (bc) { - daddr.sin_addr = *preq_addr; + daddr.sin_addr = preq_addr; } } if (!bc) { @@ -190,10 +192,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) } } memcpy(bc->macaddr, slirp->client_ethaddr, 6); - } else if (preq_addr) { - bc = request_addr(slirp, preq_addr, slirp->client_ethaddr); + } else if (preq_addr.s_addr != htonl(0L)) { + bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr); if (bc) { - daddr.sin_addr = *preq_addr; + daddr.sin_addr = preq_addr; memcpy(bc->macaddr, slirp->client_ethaddr, 6); } else { daddr.sin_addr.s_addr = 0; -- cgit v1.2.3