mm.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 2,038 行 · 第 1/5 页
C
2,038 行
page_unlock(l3pg); return rc; } if ( unlikely(!get_page_from_l3e(nl3e, pfn, d)) ) return page_unlock(l3pg), 0; adjust_guest_l3e(nl3e, d); if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr, preserve_ad)) ) { ol3e = nl3e; rc = 0; } } else if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr, preserve_ad)) ) { page_unlock(l3pg); return 0; } if ( likely(rc) ) { if ( !create_pae_xen_mappings(d, pl3e) ) BUG(); pae_flush_pgd(pfn, pgentry_ptr_to_slot(pl3e), nl3e); } page_unlock(l3pg); put_page_from_l3e(ol3e, pfn); return rc;}#endif#if CONFIG_PAGING_LEVELS >= 4/* Update the L4 entry at pl4e to new value nl4e. pl4e is within frame pfn. */static int mod_l4_entry(l4_pgentry_t *pl4e, l4_pgentry_t nl4e, unsigned long pfn, int preserve_ad){ struct vcpu *curr = current; struct domain *d = curr->domain; l4_pgentry_t ol4e; struct page_info *l4pg = mfn_to_page(pfn); int rc = 1; if ( unlikely(!is_guest_l4_slot(d, pgentry_ptr_to_slot(pl4e))) ) { MEM_LOG("Illegal L4 update attempt in Xen-private area %p", pl4e); return 0; } page_lock(l4pg); if ( unlikely(__copy_from_user(&ol4e, pl4e, sizeof(ol4e)) != 0) ) return page_unlock(l4pg), 0; if ( l4e_get_flags(nl4e) & _PAGE_PRESENT ) { if ( unlikely(l4e_get_flags(nl4e) & L4_DISALLOW_MASK) ) { page_unlock(l4pg); MEM_LOG("Bad L4 flags %x", l4e_get_flags(nl4e) & L4_DISALLOW_MASK); return 0; } /* Fast path for identical mapping and presence. */ if ( !l4e_has_changed(ol4e, nl4e, _PAGE_PRESENT) ) { adjust_guest_l4e(nl4e, d); rc = UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr, preserve_ad); page_unlock(l4pg); return rc; } if ( unlikely(!get_page_from_l4e(nl4e, pfn, d)) ) return page_unlock(l4pg), 0; adjust_guest_l4e(nl4e, d); if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr, preserve_ad)) ) { ol4e = nl4e; rc = 0; } } else if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr, preserve_ad)) ) { page_unlock(l4pg); return 0; } page_unlock(l4pg); put_page_from_l4e(ol4e, pfn); return rc;}#endifvoid put_page(struct page_info *page){ u32 nx, x, y = page->count_info; do { x = y; nx = x - 1; } while ( unlikely((y = cmpxchg(&page->count_info, x, nx)) != x) ); if ( unlikely((nx & PGC_count_mask) == 0) ) { cleanup_page_cacheattr(page); free_domheap_page(page); }}int get_page(struct page_info *page, struct domain *domain){ u32 x, nx, y = page->count_info; u32 d, nd = page->u.inuse._domain; u32 _domain = pickle_domptr(domain); do { x = y; nx = x + 1; d = nd; if ( unlikely((x & PGC_count_mask) == 0) || /* Not allocated? */ unlikely((nx & PGC_count_mask) == 0) || /* Count overflow? */ unlikely(d != _domain) ) /* Wrong owner? */ { if ( !_shadow_mode_refcounts(domain) && !domain->is_dying ) gdprintk(XENLOG_INFO, "Error pfn %lx: rd=%p, od=%p, caf=%08x, taf=%" PRtype_info "\n", page_to_mfn(page), domain, unpickle_domptr(d), x, page->u.inuse.type_info); return 0; } asm volatile ( LOCK_PREFIX "cmpxchg8b %2" : "=d" (nd), "=a" (y), "=m" (*(volatile u64 *)(&page->count_info)) : "0" (d), "1" (x), "c" (d), "b" (nx) ); } while ( unlikely(nd != d) || unlikely(y != x) ); return 1;}static int alloc_page_type(struct page_info *page, unsigned long type){ struct domain *owner = page_get_owner(page); /* A page table is dirtied when its type count becomes non-zero. */ if ( likely(owner != NULL) ) paging_mark_dirty(owner, page_to_mfn(page)); switch ( type & PGT_type_mask ) { case PGT_l1_page_table: return alloc_l1_table(page); case PGT_l2_page_table: return alloc_l2_table(page, type); case PGT_l3_page_table: return alloc_l3_table(page); case PGT_l4_page_table: return alloc_l4_table(page); case PGT_seg_desc_page: return alloc_segdesc_page(page); default: printk("Bad type in alloc_page_type %lx t=%" PRtype_info " c=%x\n", type, page->u.inuse.type_info, page->count_info); BUG(); } return 0;}void free_page_type(struct page_info *page, unsigned long type){ struct domain *owner = page_get_owner(page); unsigned long gmfn; if ( likely(owner != NULL) ) { /* * We have to flush before the next use of the linear mapping * (e.g., update_va_mapping()) or we could end up modifying a page * that is no longer a page table (and hence screw up ref counts). */ if ( current->domain == owner ) queue_deferred_ops(owner, DOP_FLUSH_ALL_TLBS); else flush_tlb_mask(owner->domain_dirty_cpumask); if ( unlikely(paging_mode_enabled(owner)) ) { /* A page table is dirtied when its type count becomes zero. */ paging_mark_dirty(owner, page_to_mfn(page)); if ( shadow_mode_refcounts(owner) ) return; gmfn = mfn_to_gmfn(owner, page_to_mfn(page)); ASSERT(VALID_M2P(gmfn)); shadow_remove_all_shadows(owner->vcpu[0], _mfn(gmfn)); } } switch ( type & PGT_type_mask ) { case PGT_l1_page_table: free_l1_table(page); break; case PGT_l2_page_table: free_l2_table(page); break;#if CONFIG_PAGING_LEVELS >= 3 case PGT_l3_page_table: free_l3_table(page); break;#endif#if CONFIG_PAGING_LEVELS >= 4 case PGT_l4_page_table: free_l4_table(page); break;#endif default: printk("%s: type %lx pfn %lx\n",__FUNCTION__, type, page_to_mfn(page)); BUG(); }}void put_page_type(struct page_info *page){ unsigned long nx, x, y = page->u.inuse.type_info; again: do { x = y; nx = x - 1; ASSERT((x & PGT_count_mask) != 0); if ( unlikely((nx & PGT_count_mask) == 0) ) { if ( unlikely((nx & PGT_type_mask) <= PGT_l4_page_table) && likely(nx & PGT_validated) ) { /* * Page-table pages must be unvalidated when count is zero. The * 'free' is safe because the refcnt is non-zero and validated * bit is clear => other ops will spin or fail. */ if ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, x & ~PGT_validated)) != x) ) goto again; /* We cleared the 'valid bit' so we do the clean up. */ free_page_type(page, x); /* Carry on, but with the 'valid bit' now clear. */ x &= ~PGT_validated; nx &= ~PGT_validated; } /* * Record TLB information for flush later. We do not stamp page * tables when running in shadow mode: * 1. Pointless, since it's the shadow pt's which must be tracked. * 2. Shadow mode reuses this field for shadowed page tables to * store flags info -- we don't want to conflict with that. */ if ( !(shadow_mode_enabled(page_get_owner(page)) && (page->count_info & PGC_page_table)) ) page->tlbflush_timestamp = tlbflush_current_time(); } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );}int get_page_type(struct page_info *page, unsigned long type){ unsigned long nx, x, y = page->u.inuse.type_info; ASSERT(!(type & ~(PGT_type_mask | PGT_pae_xen_l2))); again: do { x = y; nx = x + 1; if ( unlikely((nx & PGT_count_mask) == 0) ) { MEM_LOG("Type count overflow on pfn %lx", page_to_mfn(page)); return 0; } else if ( unlikely((x & PGT_count_mask) == 0) ) { struct domain *d = page_get_owner(page); /* Normally we should never let a page go from type count 0 * to type count 1 when it is shadowed. One exception: * out-of-sync shadowed pages are allowed to become * writeable. */ if ( d && shadow_mode_enabled(d) && (page->count_info & PGC_page_table) && !((page->shadow_flags & (1u<<29)) && type == PGT_writable_page) ) shadow_remove_all_shadows(d->vcpu[0], _mfn(page_to_mfn(page))); ASSERT(!(x & PGT_pae_xen_l2)); if ( (x & PGT_type_mask) != type ) { /* * On type change we check to flush stale TLB entries. This * may be unnecessary (e.g., page was GDT/LDT) but those * circumstances should be very rare. */ cpumask_t mask = d->domain_dirty_cpumask; /* Don't flush if the timestamp is old enough */ tlbflush_filter(mask, page->tlbflush_timestamp); if ( unlikely(!cpus_empty(mask)) && /* Shadow mode: track only writable pages. */ (!shadow_mode_enabled(page_get_owner(page)) || ((nx & PGT_type_mask) == PGT_writable_page)) ) { perfc_incr(need_flush_tlb_flush); flush_tlb_mask(mask); } /* We lose existing type and validity. */ nx &= ~(PGT_type_mask | PGT_validated); nx |= type; /* No special validation needed for writable pages. */ /* Page tables and GDT/LDT need to be scanned for validity. */ if ( type == PGT_writable_page ) nx |= PGT_validated; } } else if ( unlikely((x & (PGT_type_mask|PGT_pae_xen_l2)) != type) ) { /* Don't log failure if it could be a recursive-mapping attempt. */ if ( ((x & PGT_type_mask) == PGT_l2_page_table) && (type == PGT_l1_page_table) ) return 0; if ( ((x & PGT_type_mask) == PGT_l3_page_table) && (type == PGT_l2_page_table) ) return 0; if ( ((x & PGT_type_mask) == PGT_l4_page_table) && (type == PGT_l3_page_table) ) return 0; MEM_LOG("Bad type (saw %" PRtype_info " != exp %" PRtype_info ") " "for mfn %lx (pfn %lx)", x, type, page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page))); return 0; } else if ( unlikely(!(x & PGT_validated)) ) { /* Someone else is updating validation of this page. Wait... */ while ( (y = page->u.inuse.type_info) == x ) cpu_relax(); goto again; } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); if ( unlikely((x & PGT_type_mask) != type) ) { /* Special pages should not be accessible from devices. */ struct domain *d = page_get_owner(page); if ( d && unlikely(need_iommu(d)) ) { if ( (x & PGT_type_mask) == PGT_writable_page ) iommu_unmap_page(d, mfn_to_gmfn(d, page_to_mfn(page))); else if ( type == PGT_writable_page ) iommu_map_page(d, mfn_to_gmfn(d, page_to_mfn(page)), page_to_mfn(page)); } } if ( unlikely(!(nx & PGT_validated)) ) { /* Try to validate page type; drop the new reference on failure. */ if ( unlikely(!alloc_page_type(page, type)) ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?