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 + -
显示快捷键?