⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mm.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * Update ref counts to shadow tables appropriately. */void update_cr3(struct vcpu *v){    unsigned long cr3_mfn=0;    if ( paging_mode_enabled(v->domain) )    {        paging_update_cr3(v);        return;    }#if CONFIG_PAGING_LEVELS == 4    if ( !(v->arch.flags & TF_kernel_mode) )        cr3_mfn = pagetable_get_pfn(v->arch.guest_table_user);    else#endif        cr3_mfn = pagetable_get_pfn(v->arch.guest_table);    make_cr3(v, cr3_mfn);}static void invalidate_shadow_ldt(struct vcpu *v){    int i;    unsigned long pfn;    struct page_info *page;        if ( v->arch.shadow_ldt_mapcnt == 0 )        return;    v->arch.shadow_ldt_mapcnt = 0;    for ( i = 16; i < 32; i++ )    {        pfn = l1e_get_pfn(v->arch.perdomain_ptes[i]);        if ( pfn == 0 ) continue;        l1e_write(&v->arch.perdomain_ptes[i], l1e_empty());        page = mfn_to_page(pfn);        ASSERT_PAGE_IS_TYPE(page, PGT_ldt_page);        ASSERT_PAGE_IS_DOMAIN(page, v->domain);        put_page_and_type(page);    }    /* Dispose of the (now possibly invalid) mappings from the TLB.  */    if ( v == current )        queue_deferred_ops(v->domain, DOP_FLUSH_TLB | DOP_RELOAD_LDT);    else        flush_tlb_mask(v->domain->domain_dirty_cpumask);}static int alloc_segdesc_page(struct page_info *page){    struct desc_struct *descs;    int i;    descs = map_domain_page(page_to_mfn(page));    for ( i = 0; i < 512; i++ )        if ( unlikely(!check_descriptor(page_get_owner(page), &descs[i])) )            goto fail;    unmap_domain_page(descs);    return 1; fail:    unmap_domain_page(descs);    return 0;}/* Map shadow page at offset @off. */int map_ldt_shadow_page(unsigned int off){    struct vcpu *v = current;    struct domain *d = v->domain;    unsigned long gmfn, mfn;    l1_pgentry_t l1e, nl1e;    unsigned long gva = v->arch.guest_context.ldt_base + (off << PAGE_SHIFT);    int okay;    BUG_ON(unlikely(in_irq()));    guest_get_eff_kern_l1e(v, gva, &l1e);    if ( unlikely(!(l1e_get_flags(l1e) & _PAGE_PRESENT)) )        return 0;    gmfn = l1e_get_pfn(l1e);    mfn = gmfn_to_mfn(d, gmfn);    if ( unlikely(!mfn_valid(mfn)) )        return 0;    okay = get_page_and_type(mfn_to_page(mfn), d, PGT_ldt_page);    if ( unlikely(!okay) )        return 0;    nl1e = l1e_from_pfn(mfn, l1e_get_flags(l1e) | _PAGE_RW);    l1e_write(&v->arch.perdomain_ptes[off + 16], nl1e);    v->arch.shadow_ldt_mapcnt++;    return 1;}static int get_page_from_pagenr(unsigned long page_nr, struct domain *d){    struct page_info *page = mfn_to_page(page_nr);    if ( unlikely(!mfn_valid(page_nr)) || unlikely(!get_page(page, d)) )    {        MEM_LOG("Could not get page ref for pfn %lx", page_nr);        return 0;    }    return 1;}static int get_page_and_type_from_pagenr(unsigned long page_nr,                                          unsigned long type,                                         struct domain *d){    struct page_info *page = mfn_to_page(page_nr);    if ( unlikely(!get_page_from_pagenr(page_nr, d)) )        return 0;    if ( unlikely(!get_page_type(page, type)) )    {        put_page(page);        return 0;    }    return 1;}/* * We allow root tables to map each other (a.k.a. linear page tables). It * needs some special care with reference counts and access permissions: *  1. The mapping entry must be read-only, or the guest may get write access *     to its own PTEs. *  2. We must only bump the reference counts for an *already validated* *     L2 table, or we can end up in a deadlock in get_page_type() by waiting *     on a validation that is required to complete that validation. *  3. We only need to increment the reference counts for the mapped page *     frame if it is mapped by a different root table. This is sufficient and *     also necessary to allow validation of a root table mapping itself. */#define define_get_linear_pagetable(level)                                  \static int                                                                  \get_##level##_linear_pagetable(                                             \    level##_pgentry_t pde, unsigned long pde_pfn, struct domain *d)         \{                                                                           \    unsigned long x, y;                                                     \    struct page_info *page;                                                 \    unsigned long pfn;                                                      \                                                                            \    if ( (level##e_get_flags(pde) & _PAGE_RW) )                             \    {                                                                       \        MEM_LOG("Attempt to create linear p.t. with write perms");          \        return 0;                                                           \    }                                                                       \                                                                            \    if ( (pfn = level##e_get_pfn(pde)) != pde_pfn )                         \    {                                                                       \        /* Make sure the mapped frame belongs to the correct domain. */     \        if ( unlikely(!get_page_from_pagenr(pfn, d)) )                      \            return 0;                                                       \                                                                            \        /*                                                                  \         * Ensure that the mapped frame is an already-validated page table. \         * If so, atomically increment the count (checking for overflow).   \         */                                                                 \        page = mfn_to_page(pfn);                                            \        y = page->u.inuse.type_info;                                        \        do {                                                                \            x = y;                                                          \            if ( unlikely((x & PGT_count_mask) == PGT_count_mask) ||        \                 unlikely((x & (PGT_type_mask|PGT_validated)) !=            \                          (PGT_##level##_page_table|PGT_validated)) )       \            {                                                               \                put_page(page);                                             \                return 0;                                                   \            }                                                               \        }                                                                   \        while ( (y = cmpxchg(&page->u.inuse.type_info, x, x + 1)) != x );   \    }                                                                       \                                                                            \    return 1;                                                               \}int is_iomem_page(unsigned long mfn){    return (!mfn_valid(mfn) || (page_get_owner(mfn_to_page(mfn)) == dom_io));}intget_page_from_l1e(    l1_pgentry_t l1e, struct domain *d){    unsigned long mfn = l1e_get_pfn(l1e);    struct page_info *page = mfn_to_page(mfn);    uint32_t l1f = l1e_get_flags(l1e);    struct vcpu *curr = current;    int okay;    if ( !(l1f & _PAGE_PRESENT) )        return 1;    if ( unlikely(l1f & l1_disallow_mask(d)) )    {        MEM_LOG("Bad L1 flags %x", l1f & l1_disallow_mask(d));        return 0;    }    if ( is_iomem_page(mfn) )    {        /* DOMID_IO reverts to caller for privilege checks. */        if ( d == dom_io )            d = curr->domain;        if ( !iomem_access_permitted(d, mfn, mfn) )        {            if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */                MEM_LOG("Non-privileged (%u) attempt to map I/O space %08lx",                         d->domain_id, mfn);            return 0;        }        return 1;    }    /* Foreign mappings into guests in shadow external mode don't     * contribute to writeable mapping refcounts.  (This allows the     * qemu-dm helper process in dom0 to map the domain's memory without     * messing up the count of "real" writable mappings.) */    okay = (((l1f & _PAGE_RW) &&              !(unlikely(paging_mode_external(d) && (d != curr->domain))))            ? get_page_and_type(page, d, PGT_writable_page)            : get_page(page, d));    if ( !okay )    {        MEM_LOG("Error getting mfn %lx (pfn %lx) from L1 entry %" PRIpte                " for dom%d",                mfn, get_gpfn_from_mfn(mfn),                l1e_get_intpte(l1e), d->domain_id);    }    else if ( pte_flags_to_cacheattr(l1f) !=              ((page->count_info >> PGC_cacheattr_base) & 7) )    {        uint32_t x, nx, y = page->count_info;        uint32_t cacheattr = pte_flags_to_cacheattr(l1f);        if ( is_xen_heap_page(page) )        {            if ( (l1f & _PAGE_RW) &&                 !(unlikely(paging_mode_external(d) &&                            (d != curr->domain))) )                put_page_type(page);            put_page(page);            MEM_LOG("Attempt to change cache attributes of Xen heap page");            return 0;        }        while ( ((y >> PGC_cacheattr_base) & 7) != cacheattr )        {            x  = y;            nx = (x & ~PGC_cacheattr_mask) | (cacheattr << PGC_cacheattr_base);            y  = cmpxchg(&page->count_info, x, nx);        }#ifdef __x86_64__        map_pages_to_xen((unsigned long)mfn_to_virt(mfn), mfn, 1,                         PAGE_HYPERVISOR | cacheattr_to_pte_flags(cacheattr));#endif    }    return okay;}/* NB. Virtual address 'l2e' maps to a machine address within frame 'pfn'. */define_get_linear_pagetable(l2);static intget_page_from_l2e(    l2_pgentry_t l2e, unsigned long pfn, struct domain *d){    int rc;    if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )        return 1;    if ( unlikely((l2e_get_flags(l2e) & L2_DISALLOW_MASK)) )    {        MEM_LOG("Bad L2 flags %x", l2e_get_flags(l2e) & L2_DISALLOW_MASK);        return 0;    }    rc = get_page_and_type_from_pagenr(l2e_get_pfn(l2e), PGT_l1_page_table, d);    if ( unlikely(!rc) )        rc = get_l2_linear_pagetable(l2e, pfn, d);    return rc;}#if CONFIG_PAGING_LEVELS >= 3define_get_linear_pagetable(l3);static intget_page_from_l3e(    l3_pgentry_t l3e, unsigned long pfn, struct domain *d){    int rc;    if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) )        return 1;    if ( unlikely((l3e_get_flags(l3e) & l3_disallow_mask(d))) )    {        MEM_LOG("Bad L3 flags %x", l3e_get_flags(l3e) & l3_disallow_mask(d));        return 0;    }    rc = get_page_and_type_from_pagenr(l3e_get_pfn(l3e), PGT_l2_page_table, d);    if ( unlikely(!rc) )        rc = get_l3_linear_pagetable(l3e, pfn, d);    return rc;}#endif /* 3 level */#if CONFIG_PAGING_LEVELS >= 4define_get_linear_pagetable(l4);static intget_page_from_l4e(    l4_pgentry_t l4e, unsigned long pfn, struct domain *d){    int rc;    if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) )        return 1;    if ( unlikely((l4e_get_flags(l4e) & L4_DISALLOW_MASK)) )    {        MEM_LOG("Bad L4 flags %x", l4e_get_flags(l4e) & L4_DISALLOW_MASK);        return 0;    }    rc = get_page_and_type_from_pagenr(l4e_get_pfn(l4e), PGT_l3_page_table, d);    if ( unlikely(!rc) )        rc = get_l4_linear_pagetable(l4e, pfn, d);    return rc;}#endif /* 4 level */#ifdef __x86_64__#ifdef USER_MAPPINGS_ARE_GLOBAL#define adjust_guest_l1e(pl1e, d)                                            \    do {                                                                     \        if ( likely(l1e_get_flags((pl1e)) & _PAGE_PRESENT) &&                \             likely(!is_pv_32on64_domain(d)) )                               \        {                                                                    \            /* _PAGE_GUEST_KERNEL page cannot have the Global bit set. */    \            if ( (l1e_get_flags((pl1e)) & (_PAGE_GUEST_KERNEL|_PAGE_GLOBAL)) \                 == (_PAGE_GUEST_KERNEL|_PAGE_GLOBAL) )                      \                MEM_LOG("Global bit is set to kernel page %lx",              \                        l1e_get_pfn((pl1e)));                                \            if ( !(l1e_get_flags((pl1e)) & _PAGE_USER) )                     \                l1e_add_flags((pl1e), (_PAGE_GUEST_KERNEL|_PAGE_USER));      \            if ( !(l1e_get_flags((pl1e)) & _PAGE_GUEST_KERNEL) )             \                l1e_add_flags((pl1e), (_PAGE_GLOBAL|_PAGE_USER));            \        }                                                                    \    } while ( 0 )#else#define adjust_guest_l1e(pl1e, d)                               \    do {                                                        \        if ( likely(l1e_get_flags((pl1e)) & _PAGE_PRESENT) &&   \             likely(!is_pv_32on64_domain(d)) )                  \            l1e_add_flags((pl1e), _PAGE_USER);                  \    } while ( 0 )#endif#define adjust_guest_l2e(pl2e, d)                               \    do {                                                        \        if ( likely(l2e_get_flags((pl2e)) & _PAGE_PRESENT) &&   \             likely(!is_pv_32on64_domain(d)) )                  \            l2e_add_flags((pl2e), _PAGE_USER);                  \    } while ( 0 )#define adjust_guest_l3e(pl3e, d)                                   \    do {                                                            \        if ( likely(l3e_get_flags((pl3e)) & _PAGE_PRESENT) )        \            l3e_add_flags((pl3e), likely(!is_pv_32on64_domain(d)) ? \                                         _PAGE_USER :               \                                         _PAGE_USER|_PAGE_RW);      \    } while ( 0 )#define adjust_guest_l4e(pl4e, d)                               \    do {                                                        \        if ( likely(l4e_get_flags((pl4e)) & _PAGE_PRESENT) &&   \             likely(!is_pv_32on64_domain(d)) )                  \            l4e_add_flags((pl4e), _PAGE_USER);                  \    } while ( 0 )#else /* !defined(__x86_64__) */#define adjust_guest_l1e(_p, _d) ((void)(_d))

⌨️ 快捷键说明

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