diff options
Diffstat (limited to 'qemu/hw/display')
36 files changed, 1447 insertions, 171 deletions
diff --git a/qemu/hw/display/Makefile.objs b/qemu/hw/display/Makefile.objs index dd8ea76d1..d99780eeb 100644 --- a/qemu/hw/display/Makefile.objs +++ b/qemu/hw/display/Makefile.objs @@ -27,6 +27,7 @@ endif obj-$(CONFIG_OMAP) += omap_dss.o obj-$(CONFIG_OMAP) += omap_lcdc.o obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o +obj-$(CONFIG_RASPI) += bcm2835_fb.o obj-$(CONFIG_SM501) += sm501.o obj-$(CONFIG_TCX) += tcx.o obj-$(CONFIG_CG3) += cg3.o @@ -35,6 +36,10 @@ obj-$(CONFIG_VGA) += vga.o common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o -obj-$(CONFIG_VIRTIO) += virtio-gpu.o +obj-$(CONFIG_VIRTIO) += virtio-gpu.o virtio-gpu-3d.o obj-$(CONFIG_VIRTIO_PCI) += virtio-gpu-pci.o obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o +virtio-gpu.o-cflags := $(VIRGL_CFLAGS) +virtio-gpu.o-libs += $(VIRGL_LIBS) +virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS) +virtio-gpu-3d.o-libs += $(VIRGL_LIBS) diff --git a/qemu/hw/display/ads7846.c b/qemu/hw/display/ads7846.c index 3f35369bb..05aa2d1e6 100644 --- a/qemu/hw/display/ads7846.c +++ b/qemu/hw/display/ads7846.c @@ -10,7 +10,8 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw/ssi.h" +#include "qemu/osdep.h" +#include "hw/ssi/ssi.h" #include "ui/console.h" typedef struct { diff --git a/qemu/hw/display/bcm2835_fb.c b/qemu/hw/display/bcm2835_fb.c new file mode 100644 index 000000000..506f1d3d9 --- /dev/null +++ b/qemu/hw/display/bcm2835_fb.c @@ -0,0 +1,425 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann. + * This code is licensed under the GNU GPLv2 and later. + * + * Heavily based on milkymist-vgafb.c, copyright terms below: + * QEMU model of the Milkymist VGA framebuffer. + * + * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/display/bcm2835_fb.h" +#include "hw/display/framebuffer.h" +#include "ui/pixel_ops.h" +#include "hw/misc/bcm2835_mbox_defs.h" + +#define DEFAULT_VCRAM_SIZE 0x4000000 +#define BCM2835_FB_OFFSET 0x00100000 + +static void fb_invalidate_display(void *opaque) +{ + BCM2835FBState *s = BCM2835_FB(opaque); + + s->invalidate = true; +} + +static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src, + int width, int deststep) +{ + BCM2835FBState *s = opaque; + uint16_t rgb565; + uint32_t rgb888; + uint8_t r, g, b; + DisplaySurface *surface = qemu_console_surface(s->con); + int bpp = surface_bits_per_pixel(surface); + + while (width--) { + switch (s->bpp) { + case 8: + /* lookup palette starting at video ram base + * TODO: cache translation, rather than doing this each time! + */ + rgb888 = ldl_le_phys(&s->dma_as, s->vcram_base + (*src << 2)); + r = (rgb888 >> 0) & 0xff; + g = (rgb888 >> 8) & 0xff; + b = (rgb888 >> 16) & 0xff; + src++; + break; + case 16: + rgb565 = lduw_le_p(src); + r = ((rgb565 >> 11) & 0x1f) << 3; + g = ((rgb565 >> 5) & 0x3f) << 2; + b = ((rgb565 >> 0) & 0x1f) << 3; + src += 2; + break; + case 24: + rgb888 = ldl_le_p(src); + r = (rgb888 >> 0) & 0xff; + g = (rgb888 >> 8) & 0xff; + b = (rgb888 >> 16) & 0xff; + src += 3; + break; + case 32: + rgb888 = ldl_le_p(src); + r = (rgb888 >> 0) & 0xff; + g = (rgb888 >> 8) & 0xff; + b = (rgb888 >> 16) & 0xff; + src += 4; + break; + default: + r = 0; + g = 0; + b = 0; + break; + } + + if (s->pixo == 0) { + /* swap to BGR pixel format */ + uint8_t tmp = r; + r = b; + b = tmp; + } + + switch (bpp) { + case 8: + *dst++ = rgb_to_pixel8(r, g, b); + break; + case 15: + *(uint16_t *)dst = rgb_to_pixel15(r, g, b); + dst += 2; + break; + case 16: + *(uint16_t *)dst = rgb_to_pixel16(r, g, b); + dst += 2; + break; + case 24: + rgb888 = rgb_to_pixel24(r, g, b); + *dst++ = rgb888 & 0xff; + *dst++ = (rgb888 >> 8) & 0xff; + *dst++ = (rgb888 >> 16) & 0xff; + break; + case 32: + *(uint32_t *)dst = rgb_to_pixel32(r, g, b); + dst += 4; + break; + default: + return; + } + } +} + +static void fb_update_display(void *opaque) +{ + BCM2835FBState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); + int first = 0; + int last = 0; + int src_width = 0; + int dest_width = 0; + + if (s->lock || !s->xres) { + return; + } + + src_width = s->xres * (s->bpp >> 3); + dest_width = s->xres; + + switch (surface_bits_per_pixel(surface)) { + case 0: + return; + case 8: + break; + case 15: + dest_width *= 2; + break; + case 16: + dest_width *= 2; + break; + case 24: + dest_width *= 3; + break; + case 32: + dest_width *= 4; + break; + default: + hw_error("bcm2835_fb: bad color depth\n"); + break; + } + + if (s->invalidate) { + framebuffer_update_memory_section(&s->fbsection, s->dma_mr, s->base, + s->yres, src_width); + } + + framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres, + src_width, dest_width, 0, s->invalidate, + draw_line_src16, s, &first, &last); + + if (first >= 0) { + dpy_gfx_update(s->con, 0, first, s->xres, last - first + 1); + } + + s->invalidate = false; +} + +static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value) +{ + value &= ~0xf; + + s->lock = true; + + s->xres = ldl_le_phys(&s->dma_as, value); + s->yres = ldl_le_phys(&s->dma_as, value + 4); + s->xres_virtual = ldl_le_phys(&s->dma_as, value + 8); + s->yres_virtual = ldl_le_phys(&s->dma_as, value + 12); + s->bpp = ldl_le_phys(&s->dma_as, value + 20); + s->xoffset = ldl_le_phys(&s->dma_as, value + 24); + s->yoffset = ldl_le_phys(&s->dma_as, value + 28); + + s->base = s->vcram_base | (value & 0xc0000000); + s->base += BCM2835_FB_OFFSET; + + /* TODO - Manage properly virtual resolution */ + + s->pitch = s->xres * (s->bpp >> 3); + s->size = s->yres * s->pitch; + + stl_le_phys(&s->dma_as, value + 16, s->pitch); + stl_le_phys(&s->dma_as, value + 32, s->base); + stl_le_phys(&s->dma_as, value + 36, s->size); + + s->invalidate = true; + qemu_console_resize(s->con, s->xres, s->yres); + s->lock = false; +} + +void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres, + uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp, + uint32_t *pixo, uint32_t *alpha) +{ + s->lock = true; + + /* TODO: input validation! */ + if (xres) { + s->xres = *xres; + } + if (yres) { + s->yres = *yres; + } + if (xoffset) { + s->xoffset = *xoffset; + } + if (yoffset) { + s->yoffset = *yoffset; + } + if (bpp) { + s->bpp = *bpp; + } + if (pixo) { + s->pixo = *pixo; + } + if (alpha) { + s->alpha = *alpha; + } + + /* TODO - Manage properly virtual resolution */ + + s->pitch = s->xres * (s->bpp >> 3); + s->size = s->yres * s->pitch; + + s->invalidate = true; + qemu_console_resize(s->con, s->xres, s->yres); + s->lock = false; +} + +static uint64_t bcm2835_fb_read(void *opaque, hwaddr offset, unsigned size) +{ + BCM2835FBState *s = opaque; + uint32_t res = 0; + + switch (offset) { + case MBOX_AS_DATA: + res = MBOX_CHAN_FB; + s->pending = false; + qemu_set_irq(s->mbox_irq, 0); + break; + + case MBOX_AS_PENDING: + res = s->pending; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); + return 0; + } + + return res; +} + +static void bcm2835_fb_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + BCM2835FBState *s = opaque; + + switch (offset) { + case MBOX_AS_DATA: + /* bcm2835_mbox should check our pending status before pushing */ + assert(!s->pending); + s->pending = true; + bcm2835_fb_mbox_push(s, value); + qemu_set_irq(s->mbox_irq, 1); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); + return; + } +} + +static const MemoryRegionOps bcm2835_fb_ops = { + .read = bcm2835_fb_read, + .write = bcm2835_fb_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, +}; + +static const VMStateDescription vmstate_bcm2835_fb = { + .name = TYPE_BCM2835_FB, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(lock, BCM2835FBState), + VMSTATE_BOOL(invalidate, BCM2835FBState), + VMSTATE_BOOL(pending, BCM2835FBState), + VMSTATE_UINT32(xres, BCM2835FBState), + VMSTATE_UINT32(yres, BCM2835FBState), + VMSTATE_UINT32(xres_virtual, BCM2835FBState), + VMSTATE_UINT32(yres_virtual, BCM2835FBState), + VMSTATE_UINT32(xoffset, BCM2835FBState), + VMSTATE_UINT32(yoffset, BCM2835FBState), + VMSTATE_UINT32(bpp, BCM2835FBState), + VMSTATE_UINT32(base, BCM2835FBState), + VMSTATE_UINT32(pitch, BCM2835FBState), + VMSTATE_UINT32(size, BCM2835FBState), + VMSTATE_UINT32(pixo, BCM2835FBState), + VMSTATE_UINT32(alpha, BCM2835FBState), + VMSTATE_END_OF_LIST() + } +}; + +static const GraphicHwOps vgafb_ops = { + .invalidate = fb_invalidate_display, + .gfx_update = fb_update_display, +}; + +static void bcm2835_fb_init(Object *obj) +{ + BCM2835FBState *s = BCM2835_FB(obj); + + memory_region_init_io(&s->iomem, obj, &bcm2835_fb_ops, s, TYPE_BCM2835_FB, + 0x10); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq); +} + +static void bcm2835_fb_reset(DeviceState *dev) +{ + BCM2835FBState *s = BCM2835_FB(dev); + + s->pending = false; + + s->xres_virtual = s->xres; + s->yres_virtual = s->yres; + s->xoffset = 0; + s->yoffset = 0; + s->base = s->vcram_base + BCM2835_FB_OFFSET; + s->pitch = s->xres * (s->bpp >> 3); + s->size = s->yres * s->pitch; + + s->invalidate = true; + s->lock = false; +} + +static void bcm2835_fb_realize(DeviceState *dev, Error **errp) +{ + BCM2835FBState *s = BCM2835_FB(dev); + Error *err = NULL; + Object *obj; + + if (s->vcram_base == 0) { + error_setg(errp, "%s: required vcram-base property not set", __func__); + return; + } + + obj = object_property_get_link(OBJECT(dev), "dma-mr", &err); + if (obj == NULL) { + error_setg(errp, "%s: required dma-mr link not found: %s", + __func__, error_get_pretty(err)); + return; + } + + s->dma_mr = MEMORY_REGION(obj); + address_space_init(&s->dma_as, s->dma_mr, NULL); + + bcm2835_fb_reset(dev); + + s->con = graphic_console_init(dev, 0, &vgafb_ops, s); + qemu_console_resize(s->con, s->xres, s->yres); +} + +static Property bcm2835_fb_props[] = { + DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/ + DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size, + DEFAULT_VCRAM_SIZE), + DEFINE_PROP_UINT32("xres", BCM2835FBState, xres, 640), + DEFINE_PROP_UINT32("yres", BCM2835FBState, yres, 480), + DEFINE_PROP_UINT32("bpp", BCM2835FBState, bpp, 16), + DEFINE_PROP_UINT32("pixo", BCM2835FBState, pixo, 1), /* 1=RGB, 0=BGR */ + DEFINE_PROP_UINT32("alpha", BCM2835FBState, alpha, 2), /* alpha ignored */ + DEFINE_PROP_END_OF_LIST() +}; + +static void bcm2835_fb_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = bcm2835_fb_props; + dc->realize = bcm2835_fb_realize; + dc->reset = bcm2835_fb_reset; + dc->vmsd = &vmstate_bcm2835_fb; +} + +static TypeInfo bcm2835_fb_info = { + .name = TYPE_BCM2835_FB, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BCM2835FBState), + .class_init = bcm2835_fb_class_init, + .instance_init = bcm2835_fb_init, +}; + +static void bcm2835_fb_register_types(void) +{ + type_register_static(&bcm2835_fb_info); +} + +type_init(bcm2835_fb_register_types) diff --git a/qemu/hw/display/blizzard.c b/qemu/hw/display/blizzard.c index 5019bbbef..c231960d9 100644 --- a/qemu/hw/display/blizzard.c +++ b/qemu/hw/display/blizzard.c @@ -18,6 +18,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "qemu-common.h" #include "ui/console.h" #include "hw/devices.h" diff --git a/qemu/hw/display/cg3.c b/qemu/hw/display/cg3.c index 34dcbc311..fc0d97fa4 100644 --- a/qemu/hw/display/cg3.c +++ b/qemu/hw/display/cg3.c @@ -23,6 +23,8 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu-common.h" #include "qemu/error-report.h" #include "ui/console.h" @@ -280,12 +282,12 @@ static void cg3_initfn(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); CG3State *s = CG3(obj); - memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE, - &error_abort); + memory_region_init_ram(&s->rom, obj, "cg3.prom", FCODE_MAX_ROM_SIZE, + &error_fatal); memory_region_set_readonly(&s->rom, true); sysbus_init_mmio(sbd, &s->rom); - memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg", + memory_region_init_io(&s->reg, obj, &cg3_reg_ops, s, "cg3.reg", CG3_REG_SIZE); sysbus_init_mmio(sbd, &s->reg); } @@ -310,7 +312,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) } memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size, - &error_abort); + &error_fatal); memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA); vmstate_register_ram_global(&s->vram_mem); sysbus_init_mmio(sbd, &s->vram_mem); diff --git a/qemu/hw/display/cirrus_vga.c b/qemu/hw/display/cirrus_vga.c index 5198037d8..3d712d592 100644 --- a/qemu/hw/display/cirrus_vga.c +++ b/qemu/hw/display/cirrus_vga.c @@ -26,6 +26,8 @@ * Reference: Finn Thogersons' VGADOC4b * available at http://home.worldonline.dk/~finth/ */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "ui/console.h" @@ -275,14 +277,14 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s, + ((int64_t)s->cirrus_blt_height-1) * pitch; int32_t max = addr + s->cirrus_blt_width; - if (min < 0 || max >= s->vga.vram_size) { + if (min < 0 || max > s->vga.vram_size) { return true; } } else { int64_t max = addr + ((int64_t)s->cirrus_blt_height-1) * pitch + s->cirrus_blt_width; - if (max >= s->vga.vram_size) { + if (max > s->vga.vram_size) { return true; } } diff --git a/qemu/hw/display/exynos4210_fimd.c b/qemu/hw/display/exynos4210_fimd.c index 603ef5056..728eb214a 100644 --- a/qemu/hw/display/exynos4210_fimd.c +++ b/qemu/hw/display/exynos4210_fimd.c @@ -22,6 +22,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "qemu-common.h" #include "hw/sysbus.h" #include "ui/console.h" @@ -1354,9 +1355,7 @@ static void exynos4210_fimd_reset(DeviceState *d) fimd_update_get_alpha(s, w); } - if (s->ifb != NULL) { - g_free(s->ifb); - } + g_free(s->ifb); s->ifb = NULL; exynos4210_fimd_invalidate(s); diff --git a/qemu/hw/display/framebuffer.c b/qemu/hw/display/framebuffer.c index 7f075ce77..df51358e7 100644 --- a/qemu/hw/display/framebuffer.c +++ b/qemu/hw/display/framebuffer.c @@ -17,6 +17,7 @@ - Remove all DisplayState knowledge from devices. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" #include "framebuffer.h" diff --git a/qemu/hw/display/g364fb.c b/qemu/hw/display/g364fb.c index 7f83a007b..70ef2c745 100644 --- a/qemu/hw/display/g364fb.c +++ b/qemu/hw/display/g364fb.c @@ -17,6 +17,7 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "qemu/error-report.h" #include "ui/console.h" diff --git a/qemu/hw/display/jazz_led.c b/qemu/hw/display/jazz_led.c index 12b1707cb..09dcdb46a 100644 --- a/qemu/hw/display/jazz_led.c +++ b/qemu/hw/display/jazz_led.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" #include "qemu-common.h" #include "ui/console.h" #include "ui/pixel_ops.h" @@ -233,8 +234,10 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata) /* TODO: draw the segments */ snprintf(buf, 2, "%02hhx\n", s->segments); - console_write_ch(chardata++, 0x00200100 | buf[0]); - console_write_ch(chardata++, 0x00200100 | buf[1]); + console_write_ch(chardata++, ATTR2CHTYPE(buf[0], QEMU_COLOR_BLUE, + QEMU_COLOR_BLACK, 1)); + console_write_ch(chardata++, ATTR2CHTYPE(buf[1], QEMU_COLOR_BLUE, + QEMU_COLOR_BLACK, 1)); dpy_text_update(s->con, 0, 0, 2, 1); } diff --git a/qemu/hw/display/milkymist-tmu2.c b/qemu/hw/display/milkymist-tmu2.c index 3e1d0b9c2..9bc88f93b 100644 --- a/qemu/hw/display/milkymist-tmu2.c +++ b/qemu/hw/display/milkymist-tmu2.c @@ -24,14 +24,15 @@ * */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" #include <X11/Xlib.h> -#include <GL/gl.h> -#include <GL/glx.h> +#include <epoxy/gl.h> +#include <epoxy/glx.h> enum { R_CTL = 0, diff --git a/qemu/hw/display/milkymist-vgafb.c b/qemu/hw/display/milkymist-vgafb.c index ab3074fad..19ca25647 100644 --- a/qemu/hw/display/milkymist-vgafb.c +++ b/qemu/hw/display/milkymist-vgafb.c @@ -22,6 +22,7 @@ * http://www.milkymist.org/socdoc/vgafb.pdf */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/sysbus.h" #include "trace.h" diff --git a/qemu/hw/display/omap_dss.c b/qemu/hw/display/omap_dss.c index f1fef2767..783e9e131 100644 --- a/qemu/hw/display/omap_dss.c +++ b/qemu/hw/display/omap_dss.c @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" #include "hw/arm/omap.h" @@ -1051,8 +1052,7 @@ struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta, omap_clk fck1, omap_clk fck2, omap_clk ck54m, omap_clk ick1, omap_clk ick2) { - struct omap_dss_s *s = (struct omap_dss_s *) - g_malloc0(sizeof(struct omap_dss_s)); + struct omap_dss_s *s = g_new0(struct omap_dss_s, 1); s->irq = irq; s->drq = drq; diff --git a/qemu/hw/display/omap_lcd_template.h b/qemu/hw/display/omap_lcd_template.h index e5dd44716..f0ce71fd6 100644 --- a/qemu/hw/display/omap_lcd_template.h +++ b/qemu/hw/display/omap_lcd_template.h @@ -136,7 +136,7 @@ static void glue(draw_line12_, DEPTH)(void *opaque, uint8_t r, g, b; do { - v = lduw_p((void *) s); + v = lduw_le_p((void *) s); r = (v >> 4) & 0xf0; g = v & 0xf0; b = (v << 4) & 0xf0; @@ -159,7 +159,7 @@ static void glue(draw_line16_, DEPTH)(void *opaque, uint8_t r, g, b; do { - v = lduw_p((void *) s); + v = lduw_le_p((void *) s); r = (v >> 8) & 0xf8; g = (v >> 3) & 0xfc; b = (v << 3) & 0xf8; diff --git a/qemu/hw/display/omap_lcdc.c b/qemu/hw/display/omap_lcdc.c index a7c6cd79b..ce1058bf8 100644 --- a/qemu/hw/display/omap_lcdc.c +++ b/qemu/hw/display/omap_lcdc.c @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" #include "hw/arm/omap.h" @@ -403,8 +404,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, struct omap_dma_lcd_channel_s *dma, omap_clk clk) { - struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) - g_malloc0(sizeof(struct omap_lcd_panel_s)); + struct omap_lcd_panel_s *s = g_new0(struct omap_lcd_panel_s, 1); s->irq = irq; s->dma = dma; diff --git a/qemu/hw/display/pl110.c b/qemu/hw/display/pl110.c index ef1a7b1a5..d589959f1 100644 --- a/qemu/hw/display/pl110.c +++ b/qemu/hw/display/pl110.c @@ -7,6 +7,7 @@ * This code is licensed under the GNU LGPL */ +#include "qemu/osdep.h" #include "hw/sysbus.h" #include "ui/console.h" #include "framebuffer.h" diff --git a/qemu/hw/display/pxa2xx_lcd.c b/qemu/hw/display/pxa2xx_lcd.c index 494700d07..845521c5b 100644 --- a/qemu/hw/display/pxa2xx_lcd.c +++ b/qemu/hw/display/pxa2xx_lcd.c @@ -10,6 +10,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" #include "hw/arm/pxa.h" @@ -309,10 +310,10 @@ static void pxa2xx_descriptor_load(PXA2xxLCDState *s) } cpu_physical_memory_read(descptr, &desc, sizeof(desc)); - s->dma_ch[i].descriptor = tswap32(desc.fdaddr); - s->dma_ch[i].source = tswap32(desc.fsaddr); - s->dma_ch[i].id = tswap32(desc.fidr); - s->dma_ch[i].command = tswap32(desc.ldcmd); + s->dma_ch[i].descriptor = le32_to_cpu(desc.fdaddr); + s->dma_ch[i].source = le32_to_cpu(desc.fsaddr); + s->dma_ch[i].id = le32_to_cpu(desc.fidr); + s->dma_ch[i].command = le32_to_cpu(desc.ldcmd); } } diff --git a/qemu/hw/display/qxl-logger.c b/qemu/hw/display/qxl-logger.c index d944d3fdb..2ec6d8fa3 100644 --- a/qemu/hw/display/qxl-logger.c +++ b/qemu/hw/display/qxl-logger.c @@ -19,6 +19,7 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "qemu/timer.h" #include "qxl.h" diff --git a/qemu/hw/display/qxl-render.c b/qemu/hw/display/qxl-render.c index a542087fc..9ad9d9e0f 100644 --- a/qemu/hw/display/qxl-render.c +++ b/qemu/hw/display/qxl-render.c @@ -19,6 +19,7 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "qxl.h" #include "trace.h" @@ -159,7 +160,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) /* * use ssd.lock to protect render_update_cookie_num. * qxl_render_update is called by io thread or vcpu thread, and the completion - * callbacks are called by spice_server thread, defering to bh called from the + * callbacks are called by spice_server thread, deferring to bh called from the * io thread. */ void qxl_render_update(PCIQXLDevice *qxl) diff --git a/qemu/hw/display/qxl.c b/qemu/hw/display/qxl.c index 2288238d0..919dc5cd3 100644 --- a/qemu/hw/display/qxl.c +++ b/qemu/hw/display/qxl.c @@ -18,8 +18,8 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include <zlib.h> -#include <stdint.h> #include "qemu-common.h" #include "qemu/timer.h" @@ -1156,7 +1156,9 @@ static void qxl_soft_reset(PCIQXLDevice *d) trace_qxl_soft_reset(d->id); qxl_check_state(d); qxl_clear_guest_bug(d); + qemu_mutex_lock(&d->async_lock); d->current_async = QXL_UNDEFINED_IO; + qemu_mutex_unlock(&d->async_lock); if (d->id == 0) { qxl_enter_vga_mode(d); @@ -1970,14 +1972,14 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp) qxl->rom_size = qxl_rom_size(); memory_region_init_ram(&qxl->rom_bar, OBJECT(qxl), "qxl.vrom", - qxl->rom_size, &error_abort); + qxl->rom_size, &error_fatal); vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev); init_qxl_rom(qxl); init_qxl_ram(qxl); qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces); memory_region_init_ram(&qxl->vram_bar, OBJECT(qxl), "qxl.vram", - qxl->vram_size, &error_abort); + qxl->vram_size, &error_fatal); vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev); memory_region_init_alias(&qxl->vram32_bar, OBJECT(qxl), "qxl.vram32", &qxl->vram_bar, 0, qxl->vram32_size); @@ -2079,7 +2081,7 @@ static void qxl_realize_secondary(PCIDevice *dev, Error **errp) qxl->id = device_id++; qxl_init_ramsize(qxl); memory_region_init_ram(&qxl->vga.vram, OBJECT(dev), "qxl.vgavram", - qxl->vga.vram_size, &error_abort); + qxl->vga.vram_size, &error_fatal); vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev); qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl); @@ -2156,7 +2158,7 @@ static int qxl_post_load(void *opaque, int version) qxl_create_guest_primary(d, 1, QXL_SYNC); /* replay surface-create and cursor-set commands */ - cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1)); + cmds = g_new0(QXLCommandExt, d->ssd.num_surfaces + 1); for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) { if (d->guest_surfaces.cmds[in] == 0) { continue; diff --git a/qemu/hw/display/sm501.c b/qemu/hw/display/sm501.c index 15a5ba800..5f7101210 100644 --- a/qemu/hw/display/sm501.c +++ b/qemu/hw/display/sm501.c @@ -22,7 +22,10 @@ * THE SOFTWARE. */ -#include <stdio.h> +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" #include "hw/hw.h" #include "hw/char/serial.h" #include "ui/console.h" @@ -1411,7 +1414,7 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, /* allocate local memory */ memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local", - local_mem_bytes, &error_abort); + local_mem_bytes, &error_fatal); vmstate_register_ram_global(&s->local_mem_region); memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA); s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region); diff --git a/qemu/hw/display/ssd0303.c b/qemu/hw/display/ssd0303.c index f6804fb51..d3017563f 100644 --- a/qemu/hw/display/ssd0303.c +++ b/qemu/hw/display/ssd0303.c @@ -10,6 +10,7 @@ /* The controller can support a variety of different displays, but we only implement one. Most of the commends relating to brightness and geometry setup are ignored. */ +#include "qemu/osdep.h" #include "hw/i2c/i2c.h" #include "ui/console.h" diff --git a/qemu/hw/display/ssd0323.c b/qemu/hw/display/ssd0323.c index 97270077e..14c1bf339 100644 --- a/qemu/hw/display/ssd0323.c +++ b/qemu/hw/display/ssd0323.c @@ -10,7 +10,8 @@ /* The controller can support a variety of different displays, but we only implement one. Most of the commends relating to brightness and geometry setup are ignored. */ -#include "hw/ssi.h" +#include "qemu/osdep.h" +#include "hw/ssi/ssi.h" #include "ui/console.h" //#define DEBUG_SSD0323 1 diff --git a/qemu/hw/display/tc6393xb.c b/qemu/hw/display/tc6393xb.c index f5f3f3e69..da3ceceb0 100644 --- a/qemu/hw/display/tc6393xb.c +++ b/qemu/hw/display/tc6393xb.c @@ -10,6 +10,8 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/devices.h" #include "hw/block/flash.h" @@ -584,7 +586,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq) memory_region_add_subregion(sysmem, base, &s->iomem); memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->vram); s->vram_ptr = memory_region_get_ram_ptr(&s->vram); memory_region_add_subregion(sysmem, base + 0x100000, &s->vram); diff --git a/qemu/hw/display/tcx.c b/qemu/hw/display/tcx.c index 6acdc2d28..8e26aae80 100644 --- a/qemu/hw/display/tcx.c +++ b/qemu/hw/display/tcx.c @@ -22,7 +22,10 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "qemu-common.h" +#include "cpu.h" /* FIXME shouldn't use TARGET_PAGE_SIZE */ #include "ui/console.h" #include "ui/pixel_ops.h" #include "hw/loader.h" @@ -944,57 +947,55 @@ static void tcx_initfn(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); TCXState *s = TCX(obj); - memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE, - &error_abort); + memory_region_init_ram(&s->rom, obj, "tcx.prom", FCODE_MAX_ROM_SIZE, + &error_fatal); memory_region_set_readonly(&s->rom, true); sysbus_init_mmio(sbd, &s->rom); /* 2/STIP : Stippler */ - memory_region_init_io(&s->stip, OBJECT(s), &tcx_stip_ops, s, "tcx.stip", + memory_region_init_io(&s->stip, obj, &tcx_stip_ops, s, "tcx.stip", TCX_STIP_NREGS); sysbus_init_mmio(sbd, &s->stip); /* 3/BLIT : Blitter */ - memory_region_init_io(&s->blit, OBJECT(s), &tcx_blit_ops, s, "tcx.blit", + memory_region_init_io(&s->blit, obj, &tcx_blit_ops, s, "tcx.blit", TCX_BLIT_NREGS); sysbus_init_mmio(sbd, &s->blit); /* 5/RSTIP : Raw Stippler */ - memory_region_init_io(&s->rstip, OBJECT(s), &tcx_rstip_ops, s, "tcx.rstip", + memory_region_init_io(&s->rstip, obj, &tcx_rstip_ops, s, "tcx.rstip", TCX_RSTIP_NREGS); sysbus_init_mmio(sbd, &s->rstip); /* 6/RBLIT : Raw Blitter */ - memory_region_init_io(&s->rblit, OBJECT(s), &tcx_rblit_ops, s, "tcx.rblit", + memory_region_init_io(&s->rblit, obj, &tcx_rblit_ops, s, "tcx.rblit", TCX_RBLIT_NREGS); sysbus_init_mmio(sbd, &s->rblit); /* 7/TEC : ??? */ - memory_region_init_io(&s->tec, OBJECT(s), &tcx_dummy_ops, s, - "tcx.tec", TCX_TEC_NREGS); + memory_region_init_io(&s->tec, obj, &tcx_dummy_ops, s, "tcx.tec", + TCX_TEC_NREGS); sysbus_init_mmio(sbd, &s->tec); /* 8/CMAP : DAC */ - memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, - "tcx.dac", TCX_DAC_NREGS); + memory_region_init_io(&s->dac, obj, &tcx_dac_ops, s, "tcx.dac", + TCX_DAC_NREGS); sysbus_init_mmio(sbd, &s->dac); /* 9/THC : Cursor */ - memory_region_init_io(&s->thc, OBJECT(s), &tcx_thc_ops, s, "tcx.thc", + memory_region_init_io(&s->thc, obj, &tcx_thc_ops, s, "tcx.thc", TCX_THC_NREGS); sysbus_init_mmio(sbd, &s->thc); /* 11/DHC : ??? */ - memory_region_init_io(&s->dhc, OBJECT(s), &tcx_dummy_ops, s, "tcx.dhc", + memory_region_init_io(&s->dhc, obj, &tcx_dummy_ops, s, "tcx.dhc", TCX_DHC_NREGS); sysbus_init_mmio(sbd, &s->dhc); /* 12/ALT : ??? */ - memory_region_init_io(&s->alt, OBJECT(s), &tcx_dummy_ops, s, "tcx.alt", + memory_region_init_io(&s->alt, obj, &tcx_dummy_ops, s, "tcx.alt", TCX_ALT_NREGS); sysbus_init_mmio(sbd, &s->alt); - - return; } static void tcx_realizefn(DeviceState *dev, Error **errp) @@ -1007,7 +1008,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) char *fcode_filename; memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram", - s->vram_size * (1 + 4 + 4), &error_abort); + s->vram_size * (1 + 4 + 4), &error_fatal); vmstate_register_ram_global(&s->vram_mem); memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA); vram_base = memory_region_get_ram_ptr(&s->vram_mem); diff --git a/qemu/hw/display/vga-isa-mm.c b/qemu/hw/display/vga-isa-mm.c index 4efc22278..51ccbccc4 100644 --- a/qemu/hw/display/vga-isa-mm.c +++ b/qemu/hw/display/vga-isa-mm.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" #include "hw/i386/pc.h" diff --git a/qemu/hw/display/vga-isa.c b/qemu/hw/display/vga-isa.c index 7f3c98941..f5aff1cbe 100644 --- a/qemu/hw/display/vga-isa.c +++ b/qemu/hw/display/vga-isa.c @@ -23,6 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" #include "hw/i386/pc.h" diff --git a/qemu/hw/display/vga-pci.c b/qemu/hw/display/vga-pci.c index 1dfa331e6..ac9a76499 100644 --- a/qemu/hw/display/vga-pci.c +++ b/qemu/hw/display/vga-pci.c @@ -23,6 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" #include "hw/pci/pci.h" diff --git a/qemu/hw/display/vga.c b/qemu/hw/display/vga.c index b35d523e6..4a55ec6db 100644 --- a/qemu/hw/display/vga.c +++ b/qemu/hw/display/vga.c @@ -21,6 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "vga.h" #include "ui/console.h" @@ -140,6 +142,13 @@ static uint32_t expand4[256]; static uint16_t expand2[256]; static uint8_t expand4to8[16]; +static void vbe_update_vgaregs(VGACommonState *s); + +static inline bool vbe_enabled(VGACommonState *s) +{ + return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED; +} + static void vga_update_memory_access(VGACommonState *s) { hwaddr base, offset, size; @@ -177,6 +186,7 @@ static void vga_update_memory_access(VGACommonState *s) size = 0x8000; break; } + assert(offset + size <= s->vram_size); memory_region_init_alias(&s->chain4_alias, memory_region_owner(&s->vram), "vga.chain4", &s->vram, offset, size); memory_region_add_subregion_overlap(s->legacy_address_space, base, @@ -234,9 +244,9 @@ static void vga_precise_update_retrace_info(VGACommonState *s) r->total_chars = vtotal_lines * htotal_chars; if (r->freq) { - r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq); + r->ticks_per_char = NANOSECONDS_PER_SECOND / (r->total_chars * r->freq); } else { - r->ticks_per_char = get_ticks_per_sec() / chars_per_sec; + r->ticks_per_char = NANOSECONDS_PER_SECOND / chars_per_sec; } r->vstart = vretr_start_line; @@ -264,7 +274,7 @@ static void vga_precise_update_retrace_info(VGACommonState *s) "dots = %d\n" "ticks/char = %" PRId64 "\n" "\n", - (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars), + (double) NANOSECONDS_PER_SECOND / (r->ticks_per_char * r->total_chars), htotal_chars, hretr_start_char, hretr_skew_chars, @@ -476,6 +486,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); #endif s->sr[s->sr_index] = val & sr_mask[s->sr_index]; + vbe_update_vgaregs(s); if (s->sr_index == VGA_SEQ_CLOCK_MODE) { s->update_retrace_info(s); } @@ -507,6 +518,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); #endif s->gr[s->gr_index] = val & gr_mask[s->gr_index]; + vbe_update_vgaregs(s); vga_update_memory_access(s); break; case VGA_CRT_IM: @@ -525,10 +537,12 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (s->cr_index == VGA_CRTC_OVERFLOW) { s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) | (val & 0x10); + vbe_update_vgaregs(s); } return; } s->cr[s->cr_index] = val; + vbe_update_vgaregs(s); switch(s->cr_index) { case VGA_CRTC_H_TOTAL: @@ -561,7 +575,7 @@ static void vbe_fixup_regs(VGACommonState *s) uint16_t *r = s->vbe_regs; uint32_t bits, linelength, maxy, offset; - if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { + if (!vbe_enabled(s)) { /* vbe is turned off -- nothing to do */ return; } @@ -636,6 +650,49 @@ static void vbe_fixup_regs(VGACommonState *s) s->vbe_start_addr = offset / 4; } +/* we initialize the VGA graphic mode */ +static void vbe_update_vgaregs(VGACommonState *s) +{ + int h, shift_control; + + if (!vbe_enabled(s)) { + /* vbe is turned off -- nothing to do */ + return; + } + + /* graphic mode + memory map 1 */ + s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 | + VGA_GR06_GRAPHICS_MODE; + s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */ + s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3; + /* width */ + s->cr[VGA_CRTC_H_DISP] = + (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; + /* height (only meaningful if < 1024) */ + h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; + s->cr[VGA_CRTC_V_DISP_END] = h; + s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) | + ((h >> 7) & 0x02) | ((h >> 3) & 0x40); + /* line compare to 1023 */ + s->cr[VGA_CRTC_LINE_COMPARE] = 0xff; + s->cr[VGA_CRTC_OVERFLOW] |= 0x10; + s->cr[VGA_CRTC_MAX_SCAN] |= 0x40; + + if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { + shift_control = 0; + s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */ + } else { + shift_control = 2; + /* set chain 4 mode */ + s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M; + /* activate all planes */ + s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES; + } + s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) | + (shift_control << 5); + s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */ +} + static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) { VGACommonState *s = opaque; @@ -712,13 +769,10 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) case VBE_DISPI_INDEX_Y_OFFSET: s->vbe_regs[s->vbe_index] = val; vbe_fixup_regs(s); + vbe_update_vgaregs(s); break; case VBE_DISPI_INDEX_BANK: - if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { - val &= (s->vbe_bank_mask >> 2); - } else { - val &= s->vbe_bank_mask; - } + val &= s->vbe_bank_mask; s->vbe_regs[s->vbe_index] = val; s->bank_offset = (val << 16); vga_update_memory_access(s); @@ -726,52 +780,19 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) case VBE_DISPI_INDEX_ENABLE: if ((val & VBE_DISPI_ENABLED) && !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { - int h, shift_control; s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0; s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED; vbe_fixup_regs(s); + vbe_update_vgaregs(s); /* clear the screen */ if (!(val & VBE_DISPI_NOCLEARMEM)) { memset(s->vram_ptr, 0, s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); } - - /* we initialize the VGA graphic mode */ - /* graphic mode + memory map 1 */ - s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 | - VGA_GR06_GRAPHICS_MODE; - s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */ - s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3; - /* width */ - s->cr[VGA_CRTC_H_DISP] = - (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; - /* height (only meaningful if < 1024) */ - h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; - s->cr[VGA_CRTC_V_DISP_END] = h; - s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) | - ((h >> 7) & 0x02) | ((h >> 3) & 0x40); - /* line compare to 1023 */ - s->cr[VGA_CRTC_LINE_COMPARE] = 0xff; - s->cr[VGA_CRTC_OVERFLOW] |= 0x10; - s->cr[VGA_CRTC_MAX_SCAN] |= 0x40; - - if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { - shift_control = 0; - s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */ - } else { - shift_control = 2; - /* set chain 4 mode */ - s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M; - /* activate all planes */ - s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES; - } - s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) | - (shift_control << 5); - s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */ } else { s->bank_offset = 0; } @@ -817,13 +838,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr) if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) { /* chain 4 mode : simplest access */ + assert(addr < s->vram_size); ret = s->vram_ptr[addr]; } else if (s->gr[VGA_GFX_MODE] & 0x10) { /* odd/even mode (aka text mode mapping) */ plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1); - ret = s->vram_ptr[((addr & ~1) << 1) | plane]; + addr = ((addr & ~1) << 1) | plane; + if (addr >= s->vram_size) { + return 0xff; + } + ret = s->vram_ptr[addr]; } else { /* standard VGA latched access */ + if (addr * sizeof(uint32_t) >= s->vram_size) { + return 0xff; + } s->latch = ((uint32_t *)s->vram_ptr)[addr]; if (!(s->gr[VGA_GFX_MODE] & 0x08)) { @@ -880,6 +909,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) plane = addr & 3; mask = (1 << plane); if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { + assert(addr < s->vram_size); s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr); @@ -893,6 +923,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) mask = (1 << plane); if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { addr = ((addr & ~1) << 1) | plane; + if (addr >= s->vram_size) { + return; + } s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr); @@ -966,6 +999,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) mask = s->sr[VGA_SEQ_PLANE_WRITE]; s->plane_updated |= mask; /* only used to detect font change */ write_mask = mask16[mask]; + if (addr * sizeof(uint32_t) >= s->vram_size) { + return; + } ((uint32_t *)s->vram_ptr)[addr] = (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | (val & write_mask); @@ -1044,7 +1080,7 @@ static void vga_get_offsets(VGACommonState *s, { uint32_t start_addr, line_offset, line_compare; - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + if (vbe_enabled(s)) { line_offset = s->vbe_line_offset; start_addr = s->vbe_start_addr; line_compare = 65535; @@ -1369,7 +1405,7 @@ static int vga_get_bpp(VGACommonState *s) { int ret; - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + if (vbe_enabled(s)) { ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; } else { ret = 0; @@ -1381,7 +1417,7 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight) { int width, height; - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { + if (vbe_enabled(s)) { width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; } else { @@ -1979,7 +2015,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) width = (s->last_width - size) / 2; dst = chardata + s->last_width + width; for (i = 0; i < size; i ++) - console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); + console_write_ch(dst ++, ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE, + QEMU_COLOR_BLACK, 1)); dpy_text_update(s->con, 0, 0, s->last_width, height); } @@ -2139,7 +2176,7 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate) s->is_vbe_vmstate = 1; memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size, - &error_abort); + &error_fatal); vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj)); xen_register_framebuffer(&s->vram); s->vram_ptr = memory_region_get_ram_ptr(&s->vram); diff --git a/qemu/hw/display/vga_int.h b/qemu/hw/display/vga_int.h index 40ba6a420..bdb43a5a3 100644 --- a/qemu/hw/display/vga_int.h +++ b/qemu/hw/display/vga_int.h @@ -25,7 +25,6 @@ #define HW_VGA_INT_H 1 #include <hw/hw.h> -#include "qapi/error.h" #include "exec/memory.h" #define ST01_V_RETRACE 0x08 diff --git a/qemu/hw/display/virtio-gpu-3d.c b/qemu/hw/display/virtio-gpu-3d.c new file mode 100644 index 000000000..fa192946a --- /dev/null +++ b/qemu/hw/display/virtio-gpu-3d.c @@ -0,0 +1,606 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * Gerd Hoffmann <kraxel@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/iov.h" +#include "trace.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-gpu.h" + +#ifdef CONFIG_VIRGL + +#include "virglrenderer.h" + +static struct virgl_renderer_callbacks virtio_gpu_3d_cbs; + +static void virgl_cmd_create_resource_2d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_create_2d c2d; + struct virgl_renderer_resource_create_args args; + + VIRTIO_GPU_FILL_CMD(c2d); + trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, + c2d.width, c2d.height); + + args.handle = c2d.resource_id; + args.target = 2; + args.format = c2d.format; + args.bind = (1 << 1); + args.width = c2d.width; + args.height = c2d.height; + args.depth = 1; + args.array_size = 1; + args.last_level = 0; + args.nr_samples = 0; + args.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP; + virgl_renderer_resource_create(&args, NULL, 0); +} + +static void virgl_cmd_create_resource_3d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_create_3d c3d; + struct virgl_renderer_resource_create_args args; + + VIRTIO_GPU_FILL_CMD(c3d); + trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format, + c3d.width, c3d.height, c3d.depth); + + args.handle = c3d.resource_id; + args.target = c3d.target; + args.format = c3d.format; + args.bind = c3d.bind; + args.width = c3d.width; + args.height = c3d.height; + args.depth = c3d.depth; + args.array_size = c3d.array_size; + args.last_level = c3d.last_level; + args.nr_samples = c3d.nr_samples; + args.flags = c3d.flags; + virgl_renderer_resource_create(&args, NULL, 0); +} + +static void virgl_cmd_resource_unref(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_unref unref; + + VIRTIO_GPU_FILL_CMD(unref); + trace_virtio_gpu_cmd_res_unref(unref.resource_id); + + virgl_renderer_resource_unref(unref.resource_id); +} + +static void virgl_cmd_context_create(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_ctx_create cc; + + VIRTIO_GPU_FILL_CMD(cc); + trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id, + cc.debug_name); + + virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, + cc.debug_name); +} + +static void virgl_cmd_context_destroy(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_ctx_destroy cd; + + VIRTIO_GPU_FILL_CMD(cd); + trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id); + + virgl_renderer_context_destroy(cd.hdr.ctx_id); +} + +static void virtio_gpu_rect_update(VirtIOGPU *g, int idx, int x, int y, + int width, int height) +{ + if (!g->scanout[idx].con) { + return; + } + + dpy_gl_update(g->scanout[idx].con, x, y, width, height); +} + +static void virgl_cmd_resource_flush(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_flush rf; + int i; + + VIRTIO_GPU_FILL_CMD(rf); + trace_virtio_gpu_cmd_res_flush(rf.resource_id, + rf.r.width, rf.r.height, rf.r.x, rf.r.y); + + for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) { + if (g->scanout[i].resource_id != rf.resource_id) { + continue; + } + virtio_gpu_rect_update(g, i, rf.r.x, rf.r.y, rf.r.width, rf.r.height); + } +} + +static void virgl_cmd_set_scanout(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_set_scanout ss; + struct virgl_renderer_resource_info info; + int ret; + + VIRTIO_GPU_FILL_CMD(ss); + trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, + ss.r.width, ss.r.height, ss.r.x, ss.r.y); + + if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + g->enable = 1; + + memset(&info, 0, sizeof(info)); + + if (ss.resource_id && ss.r.width && ss.r.height) { + ret = virgl_renderer_resource_get_info(ss.resource_id, &info); + if (ret == -1) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: illegal resource specified %d\n", + __func__, ss.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + qemu_console_resize(g->scanout[ss.scanout_id].con, + ss.r.width, ss.r.height); + virgl_renderer_force_ctx_0(); + dpy_gl_scanout(g->scanout[ss.scanout_id].con, info.tex_id, + info.flags & 1 /* FIXME: Y_0_TOP */, + ss.r.x, ss.r.y, ss.r.width, ss.r.height); + } else { + if (ss.scanout_id != 0) { + dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL); + } + dpy_gl_scanout(g->scanout[ss.scanout_id].con, 0, false, + 0, 0, 0, 0); + } + g->scanout[ss.scanout_id].resource_id = ss.resource_id; +} + +static void virgl_cmd_submit_3d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_cmd_submit cs; + void *buf; + size_t s; + + VIRTIO_GPU_FILL_CMD(cs); + trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size); + + buf = g_malloc(cs.size); + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + sizeof(cs), buf, cs.size); + if (s != cs.size) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: size mismatch (%zd/%d)", + __func__, s, cs.size); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + goto out; + } + + if (virtio_gpu_stats_enabled(g->conf)) { + g->stats.req_3d++; + g->stats.bytes_3d += cs.size; + } + + virgl_renderer_submit_cmd(buf, cs.hdr.ctx_id, cs.size / 4); + +out: + g_free(buf); +} + +static void virgl_cmd_transfer_to_host_2d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_transfer_to_host_2d t2d; + struct virtio_gpu_box box; + + VIRTIO_GPU_FILL_CMD(t2d); + trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id); + + box.x = t2d.r.x; + box.y = t2d.r.y; + box.z = 0; + box.w = t2d.r.width; + box.h = t2d.r.height; + box.d = 1; + + virgl_renderer_transfer_write_iov(t2d.resource_id, + 0, + 0, + 0, + 0, + (struct virgl_box *)&box, + t2d.offset, NULL, 0); +} + +static void virgl_cmd_transfer_to_host_3d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_transfer_host_3d t3d; + + VIRTIO_GPU_FILL_CMD(t3d); + trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id); + + virgl_renderer_transfer_write_iov(t3d.resource_id, + t3d.hdr.ctx_id, + t3d.level, + t3d.stride, + t3d.layer_stride, + (struct virgl_box *)&t3d.box, + t3d.offset, NULL, 0); +} + +static void +virgl_cmd_transfer_from_host_3d(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_transfer_host_3d tf3d; + + VIRTIO_GPU_FILL_CMD(tf3d); + trace_virtio_gpu_cmd_res_xfer_fromh_3d(tf3d.resource_id); + + virgl_renderer_transfer_read_iov(tf3d.resource_id, + tf3d.hdr.ctx_id, + tf3d.level, + tf3d.stride, + tf3d.layer_stride, + (struct virgl_box *)&tf3d.box, + tf3d.offset, NULL, 0); +} + + +static void virgl_resource_attach_backing(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_attach_backing att_rb; + struct iovec *res_iovs; + int ret; + + VIRTIO_GPU_FILL_CMD(att_rb); + trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id); + + ret = virtio_gpu_create_mapping_iov(&att_rb, cmd, &res_iovs); + if (ret != 0) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + return; + } + + virgl_renderer_resource_attach_iov(att_rb.resource_id, + res_iovs, att_rb.nr_entries); +} + +static void virgl_resource_detach_backing(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_detach_backing detach_rb; + struct iovec *res_iovs = NULL; + int num_iovs = 0; + + VIRTIO_GPU_FILL_CMD(detach_rb); + trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id); + + virgl_renderer_resource_detach_iov(detach_rb.resource_id, + &res_iovs, + &num_iovs); + if (res_iovs == NULL || num_iovs == 0) { + return; + } + virtio_gpu_cleanup_mapping_iov(res_iovs, num_iovs); +} + + +static void virgl_cmd_ctx_attach_resource(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_ctx_resource att_res; + + VIRTIO_GPU_FILL_CMD(att_res); + trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id, + att_res.resource_id); + + virgl_renderer_ctx_attach_resource(att_res.hdr.ctx_id, att_res.resource_id); +} + +static void virgl_cmd_ctx_detach_resource(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_ctx_resource det_res; + + VIRTIO_GPU_FILL_CMD(det_res); + trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id, + det_res.resource_id); + + virgl_renderer_ctx_detach_resource(det_res.hdr.ctx_id, det_res.resource_id); +} + +static void virgl_cmd_get_capset_info(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_get_capset_info info; + struct virtio_gpu_resp_capset_info resp; + + VIRTIO_GPU_FILL_CMD(info); + + if (info.capset_index == 0) { + resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; + virgl_renderer_get_cap_set(resp.capset_id, + &resp.capset_max_version, + &resp.capset_max_size); + } else { + resp.capset_max_version = 0; + resp.capset_max_size = 0; + } + resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO; + virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp)); +} + +static void virgl_cmd_get_capset(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_get_capset gc; + struct virtio_gpu_resp_capset *resp; + uint32_t max_ver, max_size; + VIRTIO_GPU_FILL_CMD(gc); + + virgl_renderer_get_cap_set(gc.capset_id, &max_ver, + &max_size); + resp = g_malloc(sizeof(*resp) + max_size); + + resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET; + virgl_renderer_fill_caps(gc.capset_id, + gc.capset_version, + (void *)resp->capset_data); + virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + max_size); + g_free(resp); +} + +void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); + + cmd->waiting = g->renderer_blocked; + if (cmd->waiting) { + return; + } + + virgl_renderer_force_ctx_0(); + switch (cmd->cmd_hdr.type) { + case VIRTIO_GPU_CMD_CTX_CREATE: + virgl_cmd_context_create(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_DESTROY: + virgl_cmd_context_destroy(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: + virgl_cmd_create_resource_2d(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D: + virgl_cmd_create_resource_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_SUBMIT_3D: + virgl_cmd_submit_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: + virgl_cmd_transfer_to_host_2d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D: + virgl_cmd_transfer_to_host_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D: + virgl_cmd_transfer_from_host_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: + virgl_resource_attach_backing(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: + virgl_resource_detach_backing(g, cmd); + break; + case VIRTIO_GPU_CMD_SET_SCANOUT: + virgl_cmd_set_scanout(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_FLUSH: + virgl_cmd_resource_flush(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_UNREF: + virgl_cmd_resource_unref(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE: + /* TODO add security */ + virgl_cmd_ctx_attach_resource(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE: + /* TODO add security */ + virgl_cmd_ctx_detach_resource(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_CAPSET_INFO: + virgl_cmd_get_capset_info(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_CAPSET: + virgl_cmd_get_capset(g, cmd); + break; + + case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: + virtio_gpu_get_display_info(g, cmd); + break; + default: + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + break; + } + + if (cmd->finished) { + return; + } + if (cmd->error) { + fprintf(stderr, "%s: ctrl 0x%x, error 0x%x\n", __func__, + cmd->cmd_hdr.type, cmd->error); + virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error); + return; + } + if (!(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) { + virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA); + return; + } + + trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type); + virgl_renderer_create_fence(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type); +} + +static void virgl_write_fence(void *opaque, uint32_t fence) +{ + VirtIOGPU *g = opaque; + struct virtio_gpu_ctrl_command *cmd, *tmp; + + QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) { + /* + * the guest can end up emitting fences out of order + * so we should check all fenced cmds not just the first one. + */ + if (cmd->cmd_hdr.fence_id > fence) { + continue; + } + trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id); + virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA); + QTAILQ_REMOVE(&g->fenceq, cmd, next); + g_free(cmd); + g->inflight--; + if (virtio_gpu_stats_enabled(g->conf)) { + fprintf(stderr, "inflight: %3d (-)\r", g->inflight); + } + } +} + +static virgl_renderer_gl_context +virgl_create_context(void *opaque, int scanout_idx, + struct virgl_renderer_gl_ctx_param *params) +{ + VirtIOGPU *g = opaque; + QEMUGLContext ctx; + QEMUGLParams qparams; + + qparams.major_ver = params->major_ver; + qparams.minor_ver = params->minor_ver; + + ctx = dpy_gl_ctx_create(g->scanout[scanout_idx].con, &qparams); + return (virgl_renderer_gl_context)ctx; +} + +static void virgl_destroy_context(void *opaque, virgl_renderer_gl_context ctx) +{ + VirtIOGPU *g = opaque; + QEMUGLContext qctx = (QEMUGLContext)ctx; + + dpy_gl_ctx_destroy(g->scanout[0].con, qctx); +} + +static int virgl_make_context_current(void *opaque, int scanout_idx, + virgl_renderer_gl_context ctx) +{ + VirtIOGPU *g = opaque; + QEMUGLContext qctx = (QEMUGLContext)ctx; + + return dpy_gl_ctx_make_current(g->scanout[scanout_idx].con, qctx); +} + +static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = { + .version = 1, + .write_fence = virgl_write_fence, + .create_gl_context = virgl_create_context, + .destroy_gl_context = virgl_destroy_context, + .make_current = virgl_make_context_current, +}; + +static void virtio_gpu_print_stats(void *opaque) +{ + VirtIOGPU *g = opaque; + + if (g->stats.requests) { + fprintf(stderr, "stats: vq req %4d, %3d -- 3D %4d (%5d)\n", + g->stats.requests, + g->stats.max_inflight, + g->stats.req_3d, + g->stats.bytes_3d); + g->stats.requests = 0; + g->stats.max_inflight = 0; + g->stats.req_3d = 0; + g->stats.bytes_3d = 0; + } else { + fprintf(stderr, "stats: idle\r"); + } + timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); +} + +static void virtio_gpu_fence_poll(void *opaque) +{ + VirtIOGPU *g = opaque; + + virgl_renderer_poll(); + virtio_gpu_process_cmdq(g); + if (!QTAILQ_EMPTY(&g->cmdq) || !QTAILQ_EMPTY(&g->fenceq)) { + timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10); + } +} + +void virtio_gpu_virgl_fence_poll(VirtIOGPU *g) +{ + virtio_gpu_fence_poll(g); +} + +void virtio_gpu_virgl_reset(VirtIOGPU *g) +{ + int i; + + /* virgl_renderer_reset() ??? */ + for (i = 0; i < g->conf.max_outputs; i++) { + if (i != 0) { + dpy_gfx_replace_surface(g->scanout[i].con, NULL); + } + dpy_gl_scanout(g->scanout[i].con, 0, false, 0, 0, 0, 0); + } +} + +int virtio_gpu_virgl_init(VirtIOGPU *g) +{ + int ret; + + ret = virgl_renderer_init(g, 0, &virtio_gpu_3d_cbs); + if (ret != 0) { + return ret; + } + + g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL, + virtio_gpu_fence_poll, g); + + if (virtio_gpu_stats_enabled(g->conf)) { + g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, + virtio_gpu_print_stats, g); + timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); + } + return 0; +} + +#endif /* CONFIG_VIRGL */ diff --git a/qemu/hw/display/virtio-gpu-pci.c b/qemu/hw/display/virtio-gpu-pci.c index 5bc62cf34..a71b230d3 100644 --- a/qemu/hw/display/virtio-gpu-pci.c +++ b/qemu/hw/display/virtio-gpu-pci.c @@ -6,10 +6,11 @@ * Authors: * Dave Airlie * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. * */ +#include "qemu/osdep.h" #include "hw/pci/pci.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-bus.h" diff --git a/qemu/hw/display/virtio-gpu.c b/qemu/hw/display/virtio-gpu.c index a67d927f5..c181fb364 100644 --- a/qemu/hw/display/virtio-gpu.c +++ b/qemu/hw/display/virtio-gpu.c @@ -7,10 +7,11 @@ * Dave Airlie <airlied@redhat.com> * Gerd Hoffmann <kraxel@redhat.com> * - * This work is licensed under the terms of the GNU GPL, version 2. + * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/iov.h" #include "ui/console.h" @@ -22,6 +23,23 @@ static struct virtio_gpu_simple_resource* virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); +#ifdef CONFIG_VIRGL +#include "virglrenderer.h" +#define VIRGL(_g, _virgl, _simple, ...) \ + do { \ + if (_g->use_virgl_renderer) { \ + _virgl(__VA_ARGS__); \ + } else { \ + _simple(__VA_ARGS__); \ + } \ + } while (0) +#else +#define VIRGL(_g, _virgl, _simple, ...) \ + do { \ + _simple(__VA_ARGS__); \ + } while (0) +#endif + static void update_cursor_data_simple(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id) @@ -45,16 +63,49 @@ static void update_cursor_data_simple(VirtIOGPU *g, pixels * sizeof(uint32_t)); } +#ifdef CONFIG_VIRGL + +static void update_cursor_data_virgl(VirtIOGPU *g, + struct virtio_gpu_scanout *s, + uint32_t resource_id) +{ + uint32_t width, height; + uint32_t pixels, *data; + + data = virgl_renderer_get_cursor_data(resource_id, &width, &height); + if (!data) { + return; + } + + if (width != s->current_cursor->width || + height != s->current_cursor->height) { + return; + } + + pixels = s->current_cursor->width * s->current_cursor->height; + memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t)); + free(data); +} + +#endif + static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) { struct virtio_gpu_scanout *s; + bool move = cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR; if (cursor->pos.scanout_id >= g->conf.max_outputs) { return; } s = &g->scanout[cursor->pos.scanout_id]; - if (cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR) { + trace_virtio_gpu_update_cursor(cursor->pos.scanout_id, + cursor->pos.x, + cursor->pos.y, + move ? "move" : "update", + cursor->resource_id); + + if (move) { if (!s->current_cursor) { s->current_cursor = cursor_alloc(64, 64); } @@ -63,7 +114,8 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) s->current_cursor->hot_y = cursor->hot_y; if (cursor->resource_id > 0) { - update_cursor_data_simple(g, s, cursor->resource_id); + VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple, + g, s, cursor->resource_id); } dpy_cursor_define(s->con, s->current_cursor); } @@ -92,9 +144,23 @@ static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config) static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features, Error **errp) { + VirtIOGPU *g = VIRTIO_GPU(vdev); + + if (virtio_gpu_virgl_enabled(g->conf)) { + features |= (1 << VIRTIO_GPU_F_VIRGL); + } return features; } +static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features) +{ + static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); + VirtIOGPU *g = VIRTIO_GPU(vdev); + + g->use_virgl_renderer = ((features & virgl) == virgl); + trace_virtio_gpu_features(g->use_virgl_renderer); +} + static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type) { g->virtio_config.events_read |= event_type; @@ -506,10 +572,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, scanout->width != ss.r.width || scanout->height != ss.r.height) { /* realloc the surface ptr */ - scanout->ds = qemu_create_displaysurface_from - (ss.r.width, ss.r.height, format, - pixman_image_get_stride(res->image), - (uint8_t *)pixman_image_get_data(res->image) + offset); + scanout->ds = qemu_create_displaysurface_pixman(res->image); if (!scanout->ds) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; @@ -563,7 +626,6 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, __func__, ab->resource_id, i); virtio_gpu_cleanup_mapping_iov(*iov, i); g_free(ents); - g_free(*iov); *iov = NULL; return -1; } @@ -580,12 +642,12 @@ void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count) cpu_physical_memory_unmap(iov[i].iov_base, iov[i].iov_len, 1, iov[i].iov_len); } + g_free(iov); } static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res) { virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt); - g_free(res->iov); res->iov = NULL; res->iov_cnt = 0; } @@ -690,6 +752,39 @@ static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq) qemu_bh_schedule(g->cursor_bh); } +void virtio_gpu_process_cmdq(VirtIOGPU *g) +{ + struct virtio_gpu_ctrl_command *cmd; + + while (!QTAILQ_EMPTY(&g->cmdq)) { + cmd = QTAILQ_FIRST(&g->cmdq); + + /* process command */ + VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd, + g, cmd); + if (cmd->waiting) { + break; + } + QTAILQ_REMOVE(&g->cmdq, cmd, next); + if (virtio_gpu_stats_enabled(g->conf)) { + g->stats.requests++; + } + + if (!cmd->finished) { + QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next); + g->inflight++; + if (virtio_gpu_stats_enabled(g->conf)) { + if (g->stats.max_inflight < g->inflight) { + g->stats.max_inflight = g->inflight; + } + fprintf(stderr, "inflight: %3d (+)\r", g->inflight); + } + } else { + g_free(cmd); + } + } +} + static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); @@ -699,25 +794,30 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) return; } - cmd = g_new(struct virtio_gpu_ctrl_command, 1); - while (virtqueue_pop(vq, &cmd->elem)) { +#ifdef CONFIG_VIRGL + if (!g->renderer_inited && g->use_virgl_renderer) { + virtio_gpu_virgl_init(g); + g->renderer_inited = true; + } +#endif + + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + while (cmd) { cmd->vq = vq; cmd->error = 0; cmd->finished = false; - g->stats.requests++; + cmd->waiting = false; + QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + } - virtio_gpu_simple_process_cmd(g, cmd); - if (!cmd->finished) { - QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next); - g->stats.inflight++; - if (g->stats.max_inflight < g->stats.inflight) { - g->stats.max_inflight = g->stats.inflight; - } - fprintf(stderr, "inflight: %3d (+)\r", g->stats.inflight); - cmd = g_new(struct virtio_gpu_ctrl_command, 1); - } + virtio_gpu_process_cmdq(g); + +#ifdef CONFIG_VIRGL + if (g->use_virgl_renderer) { + virtio_gpu_virgl_fence_poll(g); } - g_free(cmd); +#endif } static void virtio_gpu_ctrl_bh(void *opaque) @@ -729,15 +829,20 @@ static void virtio_gpu_ctrl_bh(void *opaque) static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); - VirtQueueElement elem; + VirtQueueElement *elem; size_t s; struct virtio_gpu_update_cursor cursor_info; if (!virtio_queue_ready(vq)) { return; } - while (virtqueue_pop(vq, &elem)) { - s = iov_to_buf(elem.out_sg, elem.out_num, 0, + for (;;) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + + s = iov_to_buf(elem->out_sg, elem->out_num, 0, &cursor_info, sizeof(cursor_info)); if (s != sizeof(cursor_info)) { qemu_log_mask(LOG_GUEST_ERROR, @@ -746,8 +851,9 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) } else { update_cursor(g, &cursor_info); } - virtqueue_push(vq, &elem, 0); + virtqueue_push(vq, elem, 0); virtio_notify(vdev, vq); + g_free(elem); } } @@ -793,17 +899,34 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) return 0; } +static void virtio_gpu_gl_block(void *opaque, bool block) +{ + VirtIOGPU *g = opaque; + + g->renderer_blocked = block; + if (!block) { + virtio_gpu_process_cmdq(g); + } +} + const GraphicHwOps virtio_gpu_ops = { .invalidate = virtio_gpu_invalidate_display, .gfx_update = virtio_gpu_update_display, .text_update = virtio_gpu_text_update, .ui_info = virtio_gpu_ui_info, + .gl_block = virtio_gpu_gl_block, +}; + +static const VMStateDescription vmstate_virtio_gpu_unmigratable = { + .name = "virtio-gpu", + .unmigratable = 1, }; static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(qdev); VirtIOGPU *g = VIRTIO_GPU(qdev); + bool have_virgl; int i; g->config_size = sizeof(struct virtio_gpu_config); @@ -814,12 +937,30 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) g->req_state[0].width = 1024; g->req_state[0].height = 768; - g->ctrl_vq = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb); - g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb); + g->use_virgl_renderer = false; +#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN) + have_virgl = false; +#else + have_virgl = display_opengl; +#endif + if (!have_virgl) { + g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); + } + + if (virtio_gpu_virgl_enabled(g->conf)) { + /* use larger control queue in 3d mode */ + g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb); + g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb); + g->virtio_config.num_capsets = 1; + } else { + g->ctrl_vq = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb); + g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb); + } g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g); g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g); QTAILQ_INIT(&g->reslist); + QTAILQ_INIT(&g->cmdq); QTAILQ_INIT(&g->fenceq); g->enabled_output_bitmask = 1; @@ -832,6 +973,8 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) dpy_gfx_replace_surface(g->scanout[i].con, NULL); } } + + vmstate_register(qdev, -1, &vmstate_virtio_gpu_unmigratable, g); } static void virtio_gpu_instance_init(Object *obj) @@ -869,10 +1012,23 @@ static void virtio_gpu_reset(VirtIODevice *vdev) g->scanout[i].ds = NULL; } g->enabled_output_bitmask = 1; + +#ifdef CONFIG_VIRGL + if (g->use_virgl_renderer) { + virtio_gpu_virgl_reset(g); + g->use_virgl_renderer = 0; + } +#endif } static Property virtio_gpu_properties[] = { DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1), +#ifdef CONFIG_VIRGL + DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags, + VIRTIO_GPU_FLAG_VIRGL_ENABLED, true), + DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags, + VIRTIO_GPU_FLAG_STATS_ENABLED, false), +#endif DEFINE_PROP_END_OF_LIST(), }; @@ -885,6 +1041,7 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) vdc->get_config = virtio_gpu_get_config; vdc->set_config = virtio_gpu_set_config; vdc->get_features = virtio_gpu_get_features; + vdc->set_features = virtio_gpu_set_features; vdc->reset = virtio_gpu_reset; @@ -917,3 +1074,14 @@ QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16); QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32); QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32); QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408); + +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24); diff --git a/qemu/hw/display/virtio-vga.c b/qemu/hw/display/virtio-vga.c index f7e539fe9..e58b165ae 100644 --- a/qemu/hw/display/virtio-vga.c +++ b/qemu/hw/display/virtio-vga.c @@ -1,3 +1,4 @@ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "ui/console.h" @@ -65,11 +66,21 @@ static int virtio_vga_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) return -1; } +static void virtio_vga_gl_block(void *opaque, bool block) +{ + VirtIOVGA *vvga = opaque; + + if (virtio_gpu_ops.gl_block) { + virtio_gpu_ops.gl_block(&vvga->vdev, block); + } +} + static const GraphicHwOps virtio_vga_ops = { .invalidate = virtio_vga_invalidate_display, .gfx_update = virtio_vga_update_display, .text_update = virtio_vga_text_update, .ui_info = virtio_vga_ui_info, + .gl_block = virtio_vga_gl_block, }; /* VGA device wrapper around PCI device around virtio GPU */ diff --git a/qemu/hw/display/vmware_vga.c b/qemu/hw/display/vmware_vga.c index 7f397d3c2..0c63fa851 100644 --- a/qemu/hw/display/vmware_vga.c +++ b/qemu/hw/display/vmware_vga.c @@ -21,6 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "hw/loader.h" #include "trace.h" @@ -488,10 +490,10 @@ static inline int vmsvga_fill_rect(struct vmsvga_state_s *s, #endif struct vmsvga_cursor_definition_s { - int width; - int height; + uint32_t width; + uint32_t height; int id; - int bpp; + uint32_t bpp; int hot_x; int hot_y; uint32_t mask[1024]; @@ -658,7 +660,10 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s) cursor.bpp = vmsvga_fifo_read(s); args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp); - if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask || + if (cursor.width > 256 || + cursor.height > 256 || + cursor.bpp > 32 || + SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask || SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) { goto badcmd; } @@ -1244,7 +1249,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s, s->fifo_size = SVGA_FIFO_SIZE; memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size, - &error_abort); + &error_fatal); vmstate_register_ram_global(&s->fifo_ram); s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram); diff --git a/qemu/hw/display/xenfb.c b/qemu/hw/display/xenfb.c index 5e324ef62..9866dfda5 100644 --- a/qemu/hw/display/xenfb.c +++ b/qemu/hw/display/xenfb.c @@ -24,16 +24,8 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdarg.h> -#include <stdlib.h> -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> +#include "qemu/osdep.h" #include <sys/mman.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <time.h> #include "hw/hw.h" #include "ui/console.h" @@ -95,23 +87,24 @@ struct XenFB { static int common_bind(struct common *c) { - uint64_t mfn; + uint64_t val; + xen_pfn_t mfn; - if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &mfn) == -1) + if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &val) == -1) return -1; - assert(mfn == (xen_pfn_t)mfn); + mfn = (xen_pfn_t)val; + assert(val == mfn); if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1) return -1; - c->page = xc_map_foreign_range(xen_xc, c->xendev.dom, - XC_PAGE_SIZE, - PROT_READ | PROT_WRITE, mfn); + c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom, + PROT_READ | PROT_WRITE, 1, &mfn, NULL); if (c->page == NULL) return -1; xen_be_bind_evtchn(&c->xendev); - xen_be_printf(&c->xendev, 1, "ring mfn %"PRIx64", remote-port %d, local-port %d\n", + xen_be_printf(&c->xendev, 1, "ring mfn %"PRI_xen_pfn", remote-port %d, local-port %d\n", mfn, c->xendev.remote_port, c->xendev.local_port); return 0; @@ -121,7 +114,7 @@ static void common_unbind(struct common *c) { xen_be_unbind_evtchn(&c->xendev); if (c->page) { - munmap(c->page, XC_PAGE_SIZE); + xenforeignmemory_unmap(xen_fmem, c->page, 1); c->page = NULL; } } @@ -248,9 +241,7 @@ static int xenfb_send_motion(struct XenInput *xenfb, event.type = XENKBD_TYPE_MOTION; event.motion.rel_x = rel_x; event.motion.rel_y = rel_y; -#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207 event.motion.rel_z = rel_z; -#endif return xenfb_kbd_event(xenfb, &event); } @@ -265,12 +256,7 @@ static int xenfb_send_position(struct XenInput *xenfb, event.type = XENKBD_TYPE_POS; event.pos.abs_x = abs_x; event.pos.abs_y = abs_y; -#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207 - event.pos.abs_z = z; -#endif -#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208 event.pos.rel_z = z; -#endif return xenfb_kbd_event(xenfb, &event); } @@ -494,15 +480,15 @@ static int xenfb_map_fb(struct XenFB *xenfb) fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages); xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd); - map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom, - PROT_READ, pgmfns, n_fbdirs); + map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom, + PROT_READ, n_fbdirs, pgmfns, NULL); if (map == NULL) goto out; xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map); - munmap(map, n_fbdirs * XC_PAGE_SIZE); + xenforeignmemory_unmap(xen_fmem, map, n_fbdirs); - xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom, - PROT_READ, fbmfns, xenfb->fbpages); + xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom, + PROT_READ, xenfb->fbpages, fbmfns, NULL); if (xenfb->pixels == NULL) goto out; @@ -784,18 +770,21 @@ static void xenfb_invalidate(void *opaque) static void xenfb_handle_events(struct XenFB *xenfb) { - uint32_t prod, cons; + uint32_t prod, cons, out_cons; struct xenfb_page *page = xenfb->c.page; prod = page->out_prod; - if (prod == page->out_cons) - return; + out_cons = page->out_cons; + if (prod - out_cons > XENFB_OUT_RING_LEN) { + return; + } xen_rmb(); /* ensure we see ring contents up to prod */ - for (cons = page->out_cons; cons != prod; cons++) { + for (cons = out_cons; cons != prod; cons++) { union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); + uint8_t type = event->type; int x, y, w, h; - switch (event->type) { + switch (type) { case XENFB_TYPE_UPDATE: if (xenfb->up_count == UP_QUEUE) xenfb->up_fullscreen = 1; @@ -909,6 +898,7 @@ static void fb_disconnect(struct XenDevice *xendev) * Replacing the framebuffer with anonymous shared memory * instead. This releases the guest pages and keeps qemu happy. */ + xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages); fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); |