From patchwork Tue Apr 4 10:23:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gerd Hoffmann X-Patchwork-Id: 9661241 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 1CD70602B9 for ; Tue, 4 Apr 2017 10:24:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0E55B28307 for ; Tue, 4 Apr 2017 10:24:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 03335284D1; Tue, 4 Apr 2017 10:24:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 995A228307 for ; Tue, 4 Apr 2017 10:24:30 +0000 (UTC) Received: from localhost ([::1]:34810 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cvLdV-00028t-Mr for patchwork-qemu-devel@patchwork.kernel.org; Tue, 04 Apr 2017 06:24:29 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54136) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cvLcY-00026l-Lr for qemu-devel@nongnu.org; Tue, 04 Apr 2017 06:23:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cvLcT-0002CY-JQ for qemu-devel@nongnu.org; Tue, 04 Apr 2017 06:23:30 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57300) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cvLcT-00029w-An for qemu-devel@nongnu.org; Tue, 04 Apr 2017 06:23:25 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AAC0319CBD1; Tue, 4 Apr 2017 10:23:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com AAC0319CBD1 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=kraxel@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com AAC0319CBD1 Received: from nilsson.home.kraxel.org (ovpn-116-84.ams2.redhat.com [10.36.116.84]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3DF0277E37; Tue, 4 Apr 2017 10:23:21 +0000 (UTC) Received: by nilsson.home.kraxel.org (Postfix, from userid 500) id 4523F80CE3; Tue, 4 Apr 2017 12:23:20 +0200 (CEST) From: Gerd Hoffmann To: qemu-devel@nongnu.org Date: Tue, 4 Apr 2017 12:23:09 +0200 Message-Id: <20170404102315.24923-5-kraxel@redhat.com> In-Reply-To: <20170404102315.24923-1-kraxel@redhat.com> References: <20170404102315.24923-1-kraxel@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 04 Apr 2017 10:23:23 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 04/10] vga: make display updates thread safe. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Alex=20Benn=C3=A9e?= , Paolo Bonzini , Mark Cave-Ayland , Gerd Hoffmann Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP The vga code clears the dirty bits *after* reading the framebuffer memory. So if the guest framebuffer updates hits the race window between vga reading the framebuffer and vga clearing the dirty bits vga will miss that update Fix it by using the new memory_region_copy_and_clear_dirty() memory_region_copy_get_dirty() functions. That way we clear the dirty bitmap before reading the framebuffer. Any guest display updates happening in parallel will be properly tracked in the dirty bitmap then and the next display refresh will pick them up. Problem triggers with mttcg only. Before mttcg was merged tcg never ran in parallel to vga emulation. Using kvm will hide the problem too, due to qemu operating on a userspace copy of the kernel's dirty bitmap. Signed-off-by: Gerd Hoffmann --- hw/display/vga.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/hw/display/vga.c b/hw/display/vga.c index f320946..9bb71f1 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1465,7 +1465,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) DisplaySurface *surface = qemu_console_surface(s->con); int y1, y, update, linesize, y_start, double_scan, mask, depth; int width, height, shift_control, line_offset, bwidth, bits; - ram_addr_t page0, page1, page_min, page_max; + ram_addr_t page0, page1; + DirtyBitmapSnapshot *snap = NULL; int disp_width, multi_scan, multi_run; uint8_t *d; uint32_t v, addr1, addr; @@ -1480,9 +1481,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) full_update |= update_basic_params(s); - if (!full_update) - vga_sync_dirty_bitmap(s); - s->get_resolution(s, &width, &height); disp_width = width; @@ -1625,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) addr1 = (s->start_addr * 4); bwidth = (width * bits + 7) / 8; y_start = -1; - page_min = -1; - page_max = 0; d = surface_data(surface); linesize = surface_stride(surface); y1 = 0; + + if (!full_update) { + vga_sync_dirty_bitmap(s); + snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1, + bwidth * height, + DIRTY_MEMORY_VGA); + } + for(y = 0; y < height; y++) { addr = addr1; if (!(s->cr[VGA_CRTC_MODE] & 1)) { @@ -1644,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) update = full_update; page0 = addr; page1 = addr + bwidth - 1; - update |= memory_region_get_dirty(&s->vram, page0, page1 - page0, - DIRTY_MEMORY_VGA); + if (full_update) { + update = 1; + } else { + update = memory_region_snapshot_get_dirty(&s->vram, snap, + page0, page1 - page0); + } /* explicit invalidation for the hardware cursor (cirrus only) */ update |= vga_scanline_invalidated(s, y); if (update) { if (y_start < 0) y_start = y; - if (page0 < page_min) - page_min = page0; - if (page1 > page_max) - page_max = page1; if (!(is_buffer_shared(surface))) { vga_draw_line(s, d, s->vram_ptr + addr, width); if (s->cursor_draw_line) @@ -1687,13 +1691,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) dpy_gfx_update(s->con, 0, y_start, disp_width, y - y_start); } - /* reset modified pages */ - if (page_max >= page_min) { - memory_region_reset_dirty(&s->vram, - page_min, - page_max - page_min, - DIRTY_MEMORY_VGA); - } + g_free(snap); memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table)); }