[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC v2 8/9] xen/arm: Implement hypercall for dirty page tracing (shadow op)
From: Elena Pyatunina <e.pyatunina@xxxxxxxxxxx> Add hypercall (shadow op: enable/disable and clean/peek dirted page bitmap) Signed-off-by: Elena Pyatunina <e.pyatunina@xxxxxxxxxxx> Singed-off-by: Alexey Sokolov <sokolov.a@xxxxxxxxxxx> --- xen/arch/arm/domain.c | 4 + xen/arch/arm/domctl.c | 19 ++++ xen/arch/arm/p2m.c | 219 +++++++++++++++++++++++++++++++++++++++++++++- xen/include/asm-arm/p2m.h | 2 + 4 files changed, 242 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 73dd0de..e3fc533 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -484,6 +484,10 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags) d->arch.vpidr = boot_cpu_data.midr.bits; d->arch.vmpidr = boot_cpu_data.mpidr.bits; + /* init for dirty-page tracing */ + d->arch.dirty.count = 0; + d->arch.dirty.top = NULL; + clear_page(d->shared_info); share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c index a0719b0..bc06534 100644 --- a/xen/arch/arm/domctl.c +++ b/xen/arch/arm/domctl.c @@ -67,6 +67,14 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, goto gethvmcontext_out; } + /* Allocate our own marshalling buffer */ + ret = -ENOMEM; + if ( (c.data = xmalloc_bytes(c.size)) == NULL ) + { + printk("(gethvmcontext) xmalloc_bytes failed: %d\n", c.size ); + goto gethvmcontext_out; + } + domain_pause(d); ret = hvm_save(d, &c); domain_unpause(d); @@ -85,6 +93,17 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, xfree(c.data); } break; + case XEN_DOMCTL_shadow_op: + { + ret = dirty_mode_op(d, &domctl->u.shadow_op); + if ( (&domctl->u.shadow_op)->op == XEN_DOMCTL_SHADOW_OP_CLEAN + || (&domctl->u.shadow_op)->op == XEN_DOMCTL_SHADOW_OP_PEEK) + { + copyback = 1; + } + } + break; + default: return -EINVAL; } diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index bae7af7..fb8ce10 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -69,8 +69,8 @@ out: spin_unlock(&p2m->lock); - return ( ((xen_pfn_t)first_index << FIRST_SHIFT) | - (second_index << SECOND_SHIFT) | + return ( ((xen_pfn_t)first_index << FIRST_SHIFT) | + (second_index << SECOND_SHIFT) | (third_index << THIRD_SHIFT) ) >> PAGE_SHIFT; } @@ -496,6 +496,221 @@ void mark_dirty(struct domain *d, paddr_t addr) spin_unlock(&d->arch.dirty.lock); } +static void free_dirty_bitmap(struct domain *d) +{ + struct page_info *pg; + + spin_lock(&d->arch.dirty.lock); + + if(d->arch.dirty.top) + { + while ( (pg = page_list_remove_head(&d->arch.dirty.pages)) ) + free_domheap_page(pg); + } + d->arch.dirty.top = NULL; + d->arch.dirty.count = 0; + + spin_unlock(&d->arch.dirty.lock); +} + +/* Change types across all p2m entries in a domain */ +static void p2m_change_entry_type_global(struct domain *d, enum mg ot, enum mg nt) +{ + struct p2m_domain *p2m = &d->arch.p2m; + int i1, i2, i3; + int first_index = first_table_offset(GUEST_RAM_BASE); + int second_index = second_table_offset(GUEST_RAM_BASE); + int third_index = third_table_offset(GUEST_RAM_BASE); + + lpae_t *first = __map_domain_page(p2m->first_level); + lpae_t pte, *second = NULL, *third = NULL; + + BUG_ON(!first && "Can't map first level p2m."); + + spin_lock(&p2m->lock); + + for (i1 = first_index; i1 < LPAE_ENTRIES*2; ++i1) + { + lpae_walk_t first_pte = first[i1].walk; + if (!first_pte.valid || !first_pte.table) + goto out; + + second = map_domain_page(first_pte.base); + BUG_ON(!second && "Can't map second level p2m."); + for(i2 = second_index; i2 < LPAE_ENTRIES; ++i2) + { + lpae_walk_t second_pte = second[i2].walk; + if (!second_pte.valid || !second_pte.table) + goto out; + + third = map_domain_page(second_pte.base); + BUG_ON(!third && "Can't map third level p2m."); + + for (i3 = third_index; i3 < LPAE_ENTRIES; ++i3) + { + lpae_walk_t third_pte = third[i3].walk; + int write = 0; + if (!third_pte.valid) + goto out; + + pte = third[i3]; + if (pte.p2m.write == 1 && nt == mg_ro) + { + pte.p2m.write = 0; + write = 1; + } + else if (pte.p2m.write == 0 && nt == mg_rw) + { + pte.p2m.write = 1; + write = 1; + } + if (write) + write_pte(&third[i3], pte); + } + unmap_domain_page(third); + + third = NULL; + third_index = 0; + } + unmap_domain_page(second); + + second = NULL; + second_index = 0; + third_index = 0; + } + +out: + flush_tlb_all_local(); + if (third) unmap_domain_page(third); + if (second) unmap_domain_page(second); + if (first) unmap_domain_page(first); + + spin_unlock(&p2m->lock); +} + +/* Read a domain's log-dirty bitmap and stats. + * If the operation is a CLEAN, clear the bitmap and stats. */ +static int log_dirty_op(struct domain *d, xen_domctl_shadow_op_t *sc) +{ + int i1, i2, rv = 0, clean = 0, peek = 1; + xen_pfn_t *first = NULL, *second = NULL; + unsigned long pages = 0, *third = NULL; + + clean = (sc->op == XEN_DOMCTL_SHADOW_OP_CLEAN); + + if (guest_handle_is_null(sc->dirty_bitmap)) + peek = 0; + + domain_pause(d); + + printk("DEBUG: log-dirty %s: dom %u dirty=%u\n", + (clean) ? "clean" : "peek", + d->domain_id, d->arch.dirty.count); + + sc->stats.dirty_count = d->arch.dirty.count; + + spin_lock(&d->arch.dirty.lock); + first = d->arch.dirty.top ? __map_domain_page(d->arch.dirty.top) : NULL; + + /* 32-bit address space starts from 0 and ends at ffffffff. + * First level of p2m tables is indexed by bits 39-30. + * So significant bits for 32-bit addresses in first table are 31-30. + * So we need to iterate from 0 to 4. + * But RAM starts from 2 gigabytes. So start from 2 instead. + * TODO remove this hardcode + */ + for (i1 = 2; (pages < sc->pages) && (i1 < 4); ++i1) + { + second = (first && first[i1]) ? map_domain_page(first[i1]) : NULL; + + for (i2 = 0; (i2 < LPAE_ENTRIES); ++i2) + { + unsigned int bytes = LPAE_ENTRIES/8; + third = (second && second[i2]) ? map_domain_page(second[i2]) : NULL; + if ( unlikely(((sc->pages - pages + 7) >> 3) < bytes) ) + bytes = (unsigned int)((sc->pages - pages + 7) >> 3); + if (peek) + { + if ( (third ? copy_to_guest_offset(sc->dirty_bitmap, pages >> 3, + (uint8_t *)third, bytes) + : clear_guest_offset(sc->dirty_bitmap, pages >> 3, + (uint8_t*)NULL /*only type matters*/, + bytes)) != 0 ) + { + rv = 1; + goto out; + } + } + pages += bytes << 3; + if (third) + { + if (clean) clear_page(third); + unmap_domain_page(third); + } + } + if (second) unmap_domain_page(second); + } + if (first) unmap_domain_page(first); + + spin_unlock(&d->arch.dirty.lock); + + if ( pages < sc->pages ) + sc->pages = pages; + + if (clean) + { + p2m_change_entry_type_global(d, mg_rw, mg_ro); + free_dirty_bitmap(d); + } + +out: + if (rv) + { + spin_unlock(&d->arch.dirty.lock); + } + domain_unpause(d); + return rv; +} + +long dirty_mode_op(struct domain *d, xen_domctl_shadow_op_t *sc) +{ + long ret = 0; + + switch (sc->op) + { + case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY: + case XEN_DOMCTL_SHADOW_OP_OFF: + { + enum mg ot = mg_clear, nt = mg_clear; + + ot = sc->op == XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY ? mg_rw : mg_ro; + nt = sc->op == XEN_DOMCTL_SHADOW_OP_OFF ? mg_rw : mg_ro; + + domain_pause(d); + + d->arch.dirty.mode = sc->op == XEN_DOMCTL_SHADOW_OP_OFF ? 0 : 1; + p2m_change_entry_type_global(d, ot, nt); + + if (sc->op == XEN_DOMCTL_SHADOW_OP_OFF) + free_dirty_bitmap(d); + + domain_unpause(d); + } + break; + + case XEN_DOMCTL_SHADOW_OP_CLEAN: + case XEN_DOMCTL_SHADOW_OP_PEEK: + { + ret = log_dirty_op(d, sc); + } + break; + + default: + return -ENOSYS; + } + return ret; +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h index fd5890f..498cf0b 100644 --- a/xen/include/asm-arm/p2m.h +++ b/xen/include/asm-arm/p2m.h @@ -2,6 +2,7 @@ #define _XEN_P2M_H #include <xen/mm.h> +#include <public/domctl.h> struct domain; @@ -112,6 +113,7 @@ static inline int get_page_and_type(struct page_info *page, enum mg { mg_clear, mg_ro, mg_rw, mg_rx }; void mark_dirty(struct domain *d, paddr_t addr); +long dirty_mode_op(struct domain *d, xen_domctl_shadow_op_t *sc); #endif /* _XEN_P2M_H */ -- 1.8.1.2 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |