From 9d9ae0f07bc5f7c7f51832c6446dd3e115531427 Mon Sep 17 00:00:00 2001 From: Cong Liu Date: Tue, 31 Oct 2023 09:25:15 +0800 Subject: virtio-gpu-rutabaga: Add empty interface to fix arm64 crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an empty element to the interfaces array, which is consistent with the behavior of other devices in qemu and fixes the crash on arm64. 0 0x0000fffff5c18550 in () at /usr/lib64/libc.so.6 1 0x0000fffff6c9cd6c in g_strdup () at /usr/lib64/libglib-2.0.so.0 2 0x0000aaaaab4945d8 in g_strdup_inline (str=) at /usr/include/glib-2.0/glib/gstrfuncs.h:321 3 type_new (info=info@entry=0xaaaaabc1b2c8 ) at ../qom/object.c:133 4 0x0000aaaaab494f14 in type_register_internal (info=0xaaaaabc1b2c8 ) at ../qom/object.c:143 5 type_register (info=0xaaaaabc1b2c8 ) at ../qom/object.c:152 6 type_register_static (info=0xaaaaabc1b2c8 ) at ../qom/object.c:157 7 type_register_static_array (infos=, nr_infos=) at ../qom/object.c:165 8 0x0000aaaaab6147e8 in module_call_init (type=type@entry=MODULE_INIT_QOM) at ../util/module.c:109 9 0x0000aaaaab10a0ec in qemu_init_subsystems () at ../system/runstate.c:817 10 0x0000aaaaab10d334 in qemu_init (argc=13, argv=0xfffffffff198) at ../system/vl.c:2760 11 0x0000aaaaaae4da6c in main (argc=, argv=) at ../system/main.c:47 Signed-off-by: Cong Liu Reviewed-by: Gurchetan Singh Reviewed-by: Marc-André Lureau Message-Id: <20231031012515.15504-1-liucong2@kylinos.cn> --- hw/display/virtio-gpu-pci-rutabaga.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/virtio-gpu-pci-rutabaga.c b/hw/display/virtio-gpu-pci-rutabaga.c index c96729e198..abbb898c65 100644 --- a/hw/display/virtio-gpu-pci-rutabaga.c +++ b/hw/display/virtio-gpu-pci-rutabaga.c @@ -36,6 +36,7 @@ static const TypeInfo virtio_gpu_rutabaga_pci_info[] = { .instance_init = virtio_gpu_rutabaga_initfn, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, } }, }; -- cgit v1.2.3 From f7ecde051dd73fad8265e83c26ea69ae0a86e1d4 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 1 Nov 2023 21:45:36 +0100 Subject: ati-vga: Fix aperture sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently these should be half the memory region sizes confirmed at least by Radeon FCocde ROM while Rage 128 Pro ROMs don't seem to use these. Linux r100 DRM driver also checks for a bit in HOST_PATH_CNTL so we also add that even though the FCode ROM does not seem to set it. Signed-off-by: BALATON Zoltan Reviewed-by: Marc-André Lureau Message-ID: --- hw/display/ati.c | 7 +++++-- hw/display/ati_dbg.c | 1 + hw/display/ati_regs.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index 6e38e00502..9a9ea754bd 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -349,14 +349,17 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) PCI_BASE_ADDRESS_0, size) & 0xfffffff0; break; case CONFIG_APER_SIZE: - val = s->vga.vram_size; + val = s->vga.vram_size / 2; break; case CONFIG_REG_1_BASE: val = pci_default_read_config(&s->dev, PCI_BASE_ADDRESS_2, size) & 0xfffffff0; break; case CONFIG_REG_APER_SIZE: - val = memory_region_size(&s->mm); + val = memory_region_size(&s->mm) / 2; + break; + case HOST_PATH_CNTL: + val = BIT(23); /* Radeon HDP_APER_CNTL */ break; case MC_STATUS: val = 5; diff --git a/hw/display/ati_dbg.c b/hw/display/ati_dbg.c index bd0ecd48c7..4aec1c383a 100644 --- a/hw/display/ati_dbg.c +++ b/hw/display/ati_dbg.c @@ -38,6 +38,7 @@ static struct ati_regdesc ati_reg_names[] = { {"CONFIG_APER_SIZE", 0x0108}, {"CONFIG_REG_1_BASE", 0x010c}, {"CONFIG_REG_APER_SIZE", 0x0110}, + {"HOST_PATH_CNTL", 0x0130}, {"MEM_CNTL", 0x0140}, {"MC_FB_LOCATION", 0x0148}, {"MC_AGP_LOCATION", 0x014C}, diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h index d6282b2ef2..c697b328da 100644 --- a/hw/display/ati_regs.h +++ b/hw/display/ati_regs.h @@ -56,6 +56,7 @@ #define CONFIG_APER_SIZE 0x0108 #define CONFIG_REG_1_BASE 0x010c #define CONFIG_REG_APER_SIZE 0x0110 +#define HOST_PATH_CNTL 0x0130 #define MEM_CNTL 0x0140 #define MC_FB_LOCATION 0x0148 #define MC_AGP_LOCATION 0x014C -- cgit v1.2.3 From e876b3400a01c5f3947de34d6c10388f43192dc9 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 1 Nov 2023 21:45:37 +0100 Subject: ati-vga: Support unaligned access to GPIO DDC registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GPIO_VGA_DDC and GPIO_DVI_DDC registers are used on Radeon for DDC access. Some drivers like the PPC Mac FCode ROM uses unaligned writes to these registers so implement this the same way as already done for GPIO_MONID which is used the same way for the Rage 128 Pro. Signed-off-by: BALATON Zoltan Acked-by: Marc-André Lureau Message-ID: --- hw/display/ati.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index 9a9ea754bd..538651c233 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -319,11 +319,13 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) case DAC_CNTL: val = s->regs.dac_cntl; break; - case GPIO_VGA_DDC: - val = s->regs.gpio_vga_ddc; + case GPIO_VGA_DDC ... GPIO_VGA_DDC + 3: + val = ati_reg_read_offs(s->regs.gpio_vga_ddc, + addr - GPIO_VGA_DDC, size); break; - case GPIO_DVI_DDC: - val = s->regs.gpio_dvi_ddc; + case GPIO_DVI_DDC ... GPIO_DVI_DDC + 3: + val = ati_reg_read_offs(s->regs.gpio_dvi_ddc, + addr - GPIO_DVI_DDC, size); break; case GPIO_MONID ... GPIO_MONID + 3: val = ati_reg_read_offs(s->regs.gpio_monid, @@ -615,29 +617,34 @@ static void ati_mm_write(void *opaque, hwaddr addr, s->regs.dac_cntl = data & 0xffffe3ff; s->vga.dac_8bit = !!(data & DAC_8BIT_EN); break; - case GPIO_VGA_DDC: + /* + * GPIO regs for DDC access. Because some drivers access these via + * multiple byte writes we have to be careful when we send bits to + * avoid spurious changes in bitbang_i2c state. Only do it when either + * the enable bits are changed or output bits changed while enabled. + */ + case GPIO_VGA_DDC ... GPIO_VGA_DDC + 3: if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) { /* FIXME: Maybe add a property to select VGA or DVI port? */ } break; - case GPIO_DVI_DDC: + case GPIO_DVI_DDC ... GPIO_DVI_DDC + 3: if (s->dev_id != PCI_DEVICE_ID_ATI_RAGE128_PF) { - s->regs.gpio_dvi_ddc = ati_i2c(&s->bbi2c, data, 0); + ati_reg_write_offs(&s->regs.gpio_dvi_ddc, + addr - GPIO_DVI_DDC, data, size); + if ((addr <= GPIO_DVI_DDC + 2 && addr + size > GPIO_DVI_DDC + 2) || + (addr == GPIO_DVI_DDC && (s->regs.gpio_dvi_ddc & 0x30000))) { + s->regs.gpio_dvi_ddc = ati_i2c(&s->bbi2c, + s->regs.gpio_dvi_ddc, 0); + } } break; case GPIO_MONID ... GPIO_MONID + 3: /* FIXME What does Radeon have here? */ if (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF) { + /* Rage128p accesses DDC via MONID(1-2) with additional mask bit */ ati_reg_write_offs(&s->regs.gpio_monid, addr - GPIO_MONID, data, size); - /* - * Rage128p accesses DDC used to get EDID via these bits. - * Because some drivers access this via multiple byte writes - * we have to be careful when we send bits to avoid spurious - * changes in bitbang_i2c state. So only do it when mask is set - * and either the enable bits are changed or output bits changed - * while enabled. - */ if ((s->regs.gpio_monid & BIT(25)) && ((addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) || (addr == GPIO_MONID && (s->regs.gpio_monid & 0x60000)))) { -- cgit v1.2.3 From bf9ac62a92ac087e44958ec18f795edfd2bf020a Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 1 Nov 2023 21:45:38 +0100 Subject: ati-vga: Add 30 bit palette access register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Radeon cards have a 30 bit DAC and corresponding palette register to access it. We only use 8 bits but let the guests use 10 bit color values for those that access it through this register. Signed-off-by: BALATON Zoltan Reviewed-by: Marc-André Lureau Message-ID: <9fa19eec95d1563cc65853cf26912f230c702b32.1698871239.git.balaton@eik.bme.hu> --- hw/display/ati.c | 9 +++++++++ hw/display/ati_dbg.c | 1 + hw/display/ati_int.h | 1 + hw/display/ati_regs.h | 1 + 4 files changed, 12 insertions(+) diff --git a/hw/display/ati.c b/hw/display/ati.c index 538651c233..4868f95cf2 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -339,6 +339,9 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) case PALETTE_DATA: val = vga_ioport_read(&s->vga, VGA_PEL_D); break; + case PALETTE_30_DATA: + val = s->regs.palette[vga_ioport_read(&s->vga, VGA_PEL_IR)]; + break; case CNFG_CNTL: val = s->regs.config_cntl; break; @@ -673,6 +676,12 @@ static void ati_mm_write(void *opaque, hwaddr addr, data >>= 8; vga_ioport_write(&s->vga, VGA_PEL_D, data & 0xff); break; + case PALETTE_30_DATA: + s->regs.palette[vga_ioport_read(&s->vga, VGA_PEL_IW)] = data; + vga_ioport_write(&s->vga, VGA_PEL_D, (data >> 22) & 0xff); + vga_ioport_write(&s->vga, VGA_PEL_D, (data >> 12) & 0xff); + vga_ioport_write(&s->vga, VGA_PEL_D, (data >> 2) & 0xff); + break; case CNFG_CNTL: s->regs.config_cntl = data; break; diff --git a/hw/display/ati_dbg.c b/hw/display/ati_dbg.c index 4aec1c383a..3ffa7f35df 100644 --- a/hw/display/ati_dbg.c +++ b/hw/display/ati_dbg.c @@ -30,6 +30,7 @@ static struct ati_regdesc ati_reg_names[] = { {"AMCGPIO_EN_MIR", 0x00a8}, {"PALETTE_INDEX", 0x00b0}, {"PALETTE_DATA", 0x00b4}, + {"PALETTE_30_DATA", 0x00b8}, {"CNFG_CNTL", 0x00e0}, {"GEN_RESET_CNTL", 0x00f0}, {"CNFG_MEMSIZE", 0x00f8}, diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h index e8d3c7af75..8abb873f01 100644 --- a/hw/display/ati_int.h +++ b/hw/display/ati_int.h @@ -44,6 +44,7 @@ typedef struct ATIVGARegs { uint32_t gpio_dvi_ddc; uint32_t gpio_monid; uint32_t config_cntl; + uint32_t palette[256]; uint32_t crtc_h_total_disp; uint32_t crtc_h_sync_strt_wid; uint32_t crtc_v_total_disp; diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h index c697b328da..d7127748ff 100644 --- a/hw/display/ati_regs.h +++ b/hw/display/ati_regs.h @@ -48,6 +48,7 @@ #define AMCGPIO_EN_MIR 0x00a8 #define PALETTE_INDEX 0x00b0 #define PALETTE_DATA 0x00b4 +#define PALETTE_30_DATA 0x00b8 #define CNFG_CNTL 0x00e0 #define GEN_RESET_CNTL 0x00f0 #define CNFG_MEMSIZE 0x00f8 -- cgit v1.2.3 From 08730ee0cc01c3fceb907a93436d15170a7556c4 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 1 Nov 2023 21:45:39 +0100 Subject: ati-vga: Implement fallback for pixman routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pixman routines can fail if no implementation is available and it will become optional soon so add fallbacks when pixman does not work. Signed-off-by: BALATON Zoltan Acked-by: Marc-André Lureau Message-ID: --- hw/display/ati.c | 8 ++++++ hw/display/ati_2d.c | 75 +++++++++++++++++++++++++++++++++++++--------------- hw/display/ati_int.h | 1 + 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index 4868f95cf2..9a87a5504a 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -1033,6 +1033,7 @@ static Property ati_vga_properties[] = { DEFINE_PROP_UINT16("x-device-id", ATIVGAState, dev_id, PCI_DEVICE_ID_ATI_RAGE128_PF), DEFINE_PROP_BOOL("guest_hwcursor", ATIVGAState, cursor_guest_mode, false), + DEFINE_PROP_UINT8("x-pixman", ATIVGAState, use_pixman, 3), DEFINE_PROP_END_OF_LIST() }; @@ -1054,11 +1055,18 @@ static void ati_vga_class_init(ObjectClass *klass, void *data) k->exit = ati_vga_exit; } +static void ati_vga_init(Object *o) +{ + object_property_set_description(o, "x-pixman", "Use pixman for: " + "1: fill, 2: blit"); +} + static const TypeInfo ati_vga_info = { .name = TYPE_ATI_VGA, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(ATIVGAState), .class_init = ati_vga_class_init, + .instance_init = ati_vga_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c index 7d786653e8..0e6b8e4367 100644 --- a/hw/display/ati_2d.c +++ b/hw/display/ati_2d.c @@ -92,6 +92,7 @@ void ati_2d_blt(ATIVGAState *s) switch (s->regs.dp_mix & GMC_ROP3_MASK) { case ROP3_SRCCOPY: { + bool fallback = false; unsigned src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width); unsigned src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? @@ -122,27 +123,50 @@ void ati_2d_blt(ATIVGAState *s) src_bits, dst_bits, src_stride, dst_stride, bpp, bpp, src_x, src_y, dst_x, dst_y, s->regs.dst_width, s->regs.dst_height); - if (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT && + if ((s->use_pixman & BIT(1)) && + s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT && s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM) { - pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits, - src_stride, dst_stride, bpp, bpp, - src_x, src_y, dst_x, dst_y, - s->regs.dst_width, s->regs.dst_height); - } else { + fallback = !pixman_blt((uint32_t *)src_bits, (uint32_t *)dst_bits, + src_stride, dst_stride, bpp, bpp, + src_x, src_y, dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height); + } else if (s->use_pixman & BIT(1)) { /* FIXME: We only really need a temporary if src and dst overlap */ int llb = s->regs.dst_width * (bpp / 8); int tmp_stride = DIV_ROUND_UP(llb, sizeof(uint32_t)); uint32_t *tmp = g_malloc(tmp_stride * sizeof(uint32_t) * s->regs.dst_height); - pixman_blt((uint32_t *)src_bits, tmp, - src_stride, tmp_stride, bpp, bpp, - src_x, src_y, 0, 0, - s->regs.dst_width, s->regs.dst_height); - pixman_blt(tmp, (uint32_t *)dst_bits, - tmp_stride, dst_stride, bpp, bpp, - 0, 0, dst_x, dst_y, - s->regs.dst_width, s->regs.dst_height); + fallback = !pixman_blt((uint32_t *)src_bits, tmp, + src_stride, tmp_stride, bpp, bpp, + src_x, src_y, 0, 0, + s->regs.dst_width, s->regs.dst_height); + if (!fallback) { + fallback = !pixman_blt(tmp, (uint32_t *)dst_bits, + tmp_stride, dst_stride, bpp, bpp, + 0, 0, dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height); + } g_free(tmp); + } else { + fallback = true; + } + if (fallback) { + unsigned int y, i, j, bypp = bpp / 8; + unsigned int src_pitch = src_stride * sizeof(uint32_t); + unsigned int dst_pitch = dst_stride * sizeof(uint32_t); + + for (y = 0; y < s->regs.dst_height; y++) { + i = dst_x * bypp; + j = src_x * bypp; + if (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM) { + i += (dst_y + y) * dst_pitch; + j += (src_y + y) * src_pitch; + } else { + i += (dst_y + s->regs.dst_height - 1 - y) * dst_pitch; + j += (src_y + s->regs.dst_height - 1 - y) * src_pitch; + } + memmove(&dst_bits[i], &src_bits[j], s->regs.dst_width * bypp); + } } if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr && dst_bits < s->vga.vram_ptr + s->vga.vbe_start_addr + @@ -180,14 +204,21 @@ void ati_2d_blt(ATIVGAState *s) dst_stride /= sizeof(uint32_t); DPRINTF("pixman_fill(%p, %d, %d, %d, %d, %d, %d, %x)\n", - dst_bits, dst_stride, bpp, - dst_x, dst_y, - s->regs.dst_width, s->regs.dst_height, - filler); - pixman_fill((uint32_t *)dst_bits, dst_stride, bpp, - dst_x, dst_y, - s->regs.dst_width, s->regs.dst_height, - filler); + dst_bits, dst_stride, bpp, dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height, filler); + if (!(s->use_pixman & BIT(0)) || + !pixman_fill((uint32_t *)dst_bits, dst_stride, bpp, dst_x, dst_y, + s->regs.dst_width, s->regs.dst_height, filler)) { + /* fallback when pixman failed or we don't want to call it */ + unsigned int x, y, i, bypp = bpp / 8; + unsigned int dst_pitch = dst_stride * sizeof(uint32_t); + for (y = 0; y < s->regs.dst_height; y++) { + i = dst_x * bypp + (dst_y + y) * dst_pitch; + for (x = 0; x < s->regs.dst_width; x++, i += bypp) { + stn_he_p(&dst_bits[i], bypp, filler); + } + } + } if (dst_bits >= s->vga.vram_ptr + s->vga.vbe_start_addr && dst_bits < s->vga.vram_ptr + s->vga.vbe_start_addr + s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] * s->vga.vbe_line_offset) { diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h index 8abb873f01..f5a47b82b0 100644 --- a/hw/display/ati_int.h +++ b/hw/display/ati_int.h @@ -90,6 +90,7 @@ struct ATIVGAState { char *model; uint16_t dev_id; uint8_t mode; + uint8_t use_pixman; bool cursor_guest_mode; uint16_t cursor_size; uint32_t cursor_offset; -- cgit v1.2.3 From 9c549ab6895a43ad0cb33e684e11cdb0b5400897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 6 Sep 2023 17:00:22 +0400 Subject: virtio-gpu: block migration of VMs with blob=true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "blob" resources don't have an associated pixman image: #0 pixman_image_get_stride (image=0x0) at ../pixman/pixman-image.c:921 #1 0x0000562327c25236 in virtio_gpu_save (f=0x56232bb13b00, opaque=0x56232b555a60, size=0, field=0x5623289ab6c8 <__compound_literal.3+104>, vmdesc=0x56232ab59fe0) at ../hw/display/virtio-gpu.c:1225 Related to: https://bugzilla.redhat.com/show_bug.cgi?id=2236353 Signed-off-by: Marc-André Lureau Acked-by: Peter Xu --- hw/display/virtio-gpu.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 4265316cbb..dd9965c2ef 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -26,6 +26,7 @@ #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/virtio/virtio-bus.h" #include "hw/qdev-properties.h" +#include "migration/blocker.h" #include "qemu/log.h" #include "qemu/module.h" #include "qapi/error.h" @@ -40,6 +41,8 @@ virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id, static void virtio_gpu_reset_bh(void *opaque); +static Error *blob_mig_blocker; + void virtio_gpu_update_cursor_data(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id) @@ -1373,6 +1376,14 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) error_setg(errp, "blobs and virgl are not compatible (yet)"); return; } + + if (!blob_mig_blocker) { + error_setg(&blob_mig_blocker, + "virtio-gpu blob VMs are currently not migratable."); + } + if (migrate_add_blocker(blob_mig_blocker, errp)) { + return; + } } if (!virtio_gpu_base_device_realize(qdev, @@ -1399,6 +1410,9 @@ static void virtio_gpu_device_unrealize(DeviceState *qdev) { VirtIOGPU *g = VIRTIO_GPU(qdev); + if (virtio_gpu_blob_enabled(g->parent_obj.conf)) { + migrate_del_blocker(blob_mig_blocker); + } g_clear_pointer(&g->ctrl_bh, qemu_bh_delete); g_clear_pointer(&g->cursor_bh, qemu_bh_delete); g_clear_pointer(&g->reset_bh, qemu_bh_delete); -- cgit v1.2.3 From e92ffae6ba28f27329752017b59b6133af27d6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 7 Sep 2023 17:00:53 +0400 Subject: virtio-gpu: factor out restore mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same function is going to be used next to restore "blob" resources. Signed-off-by: Marc-André Lureau Acked-by: Peter Xu --- hw/display/virtio-gpu.c | 60 +++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index dd9965c2ef..8efabae7ee 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1233,6 +1233,35 @@ static int virtio_gpu_save(QEMUFile *f, void *opaque, size_t size, return vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL); } +static bool virtio_gpu_load_restore_mapping(VirtIOGPU *g, + struct virtio_gpu_simple_resource *res) +{ + int i; + + for (i = 0; i < res->iov_cnt; i++) { + hwaddr len = res->iov[i].iov_len; + res->iov[i].iov_base = + dma_memory_map(VIRTIO_DEVICE(g)->dma_as, res->addrs[i], &len, + DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED); + + if (!res->iov[i].iov_base || len != res->iov[i].iov_len) { + /* Clean up the half-a-mapping we just created... */ + if (res->iov[i].iov_base) { + dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as, res->iov[i].iov_base, + len, DMA_DIRECTION_TO_DEVICE, 0); + } + /* ...and the mappings for previous loop iterations */ + res->iov_cnt = i; + virtio_gpu_cleanup_mapping(g, res); + return false; + } + } + + QTAILQ_INSERT_HEAD(&g->reslist, res, next); + g->hostmem += res->hostmem; + return true; +} + static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, const VMStateField *field) { @@ -1297,35 +1326,12 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, qemu_get_buffer(f, (void *)pixman_image_get_data(res->image), pixman_image_get_stride(res->image) * res->height); - /* restore mapping */ - for (i = 0; i < res->iov_cnt; i++) { - hwaddr len = res->iov[i].iov_len; - res->iov[i].iov_base = - dma_memory_map(VIRTIO_DEVICE(g)->dma_as, res->addrs[i], &len, - DMA_DIRECTION_TO_DEVICE, - MEMTXATTRS_UNSPECIFIED); - - if (!res->iov[i].iov_base || len != res->iov[i].iov_len) { - /* Clean up the half-a-mapping we just created... */ - if (res->iov[i].iov_base) { - dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as, - res->iov[i].iov_base, - len, - DMA_DIRECTION_TO_DEVICE, - 0); - } - /* ...and the mappings for previous loop iterations */ - res->iov_cnt = i; - virtio_gpu_cleanup_mapping(g, res); - pixman_image_unref(res->image); - g_free(res); - return -EINVAL; - } + if (!virtio_gpu_load_restore_mapping(g, res)) { + pixman_image_unref(res->image); + g_free(res); + return -EINVAL; } - QTAILQ_INSERT_HEAD(&g->reslist, res, next); - g->hostmem += res->hostmem; - resource_id = qemu_get_be32(f); } -- cgit v1.2.3 From 0f2a301db322a7636edf9a759deb46dd8caa8824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 7 Sep 2023 17:02:53 +0400 Subject: virtio-gpu: move scanout restoration to post_load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we are going to introduce an extra subsection for "blob" resources, scanout have to be restored after. Signed-off-by: Marc-André Lureau Acked-by: Peter Xu --- hw/display/virtio-gpu.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 8efabae7ee..26065c6466 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1267,7 +1267,6 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, { VirtIOGPU *g = opaque; struct virtio_gpu_simple_resource *res; - struct virtio_gpu_scanout *scanout; uint32_t resource_id, pformat; void *bits = NULL; int i; @@ -1337,6 +1336,17 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, /* load & apply scanout state */ vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1); + + return 0; +} + +static int virtio_gpu_post_load(void *opaque, int version_id) +{ + VirtIOGPU *g = opaque; + struct virtio_gpu_scanout *scanout; + struct virtio_gpu_simple_resource *res; + int i; + for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { /* FIXME: should take scanout.r.{x,y} into account */ scanout = &g->parent_obj.scanout[i]; @@ -1520,6 +1530,7 @@ static const VMStateDescription vmstate_virtio_gpu = { } /* device */, VMSTATE_END_OF_LIST() }, + .post_load = virtio_gpu_post_load, }; static Property virtio_gpu_properties[] = { -- cgit v1.2.3 From f66767f75c9c2ddebbf17aab37bfd752716a96b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 7 Sep 2023 17:04:31 +0400 Subject: virtio-gpu: add virtio-gpu/blob vmstate subsection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Acked-by: Peter Xu --- hw/display/virtio-gpu.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 26065c6466..1ab662db72 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1216,6 +1216,9 @@ static int virtio_gpu_save(QEMUFile *f, void *opaque, size_t size, assert(QTAILQ_EMPTY(&g->cmdq)); QTAILQ_FOREACH(res, &g->reslist, next) { + if (res->blob_size) { + continue; + } qemu_put_be32(f, res->resource_id); qemu_put_be32(f, res->width); qemu_put_be32(f, res->height); @@ -1340,6 +1343,74 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, return 0; } +static int virtio_gpu_blob_save(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, JSONWriter *vmdesc) +{ + VirtIOGPU *g = opaque; + struct virtio_gpu_simple_resource *res; + int i; + + /* in 2d mode we should never find unprocessed commands here */ + assert(QTAILQ_EMPTY(&g->cmdq)); + + QTAILQ_FOREACH(res, &g->reslist, next) { + if (!res->blob_size) { + continue; + } + qemu_put_be32(f, res->resource_id); + qemu_put_be32(f, res->blob_size); + qemu_put_be32(f, res->iov_cnt); + for (i = 0; i < res->iov_cnt; i++) { + qemu_put_be64(f, res->addrs[i]); + qemu_put_be32(f, res->iov[i].iov_len); + } + } + qemu_put_be32(f, 0); /* end of list */ + + return 0; +} + +static int virtio_gpu_blob_load(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + VirtIOGPU *g = opaque; + struct virtio_gpu_simple_resource *res; + uint32_t resource_id; + int i; + + resource_id = qemu_get_be32(f); + while (resource_id != 0) { + res = virtio_gpu_find_resource(g, resource_id); + if (res) { + return -EINVAL; + } + + res = g_new0(struct virtio_gpu_simple_resource, 1); + res->resource_id = resource_id; + res->blob_size = qemu_get_be32(f); + res->iov_cnt = qemu_get_be32(f); + res->addrs = g_new(uint64_t, res->iov_cnt); + res->iov = g_new(struct iovec, res->iov_cnt); + + /* read data */ + for (i = 0; i < res->iov_cnt; i++) { + res->addrs[i] = qemu_get_be64(f); + res->iov[i].iov_len = qemu_get_be32(f); + } + + if (!virtio_gpu_load_restore_mapping(g, res)) { + g_free(res); + return -EINVAL; + } + + virtio_gpu_init_udmabuf(res); + + resource_id = qemu_get_be32(f); + } + + return 0; +} + static int virtio_gpu_post_load(void *opaque, int version_id) { VirtIOGPU *g = opaque; @@ -1505,6 +1576,32 @@ virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config) } } +static bool virtio_gpu_blob_state_needed(void *opaque) +{ + VirtIOGPU *g = VIRTIO_GPU(opaque); + + return virtio_gpu_blob_enabled(g->parent_obj.conf); +} + +const VMStateDescription vmstate_virtio_gpu_blob_state = { + .name = "virtio-gpu/blob", + .minimum_version_id = VIRTIO_GPU_VM_VERSION, + .version_id = VIRTIO_GPU_VM_VERSION, + .needed = virtio_gpu_blob_state_needed, + .fields = (const VMStateField[]){ + { + .name = "virtio-gpu/blob", + .info = &(const VMStateInfo) { + .name = "blob", + .get = virtio_gpu_blob_load, + .put = virtio_gpu_blob_save, + }, + .flags = VMS_SINGLE, + } /* device */, + VMSTATE_END_OF_LIST() + }, +}; + /* * For historical reasons virtio_gpu does not adhere to virtio migration * scheme as described in doc/virtio-migration.txt, in a sense that no @@ -1530,6 +1627,10 @@ static const VMStateDescription vmstate_virtio_gpu = { } /* device */, VMSTATE_END_OF_LIST() }, + .subsections = (const VMStateDescription * []) { + &vmstate_virtio_gpu_blob_state, + NULL + }, .post_load = virtio_gpu_post_load, }; -- cgit v1.2.3 From 10b9ddbc83b94986cbdf989e26fb7269fb2e9f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 7 Sep 2023 17:04:58 +0400 Subject: Revert "virtio-gpu: block migration of VMs with blob=true" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we decide to apply this patch (for easier backporting reasons), we can now revert it. Signed-off-by: Marc-André Lureau Acked-by: Peter Xu --- hw/display/virtio-gpu.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 1ab662db72..2707bceea8 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -26,7 +26,6 @@ #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/virtio/virtio-bus.h" #include "hw/qdev-properties.h" -#include "migration/blocker.h" #include "qemu/log.h" #include "qemu/module.h" #include "qapi/error.h" @@ -41,8 +40,6 @@ virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id, static void virtio_gpu_reset_bh(void *opaque); -static Error *blob_mig_blocker; - void virtio_gpu_update_cursor_data(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id) @@ -1463,14 +1460,6 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) error_setg(errp, "blobs and virgl are not compatible (yet)"); return; } - - if (!blob_mig_blocker) { - error_setg(&blob_mig_blocker, - "virtio-gpu blob VMs are currently not migratable."); - } - if (migrate_add_blocker(blob_mig_blocker, errp)) { - return; - } } if (!virtio_gpu_base_device_realize(qdev, @@ -1497,9 +1486,6 @@ static void virtio_gpu_device_unrealize(DeviceState *qdev) { VirtIOGPU *g = VIRTIO_GPU(qdev); - if (virtio_gpu_blob_enabled(g->parent_obj.conf)) { - migrate_del_blocker(blob_mig_blocker); - } g_clear_pointer(&g->ctrl_bh, qemu_bh_delete); g_clear_pointer(&g->cursor_bh, qemu_bh_delete); g_clear_pointer(&g->reset_bh, qemu_bh_delete); -- cgit v1.2.3