[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC] x86/altp2m: fix display frozen when switching to a new view early
When an new altp2m view is created very early on guest boot, the display will freeze (although the guest will run normally). This may also happen on resizing the display. The reason is the way Xen currently (mis)handles logdirty VGA: it intentionally misconfigures VGA pages so that they will fault. The problem is that it only does this in the host p2m. Once we switch to a new altp2m, the misconfigured entries will no longer fault, so the display will not be updated. This patch: * updates ept_handle_misconfig() to use the active altp2m instead of the hostp2m; * has p2m_init_altp2m_ept() copy over max_mapped_pfn, logdirty_ranges, global_logdirty, ept.ad and default_access from the hostp2m (the latter more for completeness than for any other reason). We should discuss if just copying over logdirty_ranges (which is a pointer) is sufficient, or if this code requires more synchronization). Also, it's worth clarifying if these variables (and which of them) should be copied over from the hostp2m or the currently active p2m; * modifies p2m_change_entry_type_global() and p2m_change_type_range() to propagate their changes to all valid altp2ms. Another aspect is that, while new modifications should work with these changes, _old_ modifications (written to the host2pm _before_ we've created the new altp2m) will, if I understand the code correctly be lost. That is to say, misconfigurations performed before p2m_init_altp2m_ept() in the hostp2m will presumably not trigger the necessary faults after switching to the new altp2m. Signed-off-by: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> --- xen/arch/x86/mm/p2m-ept.c | 53 +++++++++++++++++++++++++++++++++++++++++------ xen/arch/x86/mm/p2m.c | 49 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 87 insertions(+), 15 deletions(-) diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index 14b5939..76de6b3 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -17,6 +17,7 @@ #include <xen/domain_page.h> #include <xen/sched.h> +#include <asm/altp2m.h> #include <asm/current.h> #include <asm/paging.h> #include <asm/types.h> @@ -656,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; @@ -1209,32 +1213,60 @@ static void ept_tlb_flush(struct p2m_domain *p2m) static void ept_enable_pml(struct p2m_domain *p2m) { + unsigned int i; + struct domain *d = p2m->domain; + /* Domain must have been paused */ - ASSERT(atomic_read(&p2m->domain->pause_count)); + ASSERT(atomic_read(&d->pause_count)); /* * No need to return whether vmx_domain_enable_pml has succeeded, as * ept_p2m_type_to_flags will do the check, and write protection will be * used if PML is not enabled. */ - if ( vmx_domain_enable_pml(p2m->domain) ) + if ( vmx_domain_enable_pml(d) ) return; /* Enable EPT A/D bit for PML */ p2m->ept.ad = 1; - vmx_domain_update_eptp(p2m->domain); + + if ( altp2m_active(d) ) + for ( i = 0; i < MAX_ALTP2M; i++ ) + { + if ( d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) + continue; + + p2m = d->arch.altp2m_p2m[i]; + p2m->ept.ad = 1; + } + + vmx_domain_update_eptp(d); } static void ept_disable_pml(struct p2m_domain *p2m) { + unsigned int i; + struct domain *d = p2m->domain; + /* Domain must have been paused */ - ASSERT(atomic_read(&p2m->domain->pause_count)); + ASSERT(atomic_read(&d->pause_count)); - vmx_domain_disable_pml(p2m->domain); + vmx_domain_disable_pml(d); /* Disable EPT A/D bit */ p2m->ept.ad = 0; - vmx_domain_update_eptp(p2m->domain); + + if ( altp2m_active(d) ) + for ( i = 0; i < MAX_ALTP2M; i++ ) + { + if ( d->arch.altp2m_eptp[i] == mfn_x(INVALID_MFN) ) + continue; + + p2m = d->arch.altp2m_p2m[i]; + p2m->ept.ad = 0; + } + + vmx_domain_update_eptp(d); } static void ept_flush_pml_buffers(struct p2m_domain *p2m) @@ -1375,11 +1407,20 @@ void setup_ept_dump(void) void p2m_init_altp2m_ept(struct domain *d, unsigned int i) { struct p2m_domain *p2m = d->arch.altp2m_p2m[i]; + struct p2m_domain *hostp2m = p2m_get_hostp2m(d); struct ept_data *ept; + p2m->max_mapped_pfn = hostp2m->max_mapped_pfn; + p2m->default_access = hostp2m->default_access; + p2m->domain = hostp2m->domain; + p2m->logdirty_ranges = hostp2m->logdirty_ranges; + 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; 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.c b/xen/arch/x86/mm/p2m.c index 6020553..bbbc0bf 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -28,6 +28,7 @@ #include <xen/vm_event.h> #include <xen/event.h> #include <public/vm_event.h> +#include <asm/altp2m.h> #include <asm/domain.h> #include <asm/page.h> #include <asm/paging.h> @@ -249,7 +250,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; @@ -258,11 +258,9 @@ int p2m_is_logdirty_range(struct p2m_domain *p2m, unsigned long start, return 0; } -void p2m_change_entry_type_global(struct domain *d, - p2m_type_t ot, p2m_type_t nt) +static void _p2m_change_entry_type_global(struct p2m_domain *p2m, + p2m_type_t ot, p2m_type_t nt) { - struct p2m_domain *p2m = p2m_get_hostp2m(d); - ASSERT(ot != nt); ASSERT(p2m_is_changeable(ot) && p2m_is_changeable(nt)); @@ -272,6 +270,22 @@ void p2m_change_entry_type_global(struct domain *d, p2m_unlock(p2m); } +void p2m_change_entry_type_global(struct domain *d, + p2m_type_t ot, p2m_type_t nt) +{ + unsigned int i; + + if ( !altp2m_active(d) ) + { + _p2m_change_entry_type_global(p2m_get_hostp2m(d), ot, nt); + return; + } + + for ( i = 0; i < MAX_ALTP2M; i++ ) + if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) + _p2m_change_entry_type_global(d->arch.altp2m_p2m[i], ot, nt); +} + void p2m_memory_type_changed(struct domain *d) { struct p2m_domain *p2m = p2m_get_hostp2m(d); @@ -965,12 +979,12 @@ 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 _p2m_change_type_range(struct p2m_domain *p2m, + unsigned long start, unsigned long end, + p2m_type_t ot, p2m_type_t nt) { + struct domain *d = p2m->domain; unsigned long gfn = start; - struct p2m_domain *p2m = p2m_get_hostp2m(d); int rc = 0; ASSERT(ot != nt); @@ -1023,6 +1037,23 @@ void p2m_change_type_range(struct domain *d, p2m_unlock(p2m); } +void p2m_change_type_range(struct domain *d, + unsigned long start, unsigned long end, + p2m_type_t ot, p2m_type_t nt) +{ + unsigned int i; + + if ( !altp2m_active(d) ) + { + _p2m_change_type_range(p2m_get_hostp2m(d), start, end, ot, nt); + return; + } + + for ( i = 0; i < MAX_ALTP2M; i++ ) + if ( d->arch.altp2m_eptp[i] != mfn_x(INVALID_MFN) ) + _p2m_change_type_range(d->arch.altp2m_p2m[i], start, end, ot, nt); +} + /* * Finish p2m type change for gfns which are marked as need_recalc in a range. * Returns: 0/1 for success, negative for failure -- 2.7.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |