From: Tim Deegan Date: Fri, 31 Aug 2007 10:06:22 +0000 (+0100) Subject: [HVM] Shadow: don't shadow the p2m table. X-Git-Tag: 3.2.0-rc1~365^2~25 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=c028cc106a4abb57e9f0c199e37073a627de7eb6;p=xen.git [HVM] Shadow: don't shadow the p2m table. For HVM vcpus with paging disabled, we used to shadow the p2m table, and skip the p2m lookup to go from gfn to mfn. Instead, we now provide a simple pagetable that gives a one-to-one mapping of 4GB, and shadow that, making the translations from gfn to mfn via the p2m. This removes the paging-disabled special-case code from the shadow fault handler, and allows us to expand the p2m interface, since all HVM translations now go through the same p2m lookups. Signed-off-by: Tim Deegan --- diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 4f56b65f0a..0f4077f48c 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1723,13 +1723,13 @@ void domain_relinquish_resources(struct domain *d) BUG_ON(!cpus_empty(d->domain_dirty_cpumask)); + /* Tear down paging-assistance stuff. */ + paging_teardown(d); + /* Drop the in-use references to page-table bases. */ for_each_vcpu ( d, v ) vcpu_destroy_pagetables(v); - /* Tear down paging-assistance stuff. */ - paging_teardown(d); - /* * Relinquish GDT mappings. No need for explicit unmapping of the LDT as * it automatically gets squashed when the guest's mappings go away. diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index cb07b19289..91b5640e54 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -517,7 +517,7 @@ void hvm_triple_fault(void) int hvm_set_cr0(unsigned long value) { struct vcpu *v = current; - unsigned long mfn, old_base_mfn, old_value = v->arch.hvm_vcpu.guest_cr[0]; + unsigned long mfn, old_value = v->arch.hvm_vcpu.guest_cr[0]; HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR0 value = %lx", value); @@ -569,10 +569,7 @@ int hvm_set_cr0(unsigned long value) } /* Now arch.guest_table points to machine physical. */ - old_base_mfn = pagetable_get_pfn(v->arch.guest_table); v->arch.guest_table = pagetable_from_pfn(mfn); - if ( old_base_mfn ) - put_page(mfn_to_page(old_base_mfn)); HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx", v->arch.hvm_vcpu.guest_cr[3], mfn); diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index 63f1675659..af72e0859e 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -621,8 +621,6 @@ static void hap_update_paging_modes(struct vcpu *v) hvm_pae_enabled(v) ? &hap_paging_pae_mode : &hap_paging_protected_mode; - v->arch.paging.translate_enabled = hvm_paging_enabled(v); - if ( pagetable_is_null(v->arch.monitor_table) ) { mfn_t mmfn = hap_make_monitor_table(v); diff --git a/xen/arch/x86/mm/paging.c b/xen/arch/x86/mm/paging.c index a78f40921a..ac4db900a5 100644 --- a/xen/arch/x86/mm/paging.c +++ b/xen/arch/x86/mm/paging.c @@ -496,10 +496,9 @@ void paging_dump_vcpu_info(struct vcpu *v) if ( paging_mode_shadow(v->domain) ) { if ( v->arch.paging.mode ) - printk("shadowed %u-on-%u, %stranslated\n", + printk("shadowed %u-on-%u\n", v->arch.paging.mode->guest_levels, - v->arch.paging.mode->shadow.shadow_levels, - paging_vcpu_mode_translate(v) ? "" : "not "); + v->arch.paging.mode->shadow.shadow_levels); else printk("not shadowed\n"); } diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 983d442a6c..b429e99fcf 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -2207,7 +2207,6 @@ static void sh_update_paging_modes(struct vcpu *v) { struct domain *d = v->domain; struct paging_mode *old_mode = v->arch.paging.mode; - mfn_t old_guest_table; ASSERT(shadow_locked_by_me(d)); @@ -2256,7 +2255,6 @@ static void sh_update_paging_modes(struct vcpu *v) #else #error unexpected paging mode #endif - v->arch.paging.translate_enabled = !!shadow_mode_translate(d); } else { @@ -2266,37 +2264,17 @@ static void sh_update_paging_modes(struct vcpu *v) ASSERT(shadow_mode_translate(d)); ASSERT(shadow_mode_external(d)); - v->arch.paging.translate_enabled = hvm_paging_enabled(v); - if ( !v->arch.paging.translate_enabled ) + if ( !hvm_paging_enabled(v) ) { - /* Set v->arch.guest_table to use the p2m map, and choose - * the appropriate shadow mode */ - old_guest_table = pagetable_get_mfn(v->arch.guest_table); -#if CONFIG_PAGING_LEVELS == 2 - v->arch.guest_table = - pagetable_from_pfn(pagetable_get_pfn(d->arch.phys_table)); - v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,2,2); -#elif CONFIG_PAGING_LEVELS == 3 - v->arch.guest_table = - pagetable_from_pfn(pagetable_get_pfn(d->arch.phys_table)); - v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,3,3); -#else /* CONFIG_PAGING_LEVELS == 4 */ - { - l4_pgentry_t *l4e; - /* Use the start of the first l3 table as a PAE l3 */ - ASSERT(pagetable_get_pfn(d->arch.phys_table) != 0); - l4e = sh_map_domain_page(pagetable_get_mfn(d->arch.phys_table)); - ASSERT(l4e_get_flags(l4e[0]) & _PAGE_PRESENT); - v->arch.guest_table = - pagetable_from_pfn(l4e_get_pfn(l4e[0])); - sh_unmap_domain_page(l4e); - } - v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode,3,3); + /* When the guest has CR0.PG clear, we provide a 32-bit, non-PAE + * pagetable for it, mapping 4 GB one-to-one using a single l2 + * page of 1024 superpage mappings */ + v->arch.guest_table = d->arch.paging.shadow.unpaged_pagetable; +#if CONFIG_PAGING_LEVELS >= 3 + v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode, 3, 2); +#else + v->arch.paging.mode = &SHADOW_INTERNAL_NAME(sh_paging_mode, 2, 2); #endif - /* Fix up refcounts on guest_table */ - get_page(mfn_to_page(pagetable_get_mfn(v->arch.guest_table)), d); - if ( mfn_x(old_guest_table) != 0 ) - put_page(mfn_to_page(old_guest_table)); } else { @@ -2428,7 +2406,9 @@ int shadow_enable(struct domain *d, u32 mode) * Returns 0 for success, -errno for failure. */ { unsigned int old_pages; - int rv = 0; + struct page_info *pg = NULL; + uint32_t *e; + int i, rv = 0; mode |= PG_SH_enable; @@ -2469,6 +2449,28 @@ int shadow_enable(struct domain *d, u32 mode) goto out_unlocked; } + /* HVM domains need an extra pagetable for vcpus that think they + * have paging disabled */ + if ( is_hvm_domain(d) ) + { + /* Get a single page from the shadow pool. Take it via the + * P2M interface to make freeing it simpler afterwards. */ + pg = shadow_alloc_p2m_page(d); + if ( pg == NULL ) + { + rv = -ENOMEM; + goto out_unlocked; + } + /* Fill it with 32-bit, non-PAE superpage entries, each mapping 4MB + * of virtual address space onto the same physical address range */ + e = sh_map_domain_page(page_to_mfn(pg)); + for ( i = 0; i < PAGE_SIZE / sizeof(*e); i++ ) + e[i] = ((0x400000U * i) + | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER + | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE); + sh_unmap_domain_page(e); + pg->u.inuse.type_info = PGT_l2_page_table | 1 | PGT_validated; + } shadow_lock(d); @@ -2492,6 +2494,10 @@ int shadow_enable(struct domain *d, u32 mode) d->arch.paging.shadow.opt_flags = SHOPT_LINUX_L3_TOPLEVEL; #endif + /* Record the 1-to-1 pagetable we just made */ + if ( is_hvm_domain(d) ) + d->arch.paging.shadow.unpaged_pagetable = pagetable_from_page(pg); + /* Update the bits */ sh_new_mode(d, mode); @@ -2500,6 +2506,8 @@ int shadow_enable(struct domain *d, u32 mode) out_unlocked: if ( rv != 0 && !pagetable_is_null(d->arch.phys_table) ) p2m_teardown(d); + if ( rv != 0 && pg != NULL ) + shadow_free_p2m_page(d, pg); domain_unpause(d); return rv; } @@ -2579,6 +2587,21 @@ void shadow_teardown(struct domain *d) ASSERT(d->arch.paging.shadow.total_pages == 0); } + /* Free the non-paged-vcpus pagetable; must happen after we've + * destroyed any shadows of it or sh_destroy_shadow will get confused. */ + if ( !pagetable_is_null(d->arch.paging.shadow.unpaged_pagetable) ) + { + for_each_vcpu(d, v) + { + ASSERT(is_hvm_vcpu(v)); + if ( !hvm_paging_enabled(v) ) + v->arch.guest_table = pagetable_null(); + } + shadow_free_p2m_page(d, + pagetable_get_page(d->arch.paging.shadow.unpaged_pagetable)); + d->arch.paging.shadow.unpaged_pagetable = pagetable_null(); + } + /* We leave the "permanent" shadow modes enabled, but clear the * log-dirty mode bit. We don't want any more mark_dirty() * calls now that we've torn down the bitmap */ @@ -2756,10 +2779,6 @@ shadow_write_p2m_entry(struct vcpu *v, unsigned long gfn, /* update the entry with new content */ safe_write_pte(p, new); - /* The P2M can be shadowed: keep the shadows synced */ - if ( d->vcpu[0] != NULL ) - (void)sh_validate_guest_entry(d->vcpu[0], table_mfn, p, sizeof(*p)); - /* install P2M in monitors for PAE Xen */ #if CONFIG_PAGING_LEVELS == 3 if ( level == 3 ) { diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 84857e43e1..34a2d0d074 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -173,9 +173,12 @@ static inline int guest_supports_superpages(struct vcpu *v) { /* The _PAGE_PSE bit must be honoured in HVM guests, whenever - * CR4.PSE is set or the guest is in PAE or long mode */ - return (is_hvm_vcpu(v) && (GUEST_PAGING_LEVELS != 2 - || (v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PSE))); + * CR4.PSE is set or the guest is in PAE or long mode. + * It's also used in the dummy PT for vcpus with CR4.PG cleared. */ + return (is_hvm_vcpu(v) && + (GUEST_PAGING_LEVELS != 2 + || !hvm_paging_enabled(v) + || (v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PSE))); } static inline int @@ -205,8 +208,9 @@ guest_supports_nx(struct vcpu *v) static inline int guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw, int guest_op) { - ASSERT(!guest_op || shadow_locked_by_me(v->domain)); - + struct domain *d = v->domain; + ASSERT(!guest_op || shadow_locked_by_me(d)); + perfc_incr(shadow_guest_walk); memset(gw, 0, sizeof(*gw)); gw->va = va; @@ -219,11 +223,11 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw, int guest_op) + guest_l4_table_offset(va); /* Walk down to the l3e */ if ( !(guest_l4e_get_flags(*gw->l4e) & _PAGE_PRESENT) ) return 0; - gw->l3mfn = vcpu_gfn_to_mfn(v, guest_l4e_get_gfn(*gw->l4e)); + gw->l3mfn = gfn_to_mfn(d, guest_l4e_get_gfn(*gw->l4e)); if ( !mfn_valid(gw->l3mfn) ) return 1; /* This mfn is a pagetable: make sure the guest can't write to it. */ if ( guest_op && sh_remove_write_access(v, gw->l3mfn, 3, va) != 0 ) - flush_tlb_mask(v->domain->domain_dirty_cpumask); + flush_tlb_mask(d->domain_dirty_cpumask); gw->l3e = ((guest_l3e_t *)sh_map_domain_page(gw->l3mfn)) + guest_l3_table_offset(va); #else /* PAE only... */ @@ -232,11 +236,11 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw, int guest_op) #endif /* PAE or 64... */ /* Walk down to the l2e */ if ( !(guest_l3e_get_flags(*gw->l3e) & _PAGE_PRESENT) ) return 0; - gw->l2mfn = vcpu_gfn_to_mfn(v, guest_l3e_get_gfn(*gw->l3e)); + gw->l2mfn = gfn_to_mfn(d, guest_l3e_get_gfn(*gw->l3e)); if ( !mfn_valid(gw->l2mfn) ) return 1; /* This mfn is a pagetable: make sure the guest can't write to it. */ if ( guest_op && sh_remove_write_access(v, gw->l2mfn, 2, va) != 0 ) - flush_tlb_mask(v->domain->domain_dirty_cpumask); + flush_tlb_mask(d->domain_dirty_cpumask); gw->l2e = ((guest_l2e_t *)sh_map_domain_page(gw->l2mfn)) + guest_l2_table_offset(va); #else /* 32-bit only... */ @@ -274,12 +278,12 @@ guest_walk_tables(struct vcpu *v, unsigned long va, walk_t *gw, int guest_op) else { /* Not a superpage: carry on and find the l1e. */ - gw->l1mfn = vcpu_gfn_to_mfn(v, guest_l2e_get_gfn(*gw->l2e)); + gw->l1mfn = gfn_to_mfn(d, guest_l2e_get_gfn(*gw->l2e)); if ( !mfn_valid(gw->l1mfn) ) return 1; /* This mfn is a pagetable: make sure the guest can't write to it. */ if ( guest_op && sh_remove_write_access(v, gw->l1mfn, 1, va) != 0 ) - flush_tlb_mask(v->domain->domain_dirty_cpumask); + flush_tlb_mask(d->domain_dirty_cpumask); gw->l1e = ((guest_l1e_t *)sh_map_domain_page(gw->l1mfn)) + guest_l1_table_offset(va); gw->eff_l1e = *gw->l1e; @@ -2191,6 +2195,7 @@ static int validate_gl4e(struct vcpu *v, void *new_ge, mfn_t sl4mfn, void *se) guest_l4e_t *new_gl4e = new_ge; shadow_l4e_t *sl4p = se; mfn_t sl3mfn = _mfn(INVALID_MFN); + struct domain *d = v->domain; int result = 0; perfc_incr(shadow_validate_gl4e_calls); @@ -2198,7 +2203,7 @@ static int validate_gl4e(struct vcpu *v, void *new_ge, mfn_t sl4mfn, void *se) if ( guest_l4e_get_flags(*new_gl4e) & _PAGE_PRESENT ) { gfn_t gl3gfn = guest_l4e_get_gfn(*new_gl4e); - mfn_t gl3mfn = vcpu_gfn_to_mfn(v, gl3gfn); + mfn_t gl3mfn = gfn_to_mfn(d, gl3gfn); if ( mfn_valid(gl3mfn) ) sl3mfn = get_shadow_status(v, gl3mfn, SH_type_l3_shadow); else @@ -2208,11 +2213,11 @@ static int validate_gl4e(struct vcpu *v, void *new_ge, mfn_t sl4mfn, void *se) sl3mfn, &new_sl4e, ft_prefetch); // check for updates to xen reserved slots - if ( !shadow_mode_external(v->domain) ) + if ( !shadow_mode_external(d) ) { int shadow_index = (((unsigned long)sl4p & ~PAGE_MASK) / sizeof(shadow_l4e_t)); - int reserved_xen_slot = !is_guest_l4_slot(v->domain, shadow_index); + int reserved_xen_slot = !is_guest_l4_slot(d, shadow_index); if ( unlikely(reserved_xen_slot) ) { @@ -2250,7 +2255,7 @@ static int validate_gl3e(struct vcpu *v, void *new_ge, mfn_t sl3mfn, void *se) if ( guest_l3e_get_flags(*new_gl3e) & _PAGE_PRESENT ) { gfn_t gl2gfn = guest_l3e_get_gfn(*new_gl3e); - mfn_t gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn); + mfn_t gl2mfn = gfn_to_mfn(v->domain, gl2gfn); if ( mfn_valid(gl2mfn) ) sl2mfn = get_shadow_status(v, gl2mfn, SH_type_l2_shadow); else @@ -2294,7 +2299,7 @@ static int validate_gl2e(struct vcpu *v, void *new_ge, mfn_t sl2mfn, void *se) } else { - mfn_t gl1mfn = vcpu_gfn_to_mfn(v, gl1gfn); + mfn_t gl1mfn = gfn_to_mfn(v->domain, gl1gfn); if ( mfn_valid(gl1mfn) ) sl1mfn = get_shadow_status(v, gl1mfn, SH_type_l1_shadow); else @@ -2361,10 +2366,9 @@ static int validate_gl1e(struct vcpu *v, void *new_ge, mfn_t sl1mfn, void *se) perfc_incr(shadow_validate_gl1e_calls); gfn = guest_l1e_get_gfn(*new_gl1e); - gmfn = vcpu_gfn_to_mfn(v, gfn); + gmfn = gfn_to_mfn(v->domain, gfn); - mmio = (is_hvm_vcpu(v) && paging_vcpu_mode_translate(v) && - mmio_space(gfn_to_paddr(gfn))); + mmio = (is_hvm_vcpu(v) && mmio_space(gfn_to_paddr(gfn))); l1e_propagate_from_guest(v, new_gl1e, _mfn(INVALID_MFN), gmfn, &new_sl1e, ft_prefetch, mmio); @@ -2593,10 +2597,8 @@ static void sh_prefetch(struct vcpu *v, walk_t *gw, /* Look at the gfn that the l1e is pointing at */ gfn = guest_l1e_get_gfn(gl1e); - gmfn = vcpu_gfn_to_mfn(v, gfn); - mmio = ( is_hvm_vcpu(v) - && paging_vcpu_mode_translate(v) - && mmio_space(gfn_to_paddr(gfn)) ); + gmfn = gfn_to_mfn(v->domain, gfn); + mmio = ( is_hvm_vcpu(v) && mmio_space(gfn_to_paddr(gfn)) ); /* Propagate the entry. Safe to use a pointer to our local * gl1e, since this is not a demand-fetch so there will be no @@ -2657,23 +2659,14 @@ static int sh_page_fault(struct vcpu *v, { if ( sh_l1e_is_gnp(sl1e) ) { - if ( likely(!is_hvm_domain(d) || - paging_vcpu_mode_translate(v)) ) - { - /* Not-present in a guest PT: pass to the guest as - * a not-present fault (by flipping two bits). */ - ASSERT(regs->error_code & PFEC_page_present); - regs->error_code ^= (PFEC_reserved_bit|PFEC_page_present); - reset_early_unshadow(v); - perfc_incr(shadow_fault_fast_gnp); - SHADOW_PRINTK("fast path not-present\n"); - return 0; - } - else - { - /* Not-present in the P2M: MMIO */ - gpa = va; - } + /* Not-present in a guest PT: pass to the guest as + * a not-present fault (by flipping two bits). */ + ASSERT(regs->error_code & PFEC_page_present); + regs->error_code ^= (PFEC_reserved_bit|PFEC_page_present); + reset_early_unshadow(v); + perfc_incr(shadow_fault_fast_gnp); + SHADOW_PRINTK("fast path not-present\n"); + return 0; } else { @@ -2745,13 +2738,6 @@ static int sh_page_fault(struct vcpu *v, // if ( unlikely(!(guest_l1e_get_flags(gw.eff_l1e) & _PAGE_PRESENT)) ) { - if ( is_hvm_domain(d) && !paging_vcpu_mode_translate(v) ) - { - /* Not present in p2m map, means this is mmio */ - gpa = va; - goto mmio; - } - perfc_incr(shadow_fault_bail_not_present); goto not_a_shadow_fault; } @@ -2801,10 +2787,8 @@ static int sh_page_fault(struct vcpu *v, /* What mfn is the guest trying to access? */ gfn = guest_l1e_get_gfn(gw.eff_l1e); - gmfn = vcpu_gfn_to_mfn(v, gfn); - mmio = (is_hvm_domain(d) - && paging_vcpu_mode_translate(v) - && mmio_space(gfn_to_paddr(gfn))); + gmfn = gfn_to_mfn(d, gfn); + mmio = (is_hvm_domain(d) && mmio_space(gfn_to_paddr(gfn))); if ( !mmio && !mfn_valid(gmfn) ) { @@ -3523,20 +3507,18 @@ sh_update_cr3(struct vcpu *v, int do_locking) ASSERT(shadow_mode_external(d)); // Is paging enabled on this vcpu? - if ( paging_vcpu_mode_translate(v) ) + if ( hvm_paging_enabled(v) ) { gfn = _gfn(paddr_to_pfn(v->arch.hvm_vcpu.guest_cr[3])); - gmfn = vcpu_gfn_to_mfn(v, gfn); + gmfn = gfn_to_mfn(d, gfn); ASSERT(mfn_valid(gmfn)); ASSERT(pagetable_get_pfn(v->arch.guest_table) == mfn_x(gmfn)); } else { - /* Paging disabled: guest_table points at (part of) p2m */ -#if SHADOW_PAGING_LEVELS != 3 /* in 3-on-4, guest-table is in slot 0 of p2m */ - /* For everything else, they sould be the same */ - ASSERT(v->arch.guest_table.pfn == d->arch.phys_table.pfn); -#endif + /* Paging disabled: guest_table points at a 32-bit 1-to-1 map */ + ASSERT(v->arch.guest_table.pfn + == d->arch.paging.shadow.unpaged_pagetable.pfn); } } #endif @@ -3574,11 +3556,11 @@ sh_update_cr3(struct vcpu *v, int do_locking) * until the next CR3 write makes us refresh our cache. */ ASSERT(v->arch.paging.shadow.guest_vtable == NULL); - if ( shadow_mode_external(d) && paging_vcpu_mode_translate(v) ) - /* Paging enabled: find where in the page the l3 table is */ + if ( shadow_mode_external(d) ) + /* Find where in the page the l3 table is */ guest_idx = guest_index((void *)v->arch.hvm_vcpu.guest_cr[3]); else - /* Paging disabled or PV: l3 is at the start of a page */ + /* PV guest: l3 is at the start of a page */ guest_idx = 0; // Ignore the low 2 bits of guest_idx -- they are really just @@ -3635,7 +3617,7 @@ sh_update_cr3(struct vcpu *v, int do_locking) if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT ) { gl2gfn = guest_l3e_get_gfn(gl3e[i]); - gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn); + gl2mfn = gfn_to_mfn(d, gl2gfn); flush |= sh_remove_write_access(v, gl2mfn, 2, 0); } } @@ -3647,7 +3629,7 @@ sh_update_cr3(struct vcpu *v, int do_locking) if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT ) { gl2gfn = guest_l3e_get_gfn(gl3e[i]); - gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn); + gl2mfn = gfn_to_mfn(d, gl2gfn); sh_set_toplevel_shadow(v, i, gl2mfn, (i == 3) ? SH_type_l2h_shadow : SH_type_l2_shadow); @@ -4001,7 +3983,7 @@ static inline void * emulate_map_dest(struct vcpu *v, } } #endif - mfn = vcpu_gfn_to_mfn(v, gfn); + mfn = gfn_to_mfn(v->domain, gfn); errcode = PFEC_write_access; if ( !(flags & _PAGE_PRESENT) ) @@ -4268,7 +4250,7 @@ audit_gfn_to_mfn(struct vcpu *v, gfn_t gfn, mfn_t gmfn) != PGT_writable_page ) return _mfn(gfn_x(gfn)); /* This is a paging-disabled shadow */ else - return gfn_to_mfn(v->domain, gfn_x(gfn)); + return gfn_to_mfn(v->domain, gfn); } diff --git a/xen/arch/x86/mm/shadow/private.h b/xen/arch/x86/mm/shadow/private.h index 16aad82075..173520b061 100644 --- a/xen/arch/x86/mm/shadow/private.h +++ b/xen/arch/x86/mm/shadow/private.h @@ -431,6 +431,13 @@ int shadow_cmpxchg_guest_entry(struct vcpu *v, intpte_t *p, #undef mfn_valid #define mfn_valid(_mfn) (mfn_x(_mfn) < max_page) +/* Override pagetable_t <-> struct page_info conversions to work with mfn_t */ +#undef pagetable_get_page +#define pagetable_get_page(x) mfn_to_page(pagetable_get_mfn(x)) +#undef pagetable_from_page +#define pagetable_from_page(pg) pagetable_from_mfn(page_to_mfn(pg)) + + #if GUEST_PAGING_LEVELS >= 3 # define is_lo_pte(_vaddr) (((_vaddr)&0x4)==0) #else diff --git a/xen/arch/x86/mm/shadow/types.h b/xen/arch/x86/mm/shadow/types.h index 1595a25a5b..3985279c06 100644 --- a/xen/arch/x86/mm/shadow/types.h +++ b/xen/arch/x86/mm/shadow/types.h @@ -406,28 +406,17 @@ valid_gfn(gfn_t m) return VALID_GFN(gfn_x(m)); } -/* Translation between mfns and gfns */ - -// vcpu-specific version of gfn_to_mfn(). This is where we hide the dirty -// little secret that, for hvm guests with paging disabled, nearly all of the -// shadow code actually think that the guest is running on *untranslated* page -// tables (which is actually domain->phys_table). -// - -static inline mfn_t -vcpu_gfn_to_mfn(struct vcpu *v, gfn_t gfn) -{ - if ( !paging_vcpu_mode_translate(v) ) - return _mfn(gfn_x(gfn)); - return gfn_to_mfn(v->domain, gfn_x(gfn)); -} - static inline paddr_t gfn_to_paddr(gfn_t gfn) { return ((paddr_t)gfn_x(gfn)) << PAGE_SHIFT; } +/* Override gfn_to_mfn to work with gfn_t */ +#undef gfn_to_mfn +#define gfn_to_mfn(d, g) _gfn_to_mfn((d), gfn_x(g)) + + /* Type used for recording a walk through guest pagetables. It is * filled in by the pagetable walk function, and also used as a cache * for later walks. diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index f8d311a91d..9e7659583d 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -86,6 +86,9 @@ struct shadow_domain { unsigned int free_pages; /* number of pages on freelists */ unsigned int p2m_pages; /* number of pages allocates to p2m */ + /* 1-to-1 map for use when HVM vcpus have paging disabled */ + pagetable_t unpaged_pagetable; + /* Shadow hashtable */ struct shadow_page_info **hash_table; int hash_walking; /* Some function is walking the hash table */ @@ -181,8 +184,6 @@ struct paging_domain { struct paging_vcpu { /* Pointers to mode-specific entry points. */ struct paging_mode *mode; - /* HVM guest: paging enabled (CR0.PG)? */ - unsigned int translate_enabled:1; /* HVM guest: last emulate was to a pagetable */ unsigned int last_write_was_pt:1; /* Translated guest: virtual TLB */ diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index 1863da5c3e..1a82ebafa3 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -61,7 +61,8 @@ static inline mfn_t gfn_to_mfn_current(unsigned long gfn) mfn_t gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn); /* General conversion function from gfn to mfn */ -static inline mfn_t gfn_to_mfn(struct domain *d, unsigned long gfn) +#define gfn_to_mfn(d, g) _gfn_to_mfn((d), (g)) +static inline mfn_t _gfn_to_mfn(struct domain *d, unsigned long gfn) { if ( !paging_mode_translate(d) ) return _mfn(gfn); diff --git a/xen/include/asm-x86/paging.h b/xen/include/asm-x86/paging.h index 35067b289b..842c4c7134 100644 --- a/xen/include/asm-x86/paging.h +++ b/xen/include/asm-x86/paging.h @@ -66,19 +66,6 @@ /* flags used for paging debug */ #define PAGING_DEBUG_LOGDIRTY 0 -/****************************************************************************** - * The equivalent for a particular vcpu of a shadowed domain. */ - -/* Is this vcpu using the P2M table to translate between GFNs and MFNs? - * - * This is true of translated HVM domains on a vcpu which has paging - * enabled. (HVM vcpus with paging disabled are using the p2m table as - * its paging table, so no translation occurs in this case.) - * It is also true for all vcpus of translated PV domains. */ -#define paging_vcpu_mode_translate(_v) ((_v)->arch.paging.translate_enabled) - - - /***************************************************************************** * Mode-specific entry points into the shadow code. * @@ -222,9 +209,6 @@ static inline int paging_invlpg(struct vcpu *v, unsigned long va) #define INVALID_GFN (-1UL) static inline unsigned long paging_gva_to_gfn(struct vcpu *v, unsigned long va) { - if ( unlikely(!paging_vcpu_mode_translate(v)) ) - return va >> PAGE_SHIFT; - return v->arch.paging.mode->gva_to_gfn(v, va); }