From: Chris Lalancette <clalance@redhat.com> Date: Thu, 5 Mar 2009 14:16:05 +0100 Subject: [xen] fix 32-on-64 PV oops in xen_set_pud Message-id: 49AFD095.5080307@redhat.com O-Subject: [RHEL5.4 PATCH]: fix 32-on-64 PV oops in xen_set_pud Bugzilla: 467698 RH-Acked-by: Justin M. Forbes <jforbes@redhat.com> All, With the current 5.3 Xen hypervisor, trying to start certain 32-bit guests (Fedora 10 is one example) will end up crashing the guest during boot. The problem stems from the order in which we are modifying the PTE entries for a guest. In the case of a PTE modification that we care about (changing the RW or PRESENT bits), then we must first "get" the page before we modify the PTE. The following patch is a backport of upstream xen-3.1-testing.hg c/s 15653, and has had good results in the virttest kernels. This should resolve BZ 467698. Please review and ACK. -- Chris Lalancette diff --git a/arch/x86/mm.c b/arch/x86/mm.c index 1d49d4a..452c829 100644 --- a/arch/x86/mm.c +++ b/arch/x86/mm.c @@ -1380,16 +1380,18 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e, return 0; } - adjust_guest_l1e(nl1e, d); - /* Fast path for identical mapping, r/w and presence. */ if ( !l1e_has_changed(ol1e, nl1e, _PAGE_RW | _PAGE_PRESENT) ) + { + adjust_guest_l1e(nl1e, d); return UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, current, preserve_ad); + } if ( unlikely(!get_page_from_l1e(nl1e, FOREIGNDOM)) ) return 0; - + + adjust_guest_l1e(nl1e, d); if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, current, preserve_ad)) ) { @@ -1437,16 +1439,18 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, return 0; } - adjust_guest_l2e(nl2e, d); - /* Fast path for identical mapping and presence. */ if ( !l2e_has_changed(ol2e, nl2e, _PAGE_PRESENT)) - return UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, current, - preserve_ad); + { + adjust_guest_l2e(nl2e, d); + return UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, current, preserve_ad); + } if ( unlikely(!get_page_from_l2e(nl2e, pfn, d)) ) return 0; + adjust_guest_l2e(nl2e, d); + if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, current, preserve_ad)) ) { @@ -1503,16 +1507,18 @@ static int mod_l3_entry(l3_pgentry_t *pl3e, return 0; } - adjust_guest_l3e(nl3e, d); - /* Fast path for identical mapping and presence. */ if (!l3e_has_changed(ol3e, nl3e, _PAGE_PRESENT)) - return UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, current, - preserve_ad); + { + adjust_guest_l3e(nl3e, d); + return UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, current, preserve_ad); + } if ( unlikely(!get_page_from_l3e(nl3e, pfn, d)) ) return 0; + adjust_guest_l3e(nl3e, d); + if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, current, preserve_ad)) ) { @@ -1566,16 +1572,18 @@ static int mod_l4_entry(struct domain *d, return 0; } - adjust_guest_l4e(nl4e, current->domain); - /* Fast path for identical mapping and presence. */ if (!l4e_has_changed(ol4e, nl4e, _PAGE_PRESENT)) - return UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, current, - preserve_ad); + { + adjust_guest_l4e(nl4e, current->domain); + return UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, current, preserve_ad); + } if ( unlikely(!get_page_from_l4e(nl4e, pfn, current->domain)) ) return 0; + adjust_guest_l4e(nl4e, current->domain); + if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, current, preserve_ad)) ) {