diff options
Diffstat (limited to 'arch/x86/xen/p2m.c')
| -rw-r--r-- | arch/x86/xen/p2m.c | 43 | 
1 files changed, 33 insertions, 10 deletions
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 8b7f18e200aa..bfc08b13044b 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -79,10 +79,14 @@  #include <xen/balloon.h>  #include <xen/grant_table.h> -#include "p2m.h"  #include "multicalls.h"  #include "xen-ops.h" +#define P2M_MID_PER_PAGE	(PAGE_SIZE / sizeof(unsigned long *)) +#define P2M_TOP_PER_PAGE	(PAGE_SIZE / sizeof(unsigned long **)) + +#define MAX_P2M_PFN	(P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE) +  #define PMDS_PER_MID_PAGE	(P2M_MID_PER_PAGE / PTRS_PER_PTE)  unsigned long *xen_p2m_addr __read_mostly; @@ -199,7 +203,8 @@ void __ref xen_build_mfn_list_list(void)  	unsigned int level, topidx, mididx;  	unsigned long *mid_mfn_p; -	if (xen_feature(XENFEAT_auto_translated_physmap)) +	if (xen_feature(XENFEAT_auto_translated_physmap) || +	    xen_start_info->flags & SIF_VIRT_P2M_4TOOLS)  		return;  	/* Pre-initialize p2m_top_mfn to be completely missing */ @@ -260,9 +265,16 @@ void xen_setup_mfn_list_list(void)  	BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); -	HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = -		virt_to_mfn(p2m_top_mfn); +	if (xen_start_info->flags & SIF_VIRT_P2M_4TOOLS) +		HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = ~0UL; +	else +		HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = +			virt_to_mfn(p2m_top_mfn);  	HYPERVISOR_shared_info->arch.max_pfn = xen_max_p2m_pfn; +	HYPERVISOR_shared_info->arch.p2m_generation = 0; +	HYPERVISOR_shared_info->arch.p2m_vaddr = (unsigned long)xen_p2m_addr; +	HYPERVISOR_shared_info->arch.p2m_cr3 = +		xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));  }  /* Set up p2m_top to point to the domain-builder provided p2m pages */ @@ -478,8 +490,12 @@ static pte_t *alloc_p2m_pmd(unsigned long addr, pte_t *pte_pg)  		ptechk = lookup_address(vaddr, &level);  		if (ptechk == pte_pg) { +			HYPERVISOR_shared_info->arch.p2m_generation++; +			wmb(); /* Tools are synchronizing via p2m_generation. */  			set_pmd(pmdp,  				__pmd(__pa(pte_newpg[i]) | _KERNPG_TABLE)); +			wmb(); /* Tools are synchronizing via p2m_generation. */ +			HYPERVISOR_shared_info->arch.p2m_generation++;  			pte_newpg[i] = NULL;  		} @@ -505,7 +521,7 @@ static pte_t *alloc_p2m_pmd(unsigned long addr, pte_t *pte_pg)   */  static bool alloc_p2m(unsigned long pfn)  { -	unsigned topidx, mididx; +	unsigned topidx;  	unsigned long *top_mfn_p, *mid_mfn;  	pte_t *ptep, *pte_pg;  	unsigned int level; @@ -513,9 +529,6 @@ static bool alloc_p2m(unsigned long pfn)  	unsigned long addr = (unsigned long)(xen_p2m_addr + pfn);  	unsigned long p2m_pfn; -	topidx = p2m_top_index(pfn); -	mididx = p2m_mid_index(pfn); -  	ptep = lookup_address(addr, &level);  	BUG_ON(!ptep || level != PG_LEVEL_4K);  	pte_pg = (pte_t *)((unsigned long)ptep & ~(PAGE_SIZE - 1)); @@ -527,7 +540,8 @@ static bool alloc_p2m(unsigned long pfn)  			return false;  	} -	if (p2m_top_mfn) { +	if (p2m_top_mfn && pfn < MAX_P2M_PFN) { +		topidx = p2m_top_index(pfn);  		top_mfn_p = &p2m_top_mfn[topidx];  		mid_mfn = ACCESS_ONCE(p2m_top_mfn_p[topidx]); @@ -577,10 +591,14 @@ static bool alloc_p2m(unsigned long pfn)  		spin_lock_irqsave(&p2m_update_lock, flags);  		if (pte_pfn(*ptep) == p2m_pfn) { +			HYPERVISOR_shared_info->arch.p2m_generation++; +			wmb(); /* Tools are synchronizing via p2m_generation. */  			set_pte(ptep,  				pfn_pte(PFN_DOWN(__pa(p2m)), PAGE_KERNEL)); +			wmb(); /* Tools are synchronizing via p2m_generation. */ +			HYPERVISOR_shared_info->arch.p2m_generation++;  			if (mid_mfn) -				mid_mfn[mididx] = virt_to_mfn(p2m); +				mid_mfn[p2m_mid_index(pfn)] = virt_to_mfn(p2m);  			p2m = NULL;  		} @@ -630,6 +648,11 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)  		return true;  	} +	/* +	 * The interface requires atomic updates on p2m elements. +	 * xen_safe_write_ulong() is using __put_user which does an atomic +	 * store via asm(). +	 */  	if (likely(!xen_safe_write_ulong(xen_p2m_addr + pfn, mfn)))  		return true;  | 

