hap.c

来自「xen 3.2.2 源码」· C语言 代码 · 共 754 行 · 第 1/2 页

C
754
字号
            goto oom;        m2mfn = page_to_mfn(pg);        l3e = hap_map_domain_page(m3mfn);        l3e[3] = l3e_from_pfn(mfn_x(m2mfn), _PAGE_PRESENT);        hap_install_xen_entries_in_l2h(v, m2mfn);        /* Install the monitor's own linear map */        l2e = hap_map_domain_page(m2mfn);        for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ )            l2e[l2_table_offset(LINEAR_PT_VIRT_START) + i] =                (l3e_get_flags(l3e[i]) & _PAGE_PRESENT)                ? l2e_from_pfn(l3e_get_pfn(l3e[i]), __PAGE_HYPERVISOR)                : l2e_empty();        hap_unmap_domain_page(l2e);        hap_unmap_domain_page(l3e);        HAP_PRINTK("new monitor table: %#lx\n", mfn_x(m3mfn));        return m3mfn;    }#else    {        mfn_t m2mfn;        if ( (pg = hap_alloc(d)) == NULL )            goto oom;        m2mfn = page_to_mfn(pg);;        hap_install_xen_entries_in_l2(v, m2mfn);        return m2mfn;    }#endif oom:    HAP_ERROR("out of memory building monitor pagetable\n");    domain_crash(d);    return _mfn(INVALID_MFN);}static void hap_destroy_monitor_table(struct vcpu* v, mfn_t mmfn){    struct domain *d = v->domain;#if CONFIG_PAGING_LEVELS == 3    /* Need to destroy the l2 monitor page in slot 4 too */    {        l3_pgentry_t *l3e = hap_map_domain_page(mmfn);        ASSERT(l3e_get_flags(l3e[3]) & _PAGE_PRESENT);        hap_free(d, _mfn(l3e_get_pfn(l3e[3])));        hap_unmap_domain_page(l3e);    }#endif    /* Put the memory back in the pool */    hap_free(d, mmfn);}/************************************************//*          HAP DOMAIN LEVEL FUNCTIONS          *//************************************************/void hap_domain_init(struct domain *d){    hap_lock_init(d);    INIT_LIST_HEAD(&d->arch.paging.hap.freelist);    /* This domain will use HAP for log-dirty mode */    paging_log_dirty_init(d, hap_enable_log_dirty, hap_disable_log_dirty,                          hap_clean_dirty_bitmap);}/* return 0 for success, -errno for failure */int hap_enable(struct domain *d, u32 mode){    unsigned int old_pages;    int rv = 0;    domain_pause(d);    /* error check */    if ( (d == current->domain) )    {        rv = -EINVAL;        goto out;    }    old_pages = d->arch.paging.hap.total_pages;    if ( old_pages == 0 )    {        unsigned int r;        hap_lock(d);        r = hap_set_allocation(d, 256, NULL);        hap_unlock(d);        if ( r != 0 )        {            hap_set_allocation(d, 0, NULL);            rv = -ENOMEM;            goto out;        }    }    /* allocate P2m table */    if ( mode & PG_translate )    {        rv = p2m_alloc_table(d, hap_alloc_p2m_page, hap_free_p2m_page);        if ( rv != 0 )            goto out;    }    d->arch.paging.mode = mode | PG_HAP_enable; out:    domain_unpause(d);    return rv;}void hap_final_teardown(struct domain *d){    if ( d->arch.paging.hap.total_pages != 0 )        hap_teardown(d);    p2m_teardown(d);    ASSERT(d->arch.paging.hap.p2m_pages == 0);}void hap_teardown(struct domain *d){    struct vcpu *v;    mfn_t mfn;    ASSERT(d->is_dying);    ASSERT(d != current->domain);    if ( !hap_locked_by_me(d) )        hap_lock(d); /* Keep various asserts happy */    if ( paging_mode_enabled(d) )    {        /* release the monitor table held by each vcpu */        for_each_vcpu ( d, v )        {            if ( v->arch.paging.mode && paging_mode_external(d) )            {                mfn = pagetable_get_mfn(v->arch.monitor_table);                if ( mfn_valid(mfn) && (mfn_x(mfn) != 0) )                    hap_destroy_monitor_table(v, mfn);                v->arch.monitor_table = pagetable_null();            }        }    }    if ( d->arch.paging.hap.total_pages != 0 )    {        HAP_PRINTK("teardown of domain %u starts."                      "  pages total = %u, free = %u, p2m=%u\n",                      d->domain_id,                      d->arch.paging.hap.total_pages,                      d->arch.paging.hap.free_pages,                      d->arch.paging.hap.p2m_pages);        hap_set_allocation(d, 0, NULL);        HAP_PRINTK("teardown done."                      "  pages total = %u, free = %u, p2m=%u\n",                      d->arch.paging.hap.total_pages,                      d->arch.paging.hap.free_pages,                      d->arch.paging.hap.p2m_pages);        ASSERT(d->arch.paging.hap.total_pages == 0);    }    d->arch.paging.mode &= ~PG_log_dirty;    hap_unlock(d);}int hap_domctl(struct domain *d, xen_domctl_shadow_op_t *sc,               XEN_GUEST_HANDLE(void) u_domctl){    int rc, preempted = 0;    switch ( sc->op )    {    case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION:        hap_lock(d);        rc = hap_set_allocation(d, sc->mb << (20 - PAGE_SHIFT), &preempted);        hap_unlock(d);        if ( preempted )            /* Not finished.  Set up to re-run the call. */            rc = hypercall_create_continuation(__HYPERVISOR_domctl, "h",                                               u_domctl);        else            /* Finished.  Return the new allocation */            sc->mb = hap_get_allocation(d);        return rc;    case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION:        sc->mb = hap_get_allocation(d);        return 0;    default:        HAP_ERROR("Bad hap domctl op %u\n", sc->op);        return -EINVAL;    }}void hap_vcpu_init(struct vcpu *v){    v->arch.paging.mode = &hap_paging_real_mode;}/************************************************//*          HAP PAGING MODE FUNCTIONS           *//************************************************//* * HAP guests can handle page faults (in the guest page tables) without * needing any action from Xen, so we should not be intercepting them. */static int hap_page_fault(struct vcpu *v, unsigned long va,                          struct cpu_user_regs *regs){    HAP_ERROR("Intercepted a guest #PF (%u:%u) with HAP enabled.\n",              v->domain->domain_id, v->vcpu_id);    domain_crash(v->domain);    return 0;}/* * HAP guests can handle invlpg without needing any action from Xen, so * should not be intercepting it. */static int hap_invlpg(struct vcpu *v, unsigned long va){    HAP_ERROR("Intercepted a guest INVLPG (%u:%u) with HAP enabled.\n",              v->domain->domain_id, v->vcpu_id);    domain_crash(v->domain);    return 0;}static void hap_update_cr3(struct vcpu *v, int do_locking){    v->arch.hvm_vcpu.hw_cr[3] = v->arch.hvm_vcpu.guest_cr[3];    hvm_update_guest_cr(v, 3);}static void hap_update_paging_modes(struct vcpu *v){    struct domain *d = v->domain;    hap_lock(d);    v->arch.paging.mode =        !hvm_paging_enabled(v)   ? &hap_paging_real_mode :        hvm_long_mode_enabled(v) ? &hap_paging_long_mode :        hvm_pae_enabled(v)       ? &hap_paging_pae_mode  :                                   &hap_paging_protected_mode;    if ( pagetable_is_null(v->arch.monitor_table) )    {        mfn_t mmfn = hap_make_monitor_table(v);        v->arch.monitor_table = pagetable_from_mfn(mmfn);        make_cr3(v, mfn_x(mmfn));        hvm_update_host_cr3(v);    }    /* CR3 is effectively updated by a mode change. Flush ASIDs, etc. */    hap_update_cr3(v, 0);    hap_unlock(d);}#if CONFIG_PAGING_LEVELS == 3static void p2m_install_entry_in_monitors(struct domain *d, l3_pgentry_t *l3e)/* Special case, only used for PAE hosts: update the mapping of the p2m * table.  This is trivial in other paging modes (one top-level entry * points to the top-level p2m, no maintenance needed), but PAE makes * life difficult by needing a copy of the p2m table in eight l2h slots * in the monitor table.  This function makes fresh copies when a p2m * l3e changes. */{    l2_pgentry_t *ml2e;    struct vcpu *v;    unsigned int index;    index = ((unsigned long)l3e & ~PAGE_MASK) / sizeof(l3_pgentry_t);    ASSERT(index < MACHPHYS_MBYTES>>1);    for_each_vcpu ( d, v )    {        if ( pagetable_get_pfn(v->arch.monitor_table) == 0 )            continue;        ASSERT(paging_mode_external(v->domain));        if ( v == current ) /* OK to use linear map of monitor_table */            ml2e = __linear_l2_table + l2_linear_offset(RO_MPT_VIRT_START);        else {            l3_pgentry_t *ml3e;            ml3e = hap_map_domain_page(                pagetable_get_mfn(v->arch.monitor_table));            ASSERT(l3e_get_flags(ml3e[3]) & _PAGE_PRESENT);            ml2e = hap_map_domain_page(_mfn(l3e_get_pfn(ml3e[3])));            ml2e += l2_table_offset(RO_MPT_VIRT_START);            hap_unmap_domain_page(ml3e);        }        ml2e[index] = l2e_from_pfn(l3e_get_pfn(*l3e), __PAGE_HYPERVISOR);        if ( v != current )            hap_unmap_domain_page(ml2e);    }}#endifstatic voidhap_write_p2m_entry(struct vcpu *v, unsigned long gfn, l1_pgentry_t *p,                    mfn_t table_mfn, l1_pgentry_t new, unsigned int level){    hap_lock(v->domain);    safe_write_pte(p, new);#if CONFIG_PAGING_LEVELS == 3    /* install P2M in monitor table for PAE Xen */    if ( level == 3 )        /* We have written to the p2m l3: need to sync the per-vcpu         * copies of it in the monitor tables */        p2m_install_entry_in_monitors(v->domain, (l3_pgentry_t *)p);#endif    hap_unlock(v->domain);}static unsigned long hap_gva_to_gfn_real_mode(    struct vcpu *v, unsigned long gva, uint32_t *pfec){    return ((paddr_t)gva >> PAGE_SHIFT);}/* Entry points into this mode of the hap code. */struct paging_mode hap_paging_real_mode = {    .page_fault             = hap_page_fault,    .invlpg                 = hap_invlpg,    .gva_to_gfn             = hap_gva_to_gfn_real_mode,    .update_cr3             = hap_update_cr3,    .update_paging_modes    = hap_update_paging_modes,    .write_p2m_entry        = hap_write_p2m_entry,    .guest_levels           = 1};struct paging_mode hap_paging_protected_mode = {    .page_fault             = hap_page_fault,    .invlpg                 = hap_invlpg,    .gva_to_gfn             = hap_gva_to_gfn_2level,    .update_cr3             = hap_update_cr3,    .update_paging_modes    = hap_update_paging_modes,    .write_p2m_entry        = hap_write_p2m_entry,    .guest_levels           = 2};struct paging_mode hap_paging_pae_mode = {    .page_fault             = hap_page_fault,    .invlpg                 = hap_invlpg,    .gva_to_gfn             = hap_gva_to_gfn_3level,    .update_cr3             = hap_update_cr3,    .update_paging_modes    = hap_update_paging_modes,    .write_p2m_entry        = hap_write_p2m_entry,    .guest_levels           = 3};struct paging_mode hap_paging_long_mode = {    .page_fault             = hap_page_fault,    .invlpg                 = hap_invlpg,    .gva_to_gfn             = hap_gva_to_gfn_4level,    .update_cr3             = hap_update_cr3,    .update_paging_modes    = hap_update_paging_modes,    .write_p2m_entry        = hap_write_p2m_entry,    .guest_levels           = 4};/* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

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