From patchwork Sat Dec 10 16:45:19 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Blue Swirl X-Patchwork-Id: 130538 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 0E5D0B6F71 for ; Sun, 11 Dec 2011 03:46:00 +1100 (EST) Received: from localhost ([::1]:34973 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RZQ3e-0006vv-3F for incoming@patchwork.ozlabs.org; Sat, 10 Dec 2011 11:45:54 -0500 Received: from eggs.gnu.org ([140.186.70.92]:56031) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RZQ3V-0006vo-Ls for qemu-devel@nongnu.org; Sat, 10 Dec 2011 11:45:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RZQ3U-0002Go-6G for qemu-devel@nongnu.org; Sat, 10 Dec 2011 11:45:45 -0500 Received: from mail-iy0-f173.google.com ([209.85.210.173]:35616) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RZQ3U-000289-0k for qemu-devel@nongnu.org; Sat, 10 Dec 2011 11:45:44 -0500 Received: by mail-iy0-f173.google.com with SMTP id k27so2853445iad.4 for ; Sat, 10 Dec 2011 08:45:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:from:date:message-id:subject:to:content-type; bh=+dsaIBNdmeAtRE/ewLy2zFQHjpmQbZxW2QIu0onyRYE=; b=jAWvE8u0hI+yXcLffaWkPnLiqCrcAQHiShFk2mCb2Dy6mOwf4C3gKZvo0pFHT2Aoir RPoFlYSZZZvGPAWfOvSS6SY+qGqGRg4kRteVREMEGCiXZpoXPwr+jSjTC7DD66G9ANuL Y9wcJY+s/HMfFCgihFXDV0JR8D5pFn9rvftLA= Received: by 10.42.147.72 with SMTP id m8mr6847301icv.56.1323535543741; Sat, 10 Dec 2011 08:45:43 -0800 (PST) MIME-Version: 1.0 Received: by 10.50.202.73 with HTTP; Sat, 10 Dec 2011 08:45:19 -0800 (PST) From: Blue Swirl Date: Sat, 10 Dec 2011 16:45:19 +0000 Message-ID: To: Avi Kivity , qemu-devel X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.210.173 Subject: [Qemu-devel] [PATCH 4/6] memory: find dirty range X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Instead of each target knowing or guessing the guest page size, iterate through the dirty ranges. Signed-off-by: Blue Swirl --- cpu-all.h | 30 ++++++++++++++++++++++++++++++ hw/tcx.c | 54 ++++++++++++++++++++++-------------------------------- hw/vga.c | 16 +++++++--------- memory.c | 16 ++++++++++++++++ memory.h | 24 ++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 41 deletions(-) * * Marks a page as dirty, after it has been dirtied outside guest code. diff --git a/cpu-all.h b/cpu-all.h index 0cb62ca..a5c6670 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -574,6 +574,36 @@ int cpu_physical_memory_set_dirty_tracking(int enable); int cpu_physical_memory_get_dirty_tracking(void); +static inline void cpu_physical_memory_range_find_dirty(ram_addr_t start, + ram_addr_t end, + ram_addr_t *pstart, + ram_addr_t *pend, + int flags) +{ + ram_addr_t idx; + + start >>= TARGET_PAGE_BITS; + end += TARGET_PAGE_SIZE - 1; + end >>= TARGET_PAGE_BITS; + + for (idx = start; idx < end; idx++) { + if (ram_list.phys_dirty[idx] & flags) { + *pstart = idx << TARGET_PAGE_BITS; + for (; idx < end; idx++) { + if (!(ram_list.phys_dirty[idx] & flags)) { + *pend = (idx << TARGET_PAGE_BITS) - 1; + return; + } + } + *pend = (end << TARGET_PAGE_BITS) - 1; + return; + } + } + /* everything pristine */ + *pstart = (end << TARGET_PAGE_BITS) - 1; + *pend = (end << TARGET_PAGE_BITS) - 1; +} + int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr); diff --git a/hw/tcx.c b/hw/tcx.c index fd45ce8..d031cbd 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -212,7 +212,7 @@ static inline void reset_dirty(TCXState *ts, ram_addr_t page_min, static void tcx_update_display(void *opaque) { TCXState *ts = opaque; - ram_addr_t page, page_min, page_max; + ram_addr_t page, page_min, page_max, p; int y, y_start, dd, ds; uint8_t *d, *s; void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); @@ -244,37 +244,28 @@ static void tcx_update_display(void *opaque) return; } - for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { - if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) { - if (y_start < 0) - y_start = y; - if (page < page_min) - page_min = page; - if (page > page_max) - page_max = page; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - } else { - if (y_start >= 0) { - /* flush to display */ - dpy_update(ts->ds, 0, y_start, - ts->width, y - y_start); - y_start = -1; - } - d += dd * 4; - s += ds * 4; + assert(MAXX == 1024); + y = 0; + for (p = 0; p < MAXX * MAXY;) { + target_phys_addr_t dirty_start, dirty_end; + + memory_region_find_dirty(&ts->vram_mem, p, MAXX * MAXY, &dirty_start, + &dirty_end, DIRTY_MEMORY_VGA); + if (dirty_start == MAXX * MAXY - 1) { + break; + } + page = dirty_start; + f(ts, d + (page >> 10) * dd, s + page, dirty_end - dirty_start); + if (y_start < 0) { + page_min = dirty_start; + /* divide by MAXX */ + y_start = page_min >> 10; } + page_max = dirty_end; + y = page_max >> 10; + p = dirty_end + 1; } + if (y_start >= 0) { /* flush to display */ dpy_update(ts->ds, 0, y_start, @@ -282,8 +273,7 @@ static void tcx_update_display(void *opaque) } /* reset modified pages */ if (page_max >= page_min) { - memory_region_reset_dirty(&ts->vram_mem, - page_min, page_max + TARGET_PAGE_SIZE, + memory_region_reset_dirty(&ts->vram_mem, page_min, page_max, DIRTY_MEMORY_VGA); } } diff --git a/hw/vga.c b/hw/vga.c index 85176a6..16c94b6 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1731,6 +1731,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) linesize = ds_get_linesize(s->ds); y1 = 0; for(y = 0; y < height; y++) { + target_phys_addr_t dirty_start, dirty_end; + addr = addr1; if (!(s->cr[0x17] & 1)) { int shift; @@ -1741,17 +1743,13 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) if (!(s->cr[0x17] & 2)) { addr = (addr & ~0x8000) | ((y1 & 2) << 14); } + memory_region_find_dirty(&s->vram, addr, addr + bwidth - 1, + &dirty_start, &dirty_end, DIRTY_MEMORY_VGA); + if (dirty_start < addr + bwidth - 1) { + update = 1; + } page0 = addr & TARGET_PAGE_MASK; page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK; - update = full_update | - memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) | - memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA); - if ((page1 - page0) > TARGET_PAGE_SIZE) { - /* if wide line, can use another page */ - update |= memory_region_get_dirty(&s->vram, - page0 + TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); - } /* explicit invalidation for the hardware cursor */ update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; if (update) { diff --git a/memory.c b/memory.c index 71600d0..af684fa 100644 --- a/memory.c +++ b/memory.c @@ -1068,6 +1068,22 @@ bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr, return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client); } +void memory_region_find_dirty(MemoryRegion *mr, target_phys_addr_t start, + target_phys_addr_t end, + target_phys_addr_t *pstart, + target_phys_addr_t *pend, + unsigned client) +{ + ram_addr_t dstart, dend; + + assert(mr->terminates); + cpu_physical_memory_range_find_dirty(mr->ram_addr + start, + mr->ram_addr + end, &dstart, &dend, + 1 << client); + *pstart = dstart - mr->ram_addr; + *pend = dend - mr->ram_addr; +} + void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr, target_phys_addr_t size) { diff --git a/memory.h b/memory.h index 1f8b5a5..ace2708 100644 --- a/memory.h +++ b/memory.h @@ -314,6 +314,30 @@ bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr, unsigned client); /** + * memory_region_find_dirty: Find dirty ranges in a memory range for a + * specified client. + * + * Returns lowest contiguous dirty memory range within the specified memory range. + * Dirty logging must be enabled. + * + * @mr: the memory region being queried. + * @start: the start address (relative to the start of the region) of the + * region being searched. + * @end: the end address (relative to the start of the region) of the + * region being searched. + * *@pstart: the returned start address (relative to the start of the region) + * of the lowest contiguous dirty range found, or @end if not found. + * *@pend: the returned end address (relative to the start of the region) + * of the lowest contiguous dirty range found. + * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or + * %DIRTY_MEMORY_VGA. + */ +void memory_region_find_dirty(MemoryRegion *mr, target_phys_addr_t start, + target_phys_addr_t end, + target_phys_addr_t *pstart, + target_phys_addr_t *pend, + unsigned client); +/** * memory_region_set_dirty: Mark a page as dirty in a memory region.