📄 paging.c
字号:
d->arch.paging.log_dirty.dirty_count++; } out: 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 rv = 0, clean = 0, peek = 1; unsigned long pages = 0; mfn_t *l4, *l3, *l2; unsigned long *l1; int i4, i3, i2; 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; } 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) && !mfn_valid(d->arch.paging.log_dirty.top) ) { rv = -EINVAL; /* perhaps should be ENOMEM? */ goto out; } if ( unlikely(d->arch.paging.log_dirty.failed_allocs) ) { printk("%s: %d failed page allocs while logging dirty pages\n", __FUNCTION__, d->arch.paging.log_dirty.failed_allocs); rv = -ENOMEM; goto out; } pages = 0; l4 = map_domain_page(mfn_x(d->arch.paging.log_dirty.top)); for ( i4 = 0; (pages < sc->pages) && (i4 < LOGDIRTY_NODE_ENTRIES); i4++ ) { l3 = mfn_valid(l4[i4]) ? map_domain_page(mfn_x(l4[i4])) : NULL; for ( i3 = 0; (pages < sc->pages) && (i3 < LOGDIRTY_NODE_ENTRIES); i3++ ) { l2 = ((l3 && mfn_valid(l3[i3])) ? map_domain_page(mfn_x(l3[i3])) : NULL); for ( i2 = 0; (pages < sc->pages) && (i2 < LOGDIRTY_NODE_ENTRIES); i2++ ) { static unsigned long zeroes[PAGE_SIZE/BYTES_PER_LONG]; unsigned int bytes = PAGE_SIZE; l1 = ((l2 && mfn_valid(l2[i2])) ? map_domain_page(mfn_x(l2[i2])) : zeroes); if ( unlikely(((sc->pages - pages + 7) >> 3) < bytes) ) bytes = (unsigned int)((sc->pages - pages + 7) >> 3); if ( likely(peek) ) { if ( copy_to_guest_offset(sc->dirty_bitmap, pages >> 3, (uint8_t *)l1, bytes) != 0 ) { rv = -EFAULT; goto out; } } if ( clean && l1 != zeroes ) clear_page(l1); pages += bytes << 3; if ( l1 != zeroes ) unmap_domain_page(l1); } if ( l2 ) unmap_domain_page(l2); } if ( l3 ) unmap_domain_page(l3); } unmap_domain_page(l4); if ( pages < sc->pages ) sc->pages = pages; log_dirty_unlock(d); if ( clean ) { /* We need to further call clean_dirty_bitmap() functions of specific * paging modes (shadow or hap). Safe because the domain is paused. */ d->arch.paging.log_dirty.clean_dirty_bitmap(d); } domain_unpause(d); return rv; 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. * * These function pointers must not be followed with the log-dirty lock held. */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; d->arch.paging.log_dirty.top = _mfn(INVALID_MFN);}/* This function fress log dirty bitmap resources. */void paging_log_dirty_teardown(struct domain*d){ log_dirty_lock(d); paging_free_log_dirty_bitmap(d); log_dirty_unlock(d);}/************************************************//* CODE FOR PAGING SUPPORT *//************************************************//* Domain paging struct initialization. */int paging_domain_init(struct domain *d){ int rc; if ( (rc = p2m_init(d)) != 0 ) return rc; /* The order of the *_init calls below is important, as the later * ones may rewrite some common fields. Shadow pagetables are the * default... */ shadow_domain_init(d); /* ... but we will use hardware assistance if it's available. */ if ( hap_enabled(d) ) hap_domain_init(d); return 0;}/* vcpu paging struct initialization goes here */void paging_vcpu_init(struct vcpu *v){ if ( hap_enabled(v->domain) ) hap_vcpu_init(v); else shadow_vcpu_init(v);}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, "Tried to do a paging op on itself.\n"); return -EINVAL; } if ( unlikely(d->is_dying) ) { gdprintk(XENLOG_INFO, "Ignoring paging op on dying domain %u\n", d->domain_id); return 0; } if ( unlikely(d->vcpu[0] == NULL) ) { PAGING_ERROR("Paging op on a domain (%u) with no vcpus\n", d->domain_id); return -EINVAL; } rc = xsm_shadow_control(d, sc->op); if ( rc ) return rc; /* 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 ( hap_enabled(d) ) return hap_domctl(d, sc, u_domctl); else return shadow_domctl(d, sc, u_domctl);}/* Call when destroying a domain */void paging_teardown(struct domain *d){ if ( hap_enabled(d) ) hap_teardown(d); else shadow_teardown(d); /* clean up log dirty resources. */ paging_log_dirty_teardown(d);}/* Call once all of the references to the domain have gone away */void paging_final_teardown(struct domain *d){ if ( hap_enabled(d) ) hap_final_teardown(d); else shadow_final_teardown(d); p2m_final_teardown(d);}/* Enable an arbitrary paging-assistance mode. Call once at domain * creation. */int paging_enable(struct domain *d, u32 mode){ if ( hap_enabled(d) ) return hap_enable(d, mode | PG_HAP_enable); else return shadow_enable(d, mode | PG_SH_enable);}/* Print paging-assistance info to the console */void paging_dump_domain_info(struct domain *d){ if ( paging_mode_enabled(d) ) { printk(" paging assistance: "); if ( paging_mode_shadow(d) ) printk("shadow "); if ( paging_mode_hap(d) ) printk("hap "); if ( paging_mode_refcounts(d) ) printk("refcounts "); if ( paging_mode_log_dirty(d) ) printk("log_dirty "); if ( paging_mode_translate(d) ) printk("translate "); if ( paging_mode_external(d) ) printk("external "); printk("\n"); }}void paging_dump_vcpu_info(struct vcpu *v){ if ( paging_mode_enabled(v->domain) ) { printk(" paging assistance: "); if ( paging_mode_shadow(v->domain) ) { if ( v->arch.paging.mode ) printk("shadowed %u-on-%u\n", v->arch.paging.mode->guest_levels, v->arch.paging.mode->shadow.shadow_levels); else printk("not shadowed\n"); } else if ( paging_mode_hap(v->domain) && v->arch.paging.mode ) printk("hap, %u levels\n", v->arch.paging.mode->guest_levels); else printk("none\n"); }}/* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * indent-tabs-mode: nil * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -