diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index 6e4e375bad..00fb82d576 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -657,6 +657,9 @@ bool_t ept_handle_misconfig(uint64_t gpa) bool_t spurious; int rc; + if ( altp2m_active(curr->domain) ) + p2m = p2m_get_altp2m(curr); + p2m_lock(p2m); spurious = curr->arch.hvm.vmx.ept_spurious_misconfig; @@ -1416,9 +1419,13 @@ void p2m_init_altp2m_ept(struct domain *d, unsigned int i) struct p2m_domain *hostp2m = p2m_get_hostp2m(d); struct ept_data *ept; + p2m->default_access = hostp2m->default_access; + p2m->domain = hostp2m->domain; + + p2m->global_logdirty = hostp2m->global_logdirty; p2m->ept.ad = hostp2m->ept.ad; p2m->min_remapped_gfn = gfn_x(INVALID_GFN); - p2m->max_remapped_gfn = 0; + p2m->max_mapped_pfn = p2m->max_remapped_gfn = 0; ept = &p2m->ept; ept->mfn = pagetable_get_pfn(p2m_get_pagetable(p2m)); d->arch.altp2m_eptp[i] = ept->eptp; diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c index 17a6b61f12..b5c19dfe3a 100644 --- a/xen/arch/x86/mm/p2m-pt.c +++ b/xen/arch/x86/mm/p2m-pt.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -464,6 +465,13 @@ int p2m_pt_handle_deferred_changes(uint64_t gpa) struct p2m_domain *p2m = p2m_get_hostp2m(current->domain); int rc; + /* + * Should altp2m ever be enabled for NPT / shadow use, this code + * should be updated to make use of the active altp2m, like + * ept_handle_misconfig(). + */ + ASSERT(!altp2m_active(current->domain)); + p2m_lock(p2m); rc = do_recalc(p2m, PFN_DOWN(gpa)); p2m_unlock(p2m); diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 7c6aae76b7..d145850c82 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -277,7 +277,6 @@ int p2m_init(struct domain *d) int p2m_is_logdirty_range(struct p2m_domain *p2m, unsigned long start, unsigned long end) { - ASSERT(p2m_is_hostp2m(p2m)); if ( p2m->global_logdirty || rangeset_contains_range(p2m->logdirty_ranges, start, end) ) return 1; @@ -286,31 +285,79 @@ int p2m_is_logdirty_range(struct p2m_domain *p2m, unsigned long start, return 0; } +static void change_entry_type_global(struct p2m_domain *p2m, + p2m_type_t ot, p2m_type_t nt) +{ + p2m->change_entry_type_global(p2m, ot, nt); + p2m->global_logdirty = (nt == p2m_ram_logdirty); +} + void p2m_change_entry_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); + struct p2m_domain *hostp2m = p2m_get_hostp2m(d); ASSERT(ot != nt); ASSERT(p2m_is_changeable(ot) && p2m_is_changeable(nt)); - p2m_lock(p2m); - p2m->change_entry_type_global(p2m, ot, nt); - p2m->global_logdirty = (nt == p2m_ram_logdirty); - p2m_unlock(p2m); + p2m_lock(hostp2m); + + change_entry_type_global(hostp2m, ot, nt); + +#ifdef CONFIG_HVM + if ( unlikely(altp2m_active(d)) ) + { + unsigned int i; + + for ( i = 0; i < MAX_ALTP2M; i++ ) + if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) + { + struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + + p2m_lock(altp2m); + change_entry_type_global(altp2m, ot, nt); + p2m_unlock(altp2m); + } + } +#endif + + p2m_unlock(hostp2m); +} + +#ifdef CONFIG_HVM +/* There's already a memory_type_changed() in asm/mtrr.h. */ +static void _memory_type_changed(struct p2m_domain *p2m) +{ + if ( p2m->memory_type_changed ) + p2m->memory_type_changed(p2m); } void p2m_memory_type_changed(struct domain *d) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); + struct p2m_domain *hostp2m = p2m_get_hostp2m(d); - if ( p2m->memory_type_changed ) + p2m_lock(hostp2m); + + _memory_type_changed(hostp2m); + + if ( unlikely(altp2m_active(d)) ) { - p2m_lock(p2m); - p2m->memory_type_changed(p2m); - p2m_unlock(p2m); + unsigned int i; + + for ( i = 0; i < MAX_ALTP2M; i++ ) + if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) + { + struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + + p2m_lock(altp2m); + _memory_type_changed(altp2m); + p2m_unlock(altp2m); + } } + + p2m_unlock(hostp2m); } +#endif int p2m_set_ioreq_server(struct domain *d, unsigned int flags, @@ -956,20 +1003,14 @@ int p2m_change_type_one(struct domain *d, unsigned long gfn_l, } /* Modify the p2m type of a range of gfns from ot to nt. */ -void p2m_change_type_range(struct domain *d, - unsigned long start, unsigned long end, - p2m_type_t ot, p2m_type_t nt) +static void change_type_range(struct p2m_domain *p2m, + unsigned long start, unsigned long end, + p2m_type_t ot, p2m_type_t nt) { unsigned long gfn = start; - struct p2m_domain *p2m = p2m_get_hostp2m(d); + struct domain *d = p2m->domain; int rc = 0; - ASSERT(ot != nt); - ASSERT(p2m_is_changeable(ot) && p2m_is_changeable(nt)); - - p2m_lock(p2m); - p2m->defer_nested_flush = 1; - if ( unlikely(end > p2m->max_mapped_pfn) ) { if ( !gfn ) @@ -1007,27 +1048,58 @@ void p2m_change_type_range(struct domain *d, rc, d->domain_id); domain_crash(d); } +} - p2m->defer_nested_flush = 0; +void p2m_change_type_range(struct domain *d, + unsigned long start, unsigned long end, + p2m_type_t ot, p2m_type_t nt) +{ + struct p2m_domain *hostp2m = p2m_get_hostp2m(d); + + ASSERT(ot != nt); + ASSERT(p2m_is_changeable(ot) && p2m_is_changeable(nt)); + + p2m_lock(hostp2m); + hostp2m->defer_nested_flush = 1; + + change_type_range(hostp2m, start, end, ot, nt); + +#ifdef CONFIG_HVM + if ( unlikely(altp2m_active(d)) ) + { + unsigned int i; + + for ( i = 0; i < MAX_ALTP2M; i++ ) + if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) + { + struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + + p2m_lock(altp2m); + change_type_range(altp2m, start, end, ot, nt); + p2m_unlock(altp2m); + } + } +#endif + hostp2m->defer_nested_flush = 0; if ( nestedhvm_enabled(d) ) p2m_flush_nestedp2m(d); - p2m_unlock(p2m); + + p2m_unlock(hostp2m); } /* * Finish p2m type change for gfns which are marked as need_recalc in a range. + * Uses the current p2m's max_mapped_pfn to further clip the invalidation + * range for alternate p2ms. * Returns: 0/1 for success, negative for failure */ -int p2m_finish_type_change(struct domain *d, - gfn_t first_gfn, unsigned long max_nr) +static int finish_type_change(struct p2m_domain *p2m, + gfn_t first_gfn, unsigned long max_nr) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); unsigned long gfn = gfn_x(first_gfn); unsigned long last_gfn = gfn + max_nr - 1; int rc = 0; - p2m_lock(p2m); - last_gfn = min(last_gfn, p2m->max_mapped_pfn); while ( gfn <= last_gfn ) { @@ -1042,14 +1114,51 @@ int p2m_finish_type_change(struct domain *d, else if ( rc < 0 ) { gdprintk(XENLOG_ERR, "p2m->recalc failed! Dom%d gfn=%lx\n", - d->domain_id, gfn); + p2m->domain->domain_id, gfn); break; } gfn++; } - p2m_unlock(p2m); + return rc; +} + +int p2m_finish_type_change(struct domain *d, + gfn_t first_gfn, unsigned long max_nr) +{ + struct p2m_domain *hostp2m = p2m_get_hostp2m(d); + int rc; + + p2m_lock(hostp2m); + + rc = finish_type_change(hostp2m, first_gfn, max_nr); + + if ( !rc ) + goto out; + +#ifdef CONFIG_HVM + if ( unlikely(altp2m_active(d)) ) + { + unsigned int i; + + for ( i = 0; i < MAX_ALTP2M; i++ ) + if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) + { + struct p2m_domain *altp2m = d->arch.altp2m_p2m[i]; + + p2m_lock(altp2m); + rc = finish_type_change(altp2m, first_gfn, max_nr); + p2m_unlock(altp2m); + + if ( !rc ) + goto out; + } + } +#endif + +out: + p2m_unlock(hostp2m); return rc; } diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index 3304921991..2095076556 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -626,9 +626,6 @@ int p2m_finish_type_change(struct domain *d, gfn_t first_gfn, unsigned long max_nr); -/* Report a change affecting memory types. */ -void p2m_memory_type_changed(struct domain *d); - int p2m_is_logdirty_range(struct p2m_domain *, unsigned long start, unsigned long end); @@ -659,6 +656,9 @@ void p2m_pod_dump_data(struct domain *d); #ifdef CONFIG_HVM +/* Report a change affecting memory types. */ +void p2m_memory_type_changed(struct domain *d); + /* Called by p2m code when demand-populating a PoD page */ bool p2m_pod_demand_populate(struct p2m_domain *p2m, gfn_t gfn, unsigned int order);