mm.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 2,038 行 · 第 1/5 页

C
2,038
字号
 fail:    MEM_LOG("Failure in alloc_l3_table: entry %d", i);    while ( i-- > 0 )    {        if ( !is_guest_l3_slot(i) )            continue;        unadjust_guest_l3e(pl3e[i], d);        put_page_from_l3e(pl3e[i], pfn);    }    unmap_domain_page(pl3e);    return 0;}#else#define alloc_l3_table(page) (0)#endif#if CONFIG_PAGING_LEVELS >= 4static int alloc_l4_table(struct page_info *page){    struct domain *d = page_get_owner(page);    unsigned long  pfn = page_to_mfn(page);    l4_pgentry_t  *pl4e = page_to_virt(page);    int            i;    for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )    {        if ( !is_guest_l4_slot(d, i) )            continue;        if ( unlikely(!get_page_from_l4e(pl4e[i], pfn, d)) )            goto fail;        adjust_guest_l4e(pl4e[i], d);    }    /* Xen private mappings. */    memcpy(&pl4e[ROOT_PAGETABLE_FIRST_XEN_SLOT],           &idle_pg_table[ROOT_PAGETABLE_FIRST_XEN_SLOT],           ROOT_PAGETABLE_XEN_SLOTS * sizeof(l4_pgentry_t));    pl4e[l4_table_offset(LINEAR_PT_VIRT_START)] =        l4e_from_pfn(pfn, __PAGE_HYPERVISOR);    pl4e[l4_table_offset(PERDOMAIN_VIRT_START)] =        l4e_from_page(virt_to_page(d->arch.mm_perdomain_l3),                      __PAGE_HYPERVISOR);    return 1; fail:    MEM_LOG("Failure in alloc_l4_table: entry %d", i);    while ( i-- > 0 )        if ( is_guest_l4_slot(d, i) )            put_page_from_l4e(pl4e[i], pfn);    return 0;}#else#define alloc_l4_table(page) (0)#endifstatic void free_l1_table(struct page_info *page){    struct domain *d = page_get_owner(page);    unsigned long pfn = page_to_mfn(page);    l1_pgentry_t *pl1e;    int i;    pl1e = map_domain_page(pfn);    for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )        if ( is_guest_l1_slot(i) )            put_page_from_l1e(pl1e[i], d);    unmap_domain_page(pl1e);}static void free_l2_table(struct page_info *page){#ifdef CONFIG_COMPAT    struct domain *d = page_get_owner(page);#endif    unsigned long pfn = page_to_mfn(page);    l2_pgentry_t *pl2e;    int i;    pl2e = map_domain_page(pfn);    for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )        if ( is_guest_l2_slot(d, page->u.inuse.type_info, i) )            put_page_from_l2e(pl2e[i], pfn);    unmap_domain_page(pl2e);    page->u.inuse.type_info &= ~PGT_pae_xen_l2;}#if CONFIG_PAGING_LEVELS >= 3static void free_l3_table(struct page_info *page){    struct domain *d = page_get_owner(page);    unsigned long pfn = page_to_mfn(page);    l3_pgentry_t *pl3e;    int           i;#ifdef DOMAIN_DESTRUCT_AVOID_RECURSION    if ( d->arch.relmem == RELMEM_l3 )        return;#endif    pl3e = map_domain_page(pfn);    for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )        if ( is_guest_l3_slot(i) )        {            put_page_from_l3e(pl3e[i], pfn);            unadjust_guest_l3e(pl3e[i], d);        }    unmap_domain_page(pl3e);}#endif#if CONFIG_PAGING_LEVELS >= 4static void free_l4_table(struct page_info *page){    struct domain *d = page_get_owner(page);    unsigned long pfn = page_to_mfn(page);    l4_pgentry_t *pl4e = page_to_virt(page);    int           i;#ifdef DOMAIN_DESTRUCT_AVOID_RECURSION    if ( d->arch.relmem == RELMEM_l4 )        return;#endif    for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )        if ( is_guest_l4_slot(d, i) )            put_page_from_l4e(pl4e[i], pfn);}#endifstatic void page_lock(struct page_info *page){#if defined(__i386__)    while ( unlikely(test_and_set_bit(_PGC_locked, &page->count_info)) )        while ( test_bit(_PGC_locked, &page->count_info) )            cpu_relax();#else    spin_lock(&page->lock);#endif}static void page_unlock(struct page_info *page){#if defined(__i386__)    clear_bit(_PGC_locked, &page->count_info);#else    spin_unlock(&page->lock);#endif}/* How to write an entry to the guest pagetables. * Returns 0 for failure (pointer not valid), 1 for success. */static inline int update_intpte(intpte_t *p,                                 intpte_t old,                                 intpte_t new,                                unsigned long mfn,                                struct vcpu *v,                                int preserve_ad){    int rv = 1;#ifndef PTE_UPDATE_WITH_CMPXCHG    if ( !preserve_ad )    {        rv = paging_write_guest_entry(v, p, new, _mfn(mfn));    }    else#endif    {        intpte_t t = old;        for ( ; ; )        {            intpte_t _new = new;            if ( preserve_ad )                _new |= old & (_PAGE_ACCESSED | _PAGE_DIRTY);            rv = paging_cmpxchg_guest_entry(v, p, &t, _new, _mfn(mfn));            if ( unlikely(rv == 0) )            {                MEM_LOG("Failed to update %" PRIpte " -> %" PRIpte                        ": saw %" PRIpte, old, _new, t);                break;            }            if ( t == old )                break;            /* Allowed to change in Accessed/Dirty flags only. */            BUG_ON((t ^ old) & ~(intpte_t)(_PAGE_ACCESSED|_PAGE_DIRTY));            old = t;        }    }    return rv;}/* Macro that wraps the appropriate type-changes around update_intpte(). * Arguments are: type, ptr, old, new, mfn, vcpu */#define UPDATE_ENTRY(_t,_p,_o,_n,_m,_v,_ad)                         \    update_intpte(&_t ## e_get_intpte(*(_p)),                       \                  _t ## e_get_intpte(_o), _t ## e_get_intpte(_n),   \                  (_m), (_v), (_ad))/* Update the L1 entry at pl1e to new value nl1e. */static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e,                         unsigned long gl1mfn, int preserve_ad){    l1_pgentry_t ol1e;    struct vcpu *curr = current;    struct domain *d = curr->domain;    unsigned long mfn;    struct page_info *l1pg = mfn_to_page(gl1mfn);    int rc = 1;    page_lock(l1pg);    if ( unlikely(__copy_from_user(&ol1e, pl1e, sizeof(ol1e)) != 0) )        return page_unlock(l1pg), 0;    if ( unlikely(paging_mode_refcounts(d)) )    {        rc = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr, preserve_ad);        page_unlock(l1pg);        return rc;    }    if ( l1e_get_flags(nl1e) & _PAGE_PRESENT )    {        /* Translate foreign guest addresses. */        mfn = gmfn_to_mfn(FOREIGNDOM, l1e_get_pfn(nl1e));        if ( unlikely(mfn == INVALID_MFN) )            return page_unlock(l1pg), 0;        ASSERT((mfn & ~(PADDR_MASK >> PAGE_SHIFT)) == 0);        nl1e = l1e_from_pfn(mfn, l1e_get_flags(nl1e));        if ( unlikely(l1e_get_flags(nl1e) & l1_disallow_mask(d)) )        {            page_unlock(l1pg);            MEM_LOG("Bad L1 flags %x",                    l1e_get_flags(nl1e) & l1_disallow_mask(d));            return 0;        }        /* Fast path for identical mapping, r/w and presence. */        if ( !l1e_has_changed(ol1e, nl1e, _PAGE_RW | _PAGE_PRESENT) )        {            adjust_guest_l1e(nl1e, d);            rc = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,                              preserve_ad);            page_unlock(l1pg);            return rc;        }        if ( unlikely(!get_page_from_l1e(nl1e, FOREIGNDOM)) )            return page_unlock(l1pg), 0;                adjust_guest_l1e(nl1e, d);        if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,                                    preserve_ad)) )        {            ol1e = nl1e;            rc = 0;        }    }    else if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,                                     preserve_ad)) )    {        page_unlock(l1pg);        return 0;    }    page_unlock(l1pg);    put_page_from_l1e(ol1e, d);    return rc;}/* Update the L2 entry at pl2e to new value nl2e. pl2e is within frame pfn. */static int mod_l2_entry(l2_pgentry_t *pl2e,                         l2_pgentry_t nl2e,                         unsigned long pfn,                        unsigned long type,                        int preserve_ad){    l2_pgentry_t ol2e;    struct vcpu *curr = current;    struct domain *d = curr->domain;    struct page_info *l2pg = mfn_to_page(pfn);    int rc = 1;    if ( unlikely(!is_guest_l2_slot(d, type, pgentry_ptr_to_slot(pl2e))) )    {        MEM_LOG("Illegal L2 update attempt in Xen-private area %p", pl2e);        return 0;    }    page_lock(l2pg);    if ( unlikely(__copy_from_user(&ol2e, pl2e, sizeof(ol2e)) != 0) )        return page_unlock(l2pg), 0;    if ( l2e_get_flags(nl2e) & _PAGE_PRESENT )    {        if ( unlikely(l2e_get_flags(nl2e) & L2_DISALLOW_MASK) )        {            page_unlock(l2pg);            MEM_LOG("Bad L2 flags %x",                    l2e_get_flags(nl2e) & L2_DISALLOW_MASK);            return 0;        }        /* Fast path for identical mapping and presence. */        if ( !l2e_has_changed(ol2e, nl2e, _PAGE_PRESENT) )        {            adjust_guest_l2e(nl2e, d);            rc = UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr, preserve_ad);            page_unlock(l2pg);            return rc;        }        if ( unlikely(!get_page_from_l2e(nl2e, pfn, d)) )            return page_unlock(l2pg), 0;        adjust_guest_l2e(nl2e, d);        if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr,                                    preserve_ad)) )        {            ol2e = nl2e;            rc = 0;        }    }    else if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr,                                     preserve_ad)) )    {        page_unlock(l2pg);        return 0;    }    page_unlock(l2pg);    put_page_from_l2e(ol2e, pfn);    return rc;}#if CONFIG_PAGING_LEVELS >= 3/* Update the L3 entry at pl3e to new value nl3e. pl3e is within frame pfn. */static int mod_l3_entry(l3_pgentry_t *pl3e,                         l3_pgentry_t nl3e,                         unsigned long pfn,                        int preserve_ad){    l3_pgentry_t ol3e;    struct vcpu *curr = current;    struct domain *d = curr->domain;    struct page_info *l3pg = mfn_to_page(pfn);    int rc = 1;    if ( unlikely(!is_guest_l3_slot(pgentry_ptr_to_slot(pl3e))) )    {        MEM_LOG("Illegal L3 update attempt in Xen-private area %p", pl3e);        return 0;    }    /*     * Disallow updates to final L3 slot. It contains Xen mappings, and it     * would be a pain to ensure they remain continuously valid throughout.     */    if ( is_pv_32bit_domain(d) && (pgentry_ptr_to_slot(pl3e) >= 3) )        return 0;    page_lock(l3pg);    if ( unlikely(__copy_from_user(&ol3e, pl3e, sizeof(ol3e)) != 0) )        return page_unlock(l3pg), 0;    if ( l3e_get_flags(nl3e) & _PAGE_PRESENT )    {        if ( unlikely(l3e_get_flags(nl3e) & l3_disallow_mask(d)) )        {            page_unlock(l3pg);            MEM_LOG("Bad L3 flags %x",                    l3e_get_flags(nl3e) & l3_disallow_mask(d));            return 0;        }        /* Fast path for identical mapping and presence. */        if ( !l3e_has_changed(ol3e, nl3e, _PAGE_PRESENT) )        {            adjust_guest_l3e(nl3e, d);            rc = UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr, preserve_ad);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?