diff -r 45516ac94c9f xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/hvm/hvm.c Wed Jun 06 12:05:42 2007 -0500 @@ -568,7 +568,7 @@ static int __hvm_copy(void *buf, paddr_t if ( dir ) { memcpy(p, buf, count); /* dir == TRUE: *to* guest */ - mark_dirty(current->domain, mfn); + paging_mark_dirty(current->domain, mfn); } else memcpy(buf, p, count); /* dir == FALSE: *from guest */ diff -r 45516ac94c9f xen/arch/x86/hvm/io.c --- a/xen/arch/x86/hvm/io.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/hvm/io.c Wed Jun 06 12:05:56 2007 -0500 @@ -865,7 +865,7 @@ void hvm_io_assist(void) if ( (p->dir == IOREQ_READ) && p->data_is_ptr ) { gmfn = get_mfn_from_gpfn(paging_gva_to_gfn(v, p->data)); - mark_dirty(d, gmfn); + paging_mark_dirty(d, gmfn); } out: diff -r 45516ac94c9f xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/hvm/svm/svm.c Thu Jun 07 06:36:04 2007 -0500 @@ -1033,8 +1033,8 @@ static int svm_do_nested_pgfault(paddr_t return 1; } - /* We should not reach here. Otherwise, P2M table is not correct.*/ - return 0; + paging_mark_dirty(current->domain, get_mfn_from_gpfn(gpa >> PAGE_SHIFT)); + return p2m_set_flags(current->domain, gpa, __PAGE_HYPERVISOR|_PAGE_USER); } static void svm_do_no_device_fault(struct vmcb_struct *vmcb) diff -r 45516ac94c9f xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/mm.c Wed Jun 06 12:05:10 2007 -0500 @@ -1556,7 +1556,7 @@ int alloc_page_type(struct page_info *pa /* A page table is dirtied when its type count becomes non-zero. */ if ( likely(owner != NULL) ) - mark_dirty(owner, page_to_mfn(page)); + paging_mark_dirty(owner, page_to_mfn(page)); switch ( type & PGT_type_mask ) { @@ -1602,7 +1602,7 @@ void free_page_type(struct page_info *pa if ( unlikely(paging_mode_enabled(owner)) ) { /* A page table is dirtied when its type count becomes zero. */ - mark_dirty(owner, page_to_mfn(page)); + paging_mark_dirty(owner, page_to_mfn(page)); if ( shadow_mode_refcounts(owner) ) return; @@ -2057,7 +2057,7 @@ int do_mmuext_op( } /* A page is dirtied when its pin status is set. */ - mark_dirty(d, mfn); + paging_mark_dirty(d, mfn); /* We can race domain destruction (domain_relinquish_resources). */ if ( unlikely(this_cpu(percpu_mm_info).foreign != NULL) ) @@ -2089,7 +2089,7 @@ int do_mmuext_op( put_page_and_type(page); put_page(page); /* A page is dirtied when its pin status is cleared. */ - mark_dirty(d, mfn); + paging_mark_dirty(d, mfn); } else { @@ -2424,7 +2424,7 @@ int do_mmu_update( set_gpfn_from_mfn(mfn, gpfn); okay = 1; - mark_dirty(FOREIGNDOM, mfn); + paging_mark_dirty(FOREIGNDOM, mfn); put_page(mfn_to_page(mfn)); break; @@ -3005,7 +3005,7 @@ long do_update_descriptor(u64 pa, u64 de break; } - mark_dirty(dom, mfn); + paging_mark_dirty(dom, mfn); /* All is good so make the update. */ gdt_pent = map_domain_page(mfn); diff -r 45516ac94c9f xen/arch/x86/mm/hap/hap.c --- a/xen/arch/x86/mm/hap/hap.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/mm/hap/hap.c Thu Jun 07 05:37:40 2007 -0500 @@ -49,6 +49,35 @@ #undef page_to_mfn #define page_to_mfn(_pg) (_mfn((_pg) - frame_table)) +/************************************************/ +/* HAP LOG DIRTY SUPPORT */ +/************************************************/ +/* hap code to call when log_dirty is enable. return 0 if no problem found. */ +int hap_enable_log_dirty(struct domain *d) +{ + /* turn on PG_log_dirty bit in paging mode */ + d->arch.paging.mode |= PG_log_dirty; + p2m_set_flags_global(d, (_PAGE_PRESENT|_PAGE_USER)); + flush_tlb_all_pge(); + + return 0; +} + +int hap_disable_log_dirty(struct domain *d) +{ + /* log dirty already accquired lock to guard this code */ + d->arch.paging.mode &= ~PG_log_dirty; + p2m_set_flags_global(d, __PAGE_HYPERVISOR|_PAGE_USER); + + return 1; +} + +void hap_clean_dirty_bitmap(struct domain *d) +{ + /* mark physical memory as not writetable and flush the TLB */ + p2m_set_flags_global(d, (_PAGE_PRESENT|_PAGE_USER)); + flush_tlb_all_pge(); +} /************************************************/ /* HAP SUPPORT FUNCTIONS */ /************************************************/ @@ -421,6 +450,10 @@ int hap_enable(struct domain *d, u32 mod } } + /* initialize log dirty here */ + paging_log_dirty_init(d, hap_enable_log_dirty, hap_disable_log_dirty, + hap_clean_dirty_bitmap); + /* allocate P2m table */ if ( mode & PG_translate ) { rv = p2m_alloc_table(d, hap_alloc_p2m_page, hap_free_p2m_page); @@ -478,6 +511,8 @@ void hap_teardown(struct domain *d) d->arch.paging.hap.free_pages, d->arch.paging.hap.p2m_pages); hap_set_allocation(d, 0, NULL); + /* release the log-dirty bitmap of dirty pages */ + paging_free_log_dirty_bitmap(d); HAP_PRINTK("teardown done." " pages total = %u, free = %u, p2m=%u\n", d->arch.paging.hap.total_pages, @@ -498,11 +533,6 @@ int hap_domctl(struct domain *d, xen_dom HERE_I_AM; - if ( unlikely(d == current->domain) ) { - gdprintk(XENLOG_INFO, "Don't try to do a hap op on yourself!\n"); - return -EINVAL; - } - switch ( sc->op ) { case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION: hap_lock(d); diff -r 45516ac94c9f xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/mm/p2m.c Thu Jun 07 05:57:09 2007 -0500 @@ -169,7 +169,7 @@ p2m_next_level(struct domain *d, mfn_t * // Returns 0 on error (out of memory) static int -set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn) +set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, u32 l1e_flags) { // XXX -- this might be able to be faster iff current->domain == d mfn_t table_mfn = pagetable_get_mfn(d->arch.phys_table); @@ -213,7 +213,7 @@ set_p2m_entry(struct domain *d, unsigned d->arch.p2m.max_mapped_pfn = gfn; if ( mfn_valid(mfn) ) - entry_content = l1e_from_pfn(mfn_x(mfn), __PAGE_HYPERVISOR|_PAGE_USER); + entry_content = l1e_from_pfn(mfn_x(mfn), l1e_flags); else entry_content = l1e_empty(); @@ -278,7 +278,7 @@ int p2m_alloc_table(struct domain *d, p2m_unlock(d); return -ENOMEM; } -list_add_tail(&p2m_top->list, &d->arch.p2m.pages); + list_add_tail(&p2m_top->list, &d->arch.p2m.pages); p2m_top->count_info = 1; p2m_top->u.inuse.type_info = @@ -297,8 +297,8 @@ list_add_tail(&p2m_top->list, &d->arch.p /* Initialise physmap tables for slot zero. Other code assumes this. */ gfn = 0; -mfn = _mfn(INVALID_MFN); - if ( !set_p2m_entry(d, gfn, mfn) ) + mfn = _mfn(INVALID_MFN); + if ( !set_p2m_entry(d, gfn, mfn, __PAGE_HYPERVISOR|_PAGE_USER) ) goto error; for ( entry = d->page_list.next; @@ -316,7 +316,7 @@ mfn = _mfn(INVALID_MFN); (gfn != 0x55555555L) #endif && gfn != INVALID_M2P_ENTRY - && !set_p2m_entry(d, gfn, mfn) ) + && !set_p2m_entry(d, gfn, mfn, __PAGE_HYPERVISOR|_PAGE_USER) ) goto error; } @@ -497,7 +497,7 @@ static void audit_p2m(struct domain *d) /* This m2p entry is stale: the domain has another frame in * this physical slot. No great disaster, but for neatness, * blow away the m2p entry. */ - set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY); + set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY, __PAGE_HYPERVISOR|_PAGE_USER); } if ( test_linear && (gfn <= d->arch.p2m.max_mapped_pfn) ) @@ -626,7 +626,7 @@ p2m_remove_page(struct domain *d, unsign ASSERT(mfn_x(gfn_to_mfn(d, gfn)) == mfn); //ASSERT(mfn_to_gfn(d, mfn) == gfn); - set_p2m_entry(d, gfn, _mfn(INVALID_MFN)); + set_p2m_entry(d, gfn, _mfn(INVALID_MFN), __PAGE_HYPERVISOR|_PAGE_USER); set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY); } @@ -659,7 +659,7 @@ guest_physmap_add_page(struct domain *d, omfn = gfn_to_mfn(d, gfn); if ( mfn_valid(omfn) ) { - set_p2m_entry(d, gfn, _mfn(INVALID_MFN)); + set_p2m_entry(d, gfn, _mfn(INVALID_MFN), __PAGE_HYPERVISOR|_PAGE_USER); set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY); } @@ -685,13 +685,129 @@ guest_physmap_add_page(struct domain *d, } } - set_p2m_entry(d, gfn, _mfn(mfn)); + set_p2m_entry(d, gfn, _mfn(mfn), __PAGE_HYPERVISOR|_PAGE_USER); set_gpfn_from_mfn(mfn, gfn); audit_p2m(d); p2m_unlock(d); } +/* This function goes through P2M table and modify l1e flags of all pages. Note + * that physical base address of l1e is intact. This function can be used for + * special purpose, such as marking physical memory as NOT WRITABLE for + * tracking dirty pages during live migration. + */ +void p2m_set_flags_global(struct domain *d, u32 l1e_flags) +{ + unsigned long mfn, gfn; + l1_pgentry_t l1e_content; + l1_pgentry_t *l1e; + l2_pgentry_t *l2e; + int i1, i2; +#if CONFIG_PAGING_LEVELS >= 3 + l3_pgentry_t *l3e; + int i3; +#if CONFIG_PAGING_LEVELS == 4 + l4_pgentry_t *l4e; + int i4; +#endif /* CONFIG_PAGING_LEVELS == 4 */ +#endif /* CONFIG_PAGING_LEVELS >= 3 */ + + if ( !paging_mode_translate(d) ) + return; + + if ( pagetable_get_pfn(d->arch.phys_table) == 0 ) + return; + + p2m_lock(d); + +#if CONFIG_PAGING_LEVELS == 4 + l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); +#elif CONFIG_PAGING_LEVELS == 3 + l3e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); +#else /* CONFIG_PAGING_LEVELS == 2 */ + l2e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); +#endif + +#if CONFIG_PAGING_LEVELS >= 3 +#if CONFIG_PAGING_LEVELS >= 4 + for ( i4 = 0; i4 < L4_PAGETABLE_ENTRIES; i4++ ) + { + if ( !(l4e_get_flags(l4e[i4]) & _PAGE_PRESENT) ) + { + continue; + } + l3e = map_domain_page(mfn_x(_mfn(l4e_get_pfn(l4e[i4])))); +#endif /* now at levels 3 or 4... */ + for ( i3 = 0; + i3 < ((CONFIG_PAGING_LEVELS==4) ? L3_PAGETABLE_ENTRIES : 8); + i3++ ) + { + if ( !(l3e_get_flags(l3e[i3]) & _PAGE_PRESENT) ) + { + continue; + } + l2e = map_domain_page(mfn_x(_mfn(l3e_get_pfn(l3e[i3])))); +#endif /* all levels... */ + for ( i2 = 0; i2 < L2_PAGETABLE_ENTRIES; i2++ ) + { + if ( !(l2e_get_flags(l2e[i2]) & _PAGE_PRESENT) ) + { + continue; + } + l1e = map_domain_page(mfn_x(_mfn(l2e_get_pfn(l2e[i2])))); + + for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++, gfn++ ) + { + if ( !(l1e_get_flags(l1e[i1]) & _PAGE_PRESENT) ) + continue; + mfn = l1e_get_pfn(l1e[i1]); + gfn = get_gpfn_from_mfn(mfn); + /* create a new 1le entry using l1e_flags */ + l1e_content = l1e_from_pfn(mfn, l1e_flags); + paging_write_p2m_entry(d, gfn, &l1e[i1], l1e_content, 1); + } + unmap_domain_page(l1e); + } +#if CONFIG_PAGING_LEVELS >= 3 + unmap_domain_page(l2e); + } +#if CONFIG_PAGING_LEVELS >= 4 + unmap_domain_page(l3e); + } +#endif +#endif + +#if CONFIG_PAGING_LEVELS == 4 + unmap_domain_page(l4e); +#elif CONFIG_PAGING_LEVELS == 3 + unmap_domain_page(l3e); +#else /* CONFIG_PAGING_LEVELS == 2 */ + unmap_domain_page(l2e); +#endif + + p2m_unlock(d); +} + +/* This function traces through P2M table and modifies l1e flags of a specific + * gpa. + */ +int p2m_set_flags(struct domain *d, paddr_t gpa, u32 l1e_flags) +{ + unsigned long gfn; + mfn_t mfn; + + p2m_lock(d); + + gfn = gpa >> PAGE_SHIFT; + mfn = gfn_to_mfn(d, gfn); + if ( mfn_valid(mfn) ) + set_p2m_entry(d, gfn, mfn, l1e_flags); + + p2m_unlock(d); + + return 1; +} /* * Local variables: diff -r 45516ac94c9f xen/arch/x86/mm/paging.c --- a/xen/arch/x86/mm/paging.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/mm/paging.c Thu Jun 07 03:48:49 2007 -0500 @@ -25,6 +25,7 @@ #include #include #include +#include /* Xen command-line option to enable hardware-assisted paging */ int opt_hap_enabled; @@ -41,7 +42,269 @@ boolean_param("hap", opt_hap_enabled); debugtrace_printk("pgdebug: %s(): " _f, __func__, ##_a); \ } while (0) - +/************************************************/ +/* LOG DIRTY SUPPORT */ +/************************************************/ +/* Override macros from asm/page.h to make them work with mfn_t */ +#undef mfn_to_page +#define mfn_to_page(_m) (frame_table + mfn_x(_m)) +#undef mfn_valid +#define mfn_valid(_mfn) (mfn_x(_mfn) < max_page) +#undef page_to_mfn +#define page_to_mfn(_pg) (_mfn((_pg) - frame_table)) + +#define log_dirty_lock_init(_d) \ + do { \ + spin_lock_init(&(_d)->arch.paging.log_dirty.lock); \ + (_d)->arch.paging.log_dirty.locker = -1; \ + (_d)->arch.paging.log_dirty.locker_function = "nobody"; \ + } while (0) + +#define log_dirty_lock(_d) \ + do { \ + if (unlikely((_d)->arch.paging.log_dirty.locker==current->processor))\ + { \ + printk("Error: paging log dirty lock held by %s\n", \ + (_d)->arch.paging.log_dirty.locker_function); \ + BUG(); \ + } \ + spin_lock(&(_d)->arch.paging.log_dirty.lock); \ + ASSERT((_d)->arch.paging.log_dirty.locker == -1); \ + (_d)->arch.paging.log_dirty.locker = current->processor; \ + (_d)->arch.paging.log_dirty.locker_function = __func__; \ + } while (0) + +#define log_dirty_unlock(_d) \ + do { \ + ASSERT((_d)->arch.paging.log_dirty.locker == current->processor); \ + (_d)->arch.paging.log_dirty.locker = -1; \ + (_d)->arch.paging.log_dirty.locker_function = "nobody"; \ + spin_unlock(&(_d)->arch.paging.log_dirty.lock); \ + } while (0) + +/* allocate bitmap resources for log dirty */ +int paging_alloc_log_dirty_bitmap(struct domain *d) +{ + ASSERT(d->arch.paging.log_dirty.bitmap == NULL); + d->arch.paging.log_dirty.bitmap_size = + (domain_get_maximum_gpfn(d) + BITS_PER_LONG) & ~(BITS_PER_LONG - 1); + d->arch.paging.log_dirty.bitmap = + xmalloc_array(unsigned long, + d->arch.paging.log_dirty.bitmap_size / BITS_PER_LONG); + if ( d->arch.paging.log_dirty.bitmap == NULL ) + { + d->arch.paging.log_dirty.bitmap_size = 0; + return -ENOMEM; + } + memset(d->arch.paging.log_dirty.bitmap, 0, + d->arch.paging.log_dirty.bitmap_size/8); + + return 0; +} + +/* free bitmap resources */ +void paging_free_log_dirty_bitmap(struct domain *d) +{ + d->arch.paging.log_dirty.bitmap_size = 0; + if ( d->arch.paging.log_dirty.bitmap ) + { + xfree(d->arch.paging.log_dirty.bitmap); + d->arch.paging.log_dirty.bitmap = NULL; + } +} + +int paging_log_dirty_enable(struct domain *d) +{ + int ret; + + domain_pause(d); + log_dirty_lock(d); + + if ( paging_mode_log_dirty(d) ) + { + ret = -EINVAL; + goto out; + } + + ret = paging_alloc_log_dirty_bitmap(d); + if ( ret != 0 ) + { + paging_free_log_dirty_bitmap(d); + goto out; + } + + ret = d->arch.paging.log_dirty.enable_log_dirty(d); + if ( ret != 0 ) + paging_free_log_dirty_bitmap(d); + + out: + log_dirty_unlock(d); + domain_unpause(d); + return ret; +} + +int paging_log_dirty_disable(struct domain *d) +{ + int ret; + + domain_pause(d); + log_dirty_lock(d); + ret = d->arch.paging.log_dirty.disable_log_dirty(d); + if ( !paging_mode_log_dirty(d) ) + paging_free_log_dirty_bitmap(d); + log_dirty_unlock(d); + domain_unpause(d); + + return ret; +} + +/* Mark a page as dirty */ +void paging_mark_dirty(struct domain *d, unsigned long guest_mfn) +{ + unsigned long pfn; + mfn_t gmfn; + + gmfn = _mfn(guest_mfn); + + if ( !paging_mode_log_dirty(d) || !mfn_valid(gmfn) ) + return; + + log_dirty_lock(d); + + ASSERT(d->arch.paging.log_dirty.bitmap != NULL); + + /* We /really/ mean PFN here, even for non-translated guests. */ + pfn = get_gpfn_from_mfn(mfn_x(gmfn)); + + /* + * Values with the MSB set denote MFNs that aren't really part of the + * domain's pseudo-physical memory map (e.g., the shared info frame). + * Nothing to do here... + */ + if ( unlikely(!VALID_M2P(pfn)) ) + return; + + if ( likely(pfn < d->arch.paging.log_dirty.bitmap_size) ) + { + if ( !__test_and_set_bit(pfn, d->arch.paging.log_dirty.bitmap) ) + { + PAGING_DEBUG(LOGDIRTY, + "marked mfn %" PRI_mfn " (pfn=%lx), dom %d\n", + mfn_x(gmfn), pfn, d->domain_id); + d->arch.paging.log_dirty.dirty_count++; + } + } + else + { + PAGING_PRINTK("mark_dirty OOR! " + "mfn=%" PRI_mfn " pfn=%lx max=%x (dom %d)\n" + "owner=%d c=%08x t=%" PRtype_info "\n", + mfn_x(gmfn), + pfn, + d->arch.paging.log_dirty.bitmap_size, + d->domain_id, + (page_get_owner(mfn_to_page(gmfn)) + ? page_get_owner(mfn_to_page(gmfn))->domain_id + : -1), + mfn_to_page(gmfn)->count_info, + mfn_to_page(gmfn)->u.inuse.type_info); + } + + log_dirty_unlock(d); +} + +/* Read a domain's log-dirty bitmap and stats. If the operation is a CLEAN, + * clear the bitmap and stats as well. */ +int paging_log_dirty_op(struct domain *d, struct xen_domctl_shadow_op *sc) +{ + int i, rv = 0, clean = 0, peek = 1; + + domain_pause(d); + log_dirty_lock(d); + + clean = (sc->op == XEN_DOMCTL_SHADOW_OP_CLEAN); + + PAGING_DEBUG(LOGDIRTY, "log-dirty %s: dom %u faults=%u dirty=%u\n", + (clean) ? "clean" : "peek", + d->domain_id, + d->arch.paging.log_dirty.fault_count, + d->arch.paging.log_dirty.dirty_count); + + sc->stats.fault_count = d->arch.paging.log_dirty.fault_count; + sc->stats.dirty_count = d->arch.paging.log_dirty.dirty_count; + + if ( clean ) + { + d->arch.paging.log_dirty.fault_count = 0; + d->arch.paging.log_dirty.dirty_count = 0; + + d->arch.paging.log_dirty.clean_dirty_bitmap(d); + } + + if ( guest_handle_is_null(sc->dirty_bitmap) ) + /* caller may have wanted just to clean the state or access stats. */ + peek = 0; + + if ( (peek || clean) && (d->arch.paging.log_dirty.bitmap == NULL) ) + { + rv = -EINVAL; /* perhaps should be ENOMEM? */ + goto out; + } + + if ( sc->pages > d->arch.paging.log_dirty.bitmap_size ) + sc->pages = d->arch.paging.log_dirty.bitmap_size; + +#define CHUNK (8*1024) /* Transfer and clear in 1kB chunks for L1 cache. */ + for ( i = 0; i < sc->pages; i += CHUNK ) + { + int bytes = ((((sc->pages - i) > CHUNK) + ? CHUNK + : (sc->pages - i)) + 7) / 8; + + if ( likely(peek) ) + { + if ( copy_to_guest_offset( + sc->dirty_bitmap, i/8, + (uint8_t *)d->arch.paging.log_dirty.bitmap + (i/8), bytes) ) + { + rv = -EFAULT; + goto out; + } + } + + if ( clean ) + memset((uint8_t *)d->arch.paging.log_dirty.bitmap + (i/8), 0, bytes); + } +#undef CHUNK + + out: + log_dirty_unlock(d); + domain_unpause(d); + return rv; +} + + +/* Note that this function takes three function pointers. Callers must supply + * these functions for log dirty code to call. This function usually is + * invoked when paging is enabled. Check shadow_enable() and hap_enable() for + * reference. + */ +void paging_log_dirty_init(struct domain *d, + int (*enable_log_dirty)(struct domain *d), + int (*disable_log_dirty)(struct domain *d), + void (*clean_dirty_bitmap)(struct domain *d)) +{ + /* We initialize log dirty lock first */ + log_dirty_lock_init(d); + + d->arch.paging.log_dirty.enable_log_dirty = enable_log_dirty; + d->arch.paging.log_dirty.disable_log_dirty = disable_log_dirty; + d->arch.paging.log_dirty.clean_dirty_bitmap = clean_dirty_bitmap; +} + +/************************************************/ +/* CODE FOR PAGING SUPPORT */ +/************************************************/ /* Domain paging struct initialization. */ void paging_domain_init(struct domain *d) { @@ -65,11 +328,60 @@ int paging_domctl(struct domain *d, xen_ int paging_domctl(struct domain *d, xen_domctl_shadow_op_t *sc, XEN_GUEST_HANDLE(void) u_domctl) { + int rc; + + if ( unlikely(d == current->domain) ) + { + gdprintk(XENLOG_INFO, "Dom %u tried to do a shadow op on itself.\n", + d->domain_id); + return -EINVAL; + } + + if ( unlikely(d->is_dying) ) + { + gdprintk(XENLOG_INFO, "Ignoring shadow op on dying domain %u\n", + d->domain_id); + return 0; + } + + if ( unlikely(d->vcpu[0] == NULL) ) + { + PAGING_ERROR("Shadow op on a domain (%u) with no vcpus\n", + d->domain_id); + return -EINVAL; + } + + /* Code to handle log-dirty. Note that some log dirty operations + * piggy-back on shadow operations. For example, when + * XEN_DOMCTL_SHADOW_OP_OFF is called, it first checks whether log dirty + * mode is enabled. If does, we disables log dirty and continues with + * shadow code. For this reason, we need to further dispatch domctl + * to next-level paging code (shadow or hap). + */ + switch ( sc->op ) + { + case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY: + return paging_log_dirty_enable(d); + + case XEN_DOMCTL_SHADOW_OP_ENABLE: + if ( sc->mode & XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY ) + return paging_log_dirty_enable(d); + + case XEN_DOMCTL_SHADOW_OP_OFF: + if ( paging_mode_log_dirty(d) ) + if ( (rc = paging_log_dirty_disable(d)) != 0 ) + return rc; + + case XEN_DOMCTL_SHADOW_OP_CLEAN: + case XEN_DOMCTL_SHADOW_OP_PEEK: + return paging_log_dirty_op(d, sc); + } + /* Here, dispatch domctl to the appropriate paging code */ if ( opt_hap_enabled && is_hvm_domain(d) ) - return hap_domctl(d, sc, u_domctl); - else - return shadow_domctl(d, sc, u_domctl); + return hap_domctl(d, sc, u_domctl); + else + return shadow_domctl(d, sc, u_domctl); } /* Call when destroying a domain */ diff -r 45516ac94c9f xen/arch/x86/mm/shadow/common.c --- a/xen/arch/x86/mm/shadow/common.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/mm/shadow/common.c Wed Jun 06 12:58:27 2007 -0500 @@ -87,8 +87,6 @@ __initcall(shadow_audit_key_init); __initcall(shadow_audit_key_init); #endif /* SHADOW_AUDIT */ -static void sh_free_log_dirty_bitmap(struct domain *d); - int _shadow_mode_refcounts(struct domain *d) { return shadow_mode_refcounts(d); @@ -541,7 +539,7 @@ sh_validate_guest_entry(struct vcpu *v, int result = 0; struct page_info *page = mfn_to_page(gmfn); - sh_mark_dirty(v->domain, gmfn); + paging_mark_dirty(v->domain, mfn_x(gmfn)); // Determine which types of shadows are affected, and update each. // @@ -2455,6 +2453,10 @@ int shadow_enable(struct domain *d, u32 } } + /* initialize log dirty here */ + paging_log_dirty_init(d, shadow_enable_log_dirty, + shadow_disable_log_dirty, shadow_clean_dirty_bitmap); + /* Init the P2M table. Must be done before we take the shadow lock * to avoid possible deadlock. */ if ( mode & PG_translate ) @@ -2463,6 +2465,7 @@ int shadow_enable(struct domain *d, u32 if (rv != 0) goto out_unlocked; } + shadow_lock(d); @@ -2565,7 +2568,7 @@ void shadow_teardown(struct domain *d) if (d->arch.paging.shadow.hash_table) shadow_hash_teardown(d); /* Release the log-dirty bitmap of dirtied pages */ - sh_free_log_dirty_bitmap(d); + paging_free_log_dirty_bitmap(d); /* Should not have any more memory held */ SHADOW_PRINTK("teardown done." " Shadow pages total = %u, free = %u, p2m=%u\n", @@ -2718,98 +2721,6 @@ static int shadow_test_disable(struct do domain_pause(d); shadow_lock(d); ret = shadow_one_bit_disable(d, PG_SH_enable); - shadow_unlock(d); - domain_unpause(d); - - return ret; -} - -static int -sh_alloc_log_dirty_bitmap(struct domain *d) -{ - ASSERT(d->arch.paging.shadow.dirty_bitmap == NULL); - d->arch.paging.shadow.dirty_bitmap_size = - (domain_get_maximum_gpfn(d) + BITS_PER_LONG) & ~(BITS_PER_LONG - 1); - d->arch.paging.shadow.dirty_bitmap = - xmalloc_array(unsigned long, - d->arch.paging.shadow.dirty_bitmap_size / BITS_PER_LONG); - if ( d->arch.paging.shadow.dirty_bitmap == NULL ) - { - d->arch.paging.shadow.dirty_bitmap_size = 0; - return -ENOMEM; - } - memset(d->arch.paging.shadow.dirty_bitmap, 0, - d->arch.paging.shadow.dirty_bitmap_size/8); - - return 0; -} - -static void -sh_free_log_dirty_bitmap(struct domain *d) -{ - d->arch.paging.shadow.dirty_bitmap_size = 0; - if ( d->arch.paging.shadow.dirty_bitmap ) - { - xfree(d->arch.paging.shadow.dirty_bitmap); - d->arch.paging.shadow.dirty_bitmap = NULL; - } -} - -static int shadow_log_dirty_enable(struct domain *d) -{ - int ret; - - domain_pause(d); - shadow_lock(d); - - if ( shadow_mode_log_dirty(d) ) - { - ret = -EINVAL; - goto out; - } - - if ( shadow_mode_enabled(d) ) - { - /* This domain already has some shadows: need to clear them out - * of the way to make sure that all references to guest memory are - * properly write-protected */ - shadow_blow_tables(d); - } - -#if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL) - /* 32bit PV guests on 64bit xen behave like older 64bit linux: they - * change an l4e instead of cr3 to switch tables. Give them the - * same optimization */ - if ( is_pv_32on64_domain(d) ) - d->arch.paging.shadow.opt_flags = SHOPT_LINUX_L3_TOPLEVEL; -#endif - - ret = sh_alloc_log_dirty_bitmap(d); - if ( ret != 0 ) - { - sh_free_log_dirty_bitmap(d); - goto out; - } - - ret = shadow_one_bit_enable(d, PG_log_dirty); - if ( ret != 0 ) - sh_free_log_dirty_bitmap(d); - - out: - shadow_unlock(d); - domain_unpause(d); - return ret; -} - -static int shadow_log_dirty_disable(struct domain *d) -{ - int ret; - - domain_pause(d); - shadow_lock(d); - ret = shadow_one_bit_disable(d, PG_log_dirty); - if ( !shadow_mode_log_dirty(d) ) - sh_free_log_dirty_bitmap(d); shadow_unlock(d); domain_unpause(d); @@ -2892,150 +2803,62 @@ void shadow_convert_to_log_dirty(struct BUG(); } - -/* Read a domain's log-dirty bitmap and stats. - * If the operation is a CLEAN, clear the bitmap and stats as well. */ -static int shadow_log_dirty_op( - struct domain *d, struct xen_domctl_shadow_op *sc) -{ - int i, rv = 0, clean = 0, peek = 1; - - domain_pause(d); +/* Shadow specific code which is called in paging_log_dirty_enable(). + * Return 0 if no problem found. + */ +int shadow_enable_log_dirty(struct domain *d) +{ + int ret; + + /* shadow lock is required here */ shadow_lock(d); - - clean = (sc->op == XEN_DOMCTL_SHADOW_OP_CLEAN); - - SHADOW_DEBUG(LOGDIRTY, "log-dirty %s: dom %u faults=%u dirty=%u\n", - (clean) ? "clean" : "peek", - d->domain_id, - d->arch.paging.shadow.fault_count, - d->arch.paging.shadow.dirty_count); - - sc->stats.fault_count = d->arch.paging.shadow.fault_count; - sc->stats.dirty_count = d->arch.paging.shadow.dirty_count; - - if ( clean ) - { - /* Need to revoke write access to the domain's pages again. - * In future, we'll have a less heavy-handed approach to this, - * but for now, we just unshadow everything except Xen. */ + if ( shadow_mode_enabled(d) ) + { + /* This domain already has some shadows: need to clear them out + * of the way to make sure that all references to guest memory are + * properly write-protected */ shadow_blow_tables(d); - - d->arch.paging.shadow.fault_count = 0; - d->arch.paging.shadow.dirty_count = 0; - } - - if ( guest_handle_is_null(sc->dirty_bitmap) ) - /* caller may have wanted just to clean the state or access stats. */ - peek = 0; - - if ( (peek || clean) && (d->arch.paging.shadow.dirty_bitmap == NULL) ) - { - rv = -EINVAL; /* perhaps should be ENOMEM? */ - goto out; - } - - if ( sc->pages > d->arch.paging.shadow.dirty_bitmap_size ) - sc->pages = d->arch.paging.shadow.dirty_bitmap_size; - -#define CHUNK (8*1024) /* Transfer and clear in 1kB chunks for L1 cache. */ - for ( i = 0; i < sc->pages; i += CHUNK ) - { - int bytes = ((((sc->pages - i) > CHUNK) - ? CHUNK - : (sc->pages - i)) + 7) / 8; - - if ( likely(peek) ) - { - if ( copy_to_guest_offset( - sc->dirty_bitmap, i/8, - (uint8_t *)d->arch.paging.shadow.dirty_bitmap + (i/8), bytes) ) - { - rv = -EFAULT; - goto out; - } - } - - if ( clean ) - memset((uint8_t *)d->arch.paging.shadow.dirty_bitmap + (i/8), 0, bytes); - } -#undef CHUNK - - out: + } + +#if (SHADOW_OPTIMIZATIONS & SHOPT_LINUX_L3_TOPLEVEL) + /* 32bit PV guests on 64bit xen behave like older 64bit linux: they + * change an l4e instead of cr3 to switch tables. Give them the + * same optimization */ + if ( is_pv_32on64_domain(d) ) + d->arch.paging.shadow.opt_flags = SHOPT_LINUX_L3_TOPLEVEL; +#endif + + ret = shadow_one_bit_enable(d, PG_log_dirty); shadow_unlock(d); - domain_unpause(d); - return rv; -} - - -/* Mark a page as dirty */ -void sh_mark_dirty(struct domain *d, mfn_t gmfn) -{ - unsigned long pfn; - int do_locking; - - if ( !shadow_mode_log_dirty(d) || !mfn_valid(gmfn) ) - return; - - /* Although this is an externally visible function, we do not know - * whether the shadow lock will be held when it is called (since it - * can be called from __hvm_copy during emulation). - * If the lock isn't held, take it for the duration of the call. */ - do_locking = !shadow_locked_by_me(d); - if ( do_locking ) - { - shadow_lock(d); - /* Check the mode again with the lock held */ - if ( unlikely(!shadow_mode_log_dirty(d)) ) - { - shadow_unlock(d); - return; - } - } - - ASSERT(d->arch.paging.shadow.dirty_bitmap != NULL); - - /* We /really/ mean PFN here, even for non-translated guests. */ - pfn = get_gpfn_from_mfn(mfn_x(gmfn)); - - /* - * Values with the MSB set denote MFNs that aren't really part of the - * domain's pseudo-physical memory map (e.g., the shared info frame). - * Nothing to do here... - */ - if ( unlikely(!VALID_M2P(pfn)) ) - return; - - /* N.B. Can use non-atomic TAS because protected by shadow_lock. */ - if ( likely(pfn < d->arch.paging.shadow.dirty_bitmap_size) ) - { - if ( !__test_and_set_bit(pfn, d->arch.paging.shadow.dirty_bitmap) ) - { - SHADOW_DEBUG(LOGDIRTY, - "marked mfn %" PRI_mfn " (pfn=%lx), dom %d\n", - mfn_x(gmfn), pfn, d->domain_id); - d->arch.paging.shadow.dirty_count++; - } - } - else - { - SHADOW_PRINTK("mark_dirty OOR! " - "mfn=%" PRI_mfn " pfn=%lx max=%x (dom %d)\n" - "owner=%d c=%08x t=%" PRtype_info "\n", - mfn_x(gmfn), - pfn, - d->arch.paging.shadow.dirty_bitmap_size, - d->domain_id, - (page_get_owner(mfn_to_page(gmfn)) - ? page_get_owner(mfn_to_page(gmfn))->domain_id - : -1), - mfn_to_page(gmfn)->count_info, - mfn_to_page(gmfn)->u.inuse.type_info); - } - - if ( do_locking ) shadow_unlock(d); -} - + + return ret; +} + +/* shadow specfic code which is called in paging_log_dirty_disable() */ +int shadow_disable_log_dirty(struct domain *d) +{ + int ret; + + /* shadow lock is required here */ + shadow_lock(d); + ret = shadow_one_bit_disable(d, PG_log_dirty); + shadow_unlock(d); + + return ret; +} + +/* This function is called when we CLEAN log dirty bitmap. See + * paging_log_dirty_op() for details. + */ +void shadow_clean_dirty_bitmap(struct domain *d) +{ + shadow_lock(d); + /* Need to revoke write access to the domain's pages again. + * In future, we'll have a less heavy-handed approach to this, + * but for now, we just unshadow everything except Xen. */ + shadow_blow_tables(d); + shadow_unlock(d); +} /**************************************************************************/ /* Shadow-control XEN_DOMCTL dispatcher */ @@ -3045,33 +2868,9 @@ int shadow_domctl(struct domain *d, { int rc, preempted = 0; - if ( unlikely(d == current->domain) ) - { - gdprintk(XENLOG_INFO, "Dom %u tried to do a shadow op on itself.\n", - d->domain_id); - return -EINVAL; - } - - if ( unlikely(d->is_dying) ) - { - gdprintk(XENLOG_INFO, "Ignoring shadow op on dying domain %u\n", - d->domain_id); - return 0; - } - - if ( unlikely(d->vcpu[0] == NULL) ) - { - SHADOW_ERROR("Shadow op on a domain (%u) with no vcpus\n", - d->domain_id); - return -EINVAL; - } - switch ( sc->op ) { case XEN_DOMCTL_SHADOW_OP_OFF: - if ( shadow_mode_log_dirty(d) ) - if ( (rc = shadow_log_dirty_disable(d)) != 0 ) - return rc; if ( d->arch.paging.mode == PG_SH_enable ) if ( (rc = shadow_test_disable(d)) != 0 ) return rc; @@ -3080,19 +2879,10 @@ int shadow_domctl(struct domain *d, case XEN_DOMCTL_SHADOW_OP_ENABLE_TEST: return shadow_test_enable(d); - case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY: - return shadow_log_dirty_enable(d); - case XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE: return shadow_enable(d, PG_refcounts|PG_translate); - case XEN_DOMCTL_SHADOW_OP_CLEAN: - case XEN_DOMCTL_SHADOW_OP_PEEK: - return shadow_log_dirty_op(d, sc); - case XEN_DOMCTL_SHADOW_OP_ENABLE: - if ( sc->mode & XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY ) - return shadow_log_dirty_enable(d); return shadow_enable(d, sc->mode << PG_mode_shift); case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION: diff -r 45516ac94c9f xen/arch/x86/mm/shadow/multi.c --- a/xen/arch/x86/mm/shadow/multi.c Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/mm/shadow/multi.c Wed Jun 06 12:08:38 2007 -0500 @@ -457,7 +457,7 @@ static u32 guest_set_ad_bits(struct vcpu } /* Set the bit(s) */ - sh_mark_dirty(v->domain, gmfn); + paging_mark_dirty(v->domain, mfn_x(gmfn)); SHADOW_DEBUG(A_AND_D, "gfn = %" SH_PRI_gfn ", " "old flags = %#x, new flags = %#x\n", gfn_x(guest_l1e_get_gfn(*ep)), guest_l1e_get_flags(*ep), @@ -717,7 +717,7 @@ _sh_propagate(struct vcpu *v, if ( unlikely((level == 1) && shadow_mode_log_dirty(d)) ) { if ( ft & FETCH_TYPE_WRITE ) - sh_mark_dirty(d, target_mfn); + paging_mark_dirty(d, mfn_x(target_mfn)); else if ( !sh_mfn_is_dirty(d, target_mfn) ) sflags &= ~_PAGE_RW; } @@ -2856,7 +2856,7 @@ static int sh_page_fault(struct vcpu *v, } perfc_incr(shadow_fault_fixed); - d->arch.paging.shadow.fault_count++; + d->arch.paging.log_dirty.fault_count++; reset_early_unshadow(v); done: @@ -4058,7 +4058,7 @@ sh_x86_emulate_write(struct vcpu *v, uns else reset_early_unshadow(v); - sh_mark_dirty(v->domain, mfn); + paging_mark_dirty(v->domain, mfn_x(mfn)); sh_unmap_domain_page(addr); shadow_audit_tables(v); @@ -4114,7 +4114,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u else reset_early_unshadow(v); - sh_mark_dirty(v->domain, mfn); + paging_mark_dirty(v->domain, mfn_x(mfn)); sh_unmap_domain_page(addr); shadow_audit_tables(v); @@ -4158,7 +4158,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, else reset_early_unshadow(v); - sh_mark_dirty(v->domain, mfn); + paging_mark_dirty(v->domain, mfn_x(mfn)); sh_unmap_domain_page(addr); shadow_audit_tables(v); diff -r 45516ac94c9f xen/arch/x86/mm/shadow/private.h --- a/xen/arch/x86/mm/shadow/private.h Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/arch/x86/mm/shadow/private.h Wed Jun 06 09:12:08 2007 -0500 @@ -496,13 +496,13 @@ sh_mfn_is_dirty(struct domain *d, mfn_t { unsigned long pfn; ASSERT(shadow_mode_log_dirty(d)); - ASSERT(d->arch.paging.shadow.dirty_bitmap != NULL); + ASSERT(d->arch.paging.log_dirty.bitmap != NULL); /* We /really/ mean PFN here, even for non-translated guests. */ pfn = get_gpfn_from_mfn(mfn_x(gmfn)); if ( likely(VALID_M2P(pfn)) - && likely(pfn < d->arch.paging.shadow.dirty_bitmap_size) - && test_bit(pfn, d->arch.paging.shadow.dirty_bitmap) ) + && likely(pfn < d->arch.paging.log_dirty.bitmap_size) + && test_bit(pfn, d->arch.paging.log_dirty.bitmap) ) return 1; return 0; diff -r 45516ac94c9f xen/include/asm-x86/domain.h --- a/xen/include/asm-x86/domain.h Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/include/asm-x86/domain.h Wed Jun 06 12:34:24 2007 -0500 @@ -92,14 +92,6 @@ struct shadow_domain { /* Fast MMIO path heuristic */ int has_fast_mmio_entries; - - /* Shadow log-dirty bitmap */ - unsigned long *dirty_bitmap; - unsigned int dirty_bitmap_size; /* in pages, bit per page */ - - /* Shadow log-dirty mode stats */ - unsigned int fault_count; - unsigned int dirty_count; }; struct shadow_vcpu { @@ -134,7 +126,6 @@ struct hap_domain { /************************************************/ /* p2m handling */ /************************************************/ - struct p2m_domain { /* Lock that protects updates to the p2m */ spinlock_t lock; @@ -156,16 +147,36 @@ struct p2m_domain { /************************************************/ /* common paging data structure */ /************************************************/ +struct log_dirty_domain { + /* log-dirty lock */ + spinlock_t lock; + int locker; /* processor that holds the lock */ + const char *locker_function; /* func that took it */ + + /* log-dirty bitmap to record dirty pages */ + unsigned long *bitmap; + unsigned int bitmap_size; /* in pages, bit per page */ + + /* log-dirty mode stats */ + unsigned int fault_count; + unsigned int dirty_count; + + /* functions which are paging mode specific */ + int (*enable_log_dirty )(struct domain *d); + int (*disable_log_dirty )(struct domain *d); + void (*clean_dirty_bitmap )(struct domain *d); +}; + struct paging_domain { - u32 mode; /* flags to control paging operation */ - + /* flags to control paging operation */ + u32 mode; /* extension for shadow paging support */ - struct shadow_domain shadow; - - /* Other paging assistance code will have structs here */ - struct hap_domain hap; -}; - + struct shadow_domain shadow; + /* extension for hardware-assited paging */ + struct hap_domain hap; + /* log dirty support */ + struct log_dirty_domain log_dirty; +}; struct paging_vcpu { /* Pointers to mode-specific entry points. */ struct paging_mode *mode; diff -r 45516ac94c9f xen/include/asm-x86/grant_table.h --- a/xen/include/asm-x86/grant_table.h Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/include/asm-x86/grant_table.h Wed Jun 06 12:03:21 2007 -0500 @@ -31,7 +31,7 @@ int replace_grant_host_mapping( #define gnttab_shared_gmfn(d, t, i) \ (mfn_to_gmfn(d, gnttab_shared_mfn(d, t, i))) -#define gnttab_mark_dirty(d, f) mark_dirty((d), (f)) +#define gnttab_mark_dirty(d, f) paging_mark_dirty((d), (f)) static inline void gnttab_clear_flag(unsigned long nr, uint16_t *addr) { diff -r 45516ac94c9f xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/include/asm-x86/p2m.h Thu Jun 07 05:37:12 2007 -0500 @@ -129,6 +129,11 @@ void guest_physmap_remove_page(struct do void guest_physmap_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn); +/* set P2M table l1e flags */ +void p2m_set_flags_global(struct domain *d, u32 l1e_flags); + +/* set P2M table l1e flags for a gpa */ +int p2m_set_flags(struct domain *d, paddr_t gpa, u32 l1e_flags); #endif /* _XEN_P2M_H */ diff -r 45516ac94c9f xen/include/asm-x86/paging.h --- a/xen/include/asm-x86/paging.h Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/include/asm-x86/paging.h Wed Jun 06 12:36:54 2007 -0500 @@ -62,6 +62,9 @@ #define paging_mode_log_dirty(_d) ((_d)->arch.paging.mode & PG_log_dirty) #define paging_mode_translate(_d) ((_d)->arch.paging.mode & PG_translate) #define paging_mode_external(_d) ((_d)->arch.paging.mode & PG_external) + +/* flags used for paging debug */ +#define PAGING_DEBUG_LOGDIRTY 0 /****************************************************************************** * The equivalent for a particular vcpu of a shadowed domain. */ @@ -136,6 +139,29 @@ struct paging_mode { struct shadow_paging_mode shadow; }; +/***************************************************************************** + * Log dirty code */ + +/* allocate log dirty bitmap resource for recording dirty pages */ +int paging_alloc_log_dirty_bitmap(struct domain *d); + +/* free log dirty bitmap resource */ +void paging_free_log_dirty_bitmap(struct domain *d); + +/* enable log dirty */ +int paging_log_dirty_enable(struct domain *d); + +/* disable log dirty */ +int paging_log_dirty_disable(struct domain *d); + +/* log dirty initialization */ +void paging_log_dirty_init(struct domain *d, + int (*enable_log_dirty)(struct domain *d), + int (*disable_log_dirty)(struct domain *d), + void (*clean_dirty_bitmap)(struct domain *d)); + +/* mark a page as dirty */ +void paging_mark_dirty(struct domain *d, unsigned long guest_mfn); /***************************************************************************** * Entry points into the paging-assistance code */ diff -r 45516ac94c9f xen/include/asm-x86/shadow.h --- a/xen/include/asm-x86/shadow.h Wed Jun 06 08:32:32 2007 -0500 +++ b/xen/include/asm-x86/shadow.h Wed Jun 06 12:37:52 2007 -0500 @@ -75,16 +75,14 @@ void shadow_teardown(struct domain *d); /* Call once all of the references to the domain have gone away */ void shadow_final_teardown(struct domain *d); -/* Mark a page as dirty in the log-dirty bitmap: called when Xen - * makes changes to guest memory on its behalf. */ -void sh_mark_dirty(struct domain *d, mfn_t gmfn); -/* Cleaner version so we don't pepper shadow_mode tests all over the place */ -static inline void mark_dirty(struct domain *d, unsigned long gmfn) -{ - if ( unlikely(shadow_mode_log_dirty(d)) ) - /* See the comment about locking in sh_mark_dirty */ - sh_mark_dirty(d, _mfn(gmfn)); -} +/* shadow code to call when log dirty is enabled */ +int shadow_enable_log_dirty(struct domain *d); + +/* shadow code to call when log dirty is disabled */ +int shadow_disable_log_dirty(struct domain *d); + +/* shadow code to call when bitmap is being cleaned */ +void shadow_clean_dirty_bitmap(struct domain *d); /* Update all the things that are derived from the guest's CR0/CR3/CR4. * Called to initialize paging structures if the paging mode