p2m.c

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

C
1,188
字号
                  i3++ )            {                if ( !(l3e_get_flags(l3e[i3]) & _PAGE_PRESENT) )                {                    gfn += 1 << (L3_PAGETABLE_SHIFT - PAGE_SHIFT);                    continue;                }                l2e = map_domain_page(mfn_x(_mfn(l3e_get_pfn(l3e[i3]))));                for ( i2 = 0; i2 < L2_PAGETABLE_ENTRIES; i2++ )                {                    if ( !(l2e_get_flags(l2e[i2]) & _PAGE_PRESENT) )                    {                        gfn += 1 << (L2_PAGETABLE_SHIFT - PAGE_SHIFT);                        continue;                    }                                        /* check for super page */                    if ( l2e_get_flags(l2e[i2]) & _PAGE_PSE )                    {                        mfn = l2e_get_pfn(l2e[i2]);                        ASSERT(mfn_valid(_mfn(mfn)));                        for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++)                        {                            m2pfn = get_gpfn_from_mfn(mfn+i1);                            if ( m2pfn != (gfn + i) )                            {                                pmbad++;                                P2M_PRINTK("mismatch: gfn %#lx -> mfn %#lx"                                           " -> gfn %#lx\n", gfn+i, mfn+i,                                           m2pfn);                                BUG();                            }                        }                        gfn += 1 << (L2_PAGETABLE_SHIFT - PAGE_SHIFT);                        continue;                    }                    l1e = map_domain_page(mfn_x(_mfn(l2e_get_pfn(l2e[i2]))));                    for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++, gfn++ )                    {                        if ( !(l1e_get_flags(l1e[i1]) & _PAGE_PRESENT) )                            continue;                        mfn = l1e_get_pfn(l1e[i1]);                        ASSERT(mfn_valid(_mfn(mfn)));                        m2pfn = get_gpfn_from_mfn(mfn);                        if ( m2pfn != gfn )                        {                            pmbad++;                            P2M_PRINTK("mismatch: gfn %#lx -> mfn %#lx"                                       " -> gfn %#lx\n", gfn, mfn, m2pfn);                            BUG();                        }                    }                    unmap_domain_page(l1e);                }                unmap_domain_page(l2e);            }#if CONFIG_PAGING_LEVELS >= 4            unmap_domain_page(l3e);        }#endif#if CONFIG_PAGING_LEVELS == 4        unmap_domain_page(l4e);#else /* CONFIG_PAGING_LEVELS == 3 */        unmap_domain_page(l3e);#endif    }    //P2M_PRINTK("p2m audit complete\n");    //if ( orphans_i | orphans_d | mpbad | pmbad )    //    P2M_PRINTK("p2m audit found %lu orphans (%lu inval %lu debug)\n",    //                   orphans_i + orphans_d, orphans_i, orphans_d,    if ( mpbad | pmbad )        P2M_PRINTK("p2m audit found %lu odd p2m, %lu bad m2p entries\n",                   pmbad, mpbad);}#else#define audit_p2m(_d) do { (void)(_d); } while(0)#endif /* P2M_AUDIT */static voidp2m_remove_page(struct domain *d, unsigned long gfn, unsigned long mfn,                unsigned int page_order){    unsigned long i;    if ( !paging_mode_translate(d) )    {        if ( need_iommu(d) )            for ( i = 0; i < (1 << page_order); i++ )                iommu_unmap_page(d, mfn + i);        return;    }    P2M_DEBUG("removing gfn=%#lx mfn=%#lx\n", gfn, mfn);    set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid);    for ( i = 0; i < (1UL << page_order); i++ )        set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);}voidguest_physmap_remove_page(struct domain *d, unsigned long gfn,                          unsigned long mfn, unsigned int page_order){    p2m_lock(d->arch.p2m);    audit_p2m(d);    p2m_remove_page(d, gfn, mfn, page_order);    audit_p2m(d);    p2m_unlock(d->arch.p2m);}intguest_physmap_add_entry(struct domain *d, unsigned long gfn,                        unsigned long mfn, unsigned int page_order,                         p2m_type_t t){    unsigned long i, ogfn;    p2m_type_t ot;    mfn_t omfn;    int rc = 0;    if ( !paging_mode_translate(d) )    {        if ( need_iommu(d) && t == p2m_ram_rw )        {            for ( i = 0; i < (1 << page_order); i++ )                if ( (rc = iommu_map_page(d, mfn + i, mfn + i)) != 0 )                {                    while ( i-- > 0 )                        iommu_unmap_page(d, mfn + i);                    return rc;                }        }        return 0;    }#if CONFIG_PAGING_LEVELS == 3    /*     * 32bit PAE nested paging does not support over 4GB guest due to      * hardware translation limit. This limitation is checked by comparing     * gfn with 0xfffffUL.     */    if ( paging_mode_hap(d) && (gfn > 0xfffffUL) )    {        if ( !test_and_set_bool(d->arch.hvm_domain.svm.npt_4gb_warning) )            dprintk(XENLOG_WARNING, "Dom%d failed to populate memory beyond"                    " 4GB: specify 'hap=0' domain config option.\n",                    d->domain_id);        return -EINVAL;    }#endif    p2m_lock(d->arch.p2m);    audit_p2m(d);    P2M_DEBUG("adding gfn=%#lx mfn=%#lx\n", gfn, mfn);    omfn = gfn_to_mfn(d, gfn, &ot);    if ( p2m_is_ram(ot) )    {        ASSERT(mfn_valid(omfn));        for ( i = 0; i < (1UL << page_order); i++ )            set_gpfn_from_mfn(mfn_x(omfn)+i, INVALID_M2P_ENTRY);    }    ogfn = mfn_to_gfn(d, _mfn(mfn));    if (#ifdef __x86_64__        (ogfn != 0x5555555555555555L)#else        (ogfn != 0x55555555L)#endif        && (ogfn != INVALID_M2P_ENTRY)        && (ogfn != gfn) )    {        /* This machine frame is already mapped at another physical address */        P2M_DEBUG("aliased! mfn=%#lx, old gfn=%#lx, new gfn=%#lx\n",                  mfn, ogfn, gfn);        omfn = gfn_to_mfn(d, ogfn, &ot);        if ( p2m_is_ram(ot) )        {            ASSERT(mfn_valid(omfn));            P2M_DEBUG("old gfn=%#lx -> mfn %#lx\n",                      ogfn , mfn_x(omfn));            if ( mfn_x(omfn) == mfn )                p2m_remove_page(d, ogfn, mfn, page_order);        }    }    if ( mfn_valid(_mfn(mfn)) )     {        if ( !set_p2m_entry(d, gfn, _mfn(mfn), page_order, t) )            rc = -EINVAL;        for ( i = 0; i < (1UL << page_order); i++ )            set_gpfn_from_mfn(mfn+i, gfn+i);    }    else    {        gdprintk(XENLOG_WARNING, "Adding bad mfn to p2m map (%#lx -> %#lx)\n",                 gfn, mfn);        if ( !set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order,                             p2m_invalid) )            rc = -EINVAL;    }    audit_p2m(d);    p2m_unlock(d->arch.p2m);    return rc;}/* Walk the whole p2m table, changing any entries of the old type * to the new type.  This is used in hardware-assisted paging to  * quickly enable or diable log-dirty tracking */void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt){    unsigned long mfn, gfn, flags;    l1_pgentry_t l1e_content;    l1_pgentry_t *l1e;    l2_pgentry_t *l2e;    mfn_t l1mfn, l2mfn;    int i1, i2;    l3_pgentry_t *l3e;    int i3;#if CONFIG_PAGING_LEVELS == 4    l4_pgentry_t *l4e;    int i4;#endif /* CONFIG_PAGING_LEVELS == 4 */    if ( !paging_mode_translate(d) )        return;    if ( pagetable_get_pfn(d->arch.phys_table) == 0 )        return;    ASSERT(p2m_locked_by_me(d->arch.p2m));#if CONFIG_PAGING_LEVELS == 4    l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));#else /* CONFIG_PAGING_LEVELS == 3 */    l3e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));#endif#if CONFIG_PAGING_LEVELS >= 4    for ( i4 = 0; i4 < L4_PAGETABLE_ENTRIES; i4++ )    {        if ( !(l4e_get_flags(l4e[i4]) & _PAGE_PRESENT) )        {            continue;        }        l3e = map_domain_page(l4e_get_pfn(l4e[i4]));#endif        for ( i3 = 0;              i3 < ((CONFIG_PAGING_LEVELS==4) ? L3_PAGETABLE_ENTRIES : 8);              i3++ )        {            if ( !(l3e_get_flags(l3e[i3]) & _PAGE_PRESENT) )            {                continue;            }            l2mfn = _mfn(l3e_get_pfn(l3e[i3]));            l2e = map_domain_page(l3e_get_pfn(l3e[i3]));            for ( i2 = 0; i2 < L2_PAGETABLE_ENTRIES; i2++ )            {                if ( !(l2e_get_flags(l2e[i2]) & _PAGE_PRESENT) )                {                    continue;                }                if ( (l2e_get_flags(l2e[i2]) & _PAGE_PSE) )                {                    flags = l2e_get_flags(l2e[i2]);                    if ( p2m_flags_to_type(flags) != ot )                        continue;                    mfn = l2e_get_pfn(l2e[i2]);                    gfn = get_gpfn_from_mfn(mfn);                    flags = p2m_type_to_flags(nt);                    l1e_content = l1e_from_pfn(mfn, flags | _PAGE_PSE);                    paging_write_p2m_entry(d, gfn, (l1_pgentry_t *)&l2e[i2],                                           l2mfn, l1e_content, 2);                    continue;                }                l1mfn = _mfn(l2e_get_pfn(l2e[i2]));                l1e = map_domain_page(mfn_x(l1mfn));                for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++, gfn++ )                {                    flags = l1e_get_flags(l1e[i1]);                    if ( p2m_flags_to_type(flags) != ot )                        continue;                    mfn = l1e_get_pfn(l1e[i1]);                    gfn = get_gpfn_from_mfn(mfn);                    /* create a new 1le entry with the new type */                    flags = p2m_type_to_flags(nt);                    l1e_content = l1e_from_pfn(mfn, flags);                    paging_write_p2m_entry(d, gfn, &l1e[i1],                                           l1mfn, l1e_content, 1);                }                unmap_domain_page(l1e);            }            unmap_domain_page(l2e);        }#if CONFIG_PAGING_LEVELS >= 4        unmap_domain_page(l3e);    }#endif#if CONFIG_PAGING_LEVELS == 4    unmap_domain_page(l4e);#else /* CONFIG_PAGING_LEVELS == 3 */    unmap_domain_page(l3e);#endif}/* Modify the p2m type of a single gfn from ot to nt, returning the  * entry's previous type */p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn,                            p2m_type_t ot, p2m_type_t nt){    p2m_type_t pt;    mfn_t mfn;    p2m_lock(d->arch.p2m);    mfn = gfn_to_mfn(d, gfn, &pt);    if ( pt == ot )        set_p2m_entry(d, gfn, mfn, 0, nt);    p2m_unlock(d->arch.p2m);    return pt;}intset_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn){    int rc = 0;    p2m_type_t ot;    mfn_t omfn;    if ( !paging_mode_translate(d) )        return 0;    omfn = gfn_to_mfn(d, gfn, &ot);    if ( p2m_is_ram(ot) )    {        ASSERT(mfn_valid(omfn));        set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY);    }    rc = set_p2m_entry(d, gfn, mfn, 0, p2m_mmio_direct);    if ( 0 == rc )        gdprintk(XENLOG_ERR,            "set_mmio_p2m_entry: set_p2m_entry failed! mfn=%08lx\n",            gmfn_to_mfn(d, gfn));    return rc;}intclear_mmio_p2m_entry(struct domain *d, unsigned long gfn){    int rc = 0;    unsigned long mfn;    if ( !paging_mode_translate(d) )        return 0;    mfn = gmfn_to_mfn(d, gfn);    if ( INVALID_MFN == mfn )    {        gdprintk(XENLOG_ERR,            "clear_mmio_p2m_entry: gfn_to_mfn failed! gfn=%08lx\n", gfn);        return 0;    }    rc = set_p2m_entry(d, gfn, _mfn(INVALID_MFN), 0, 0);    return rc;}/* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

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