diff options
Diffstat (limited to 'arch/x86/mm/pageattr.c')
| -rw-r--r-- | arch/x86/mm/pageattr.c | 27 | 
1 files changed, 24 insertions, 3 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 1d4eb93d333..28195c350b9 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -6,13 +6,13 @@  #include <linux/bootmem.h>  #include <linux/module.h>  #include <linux/sched.h> -#include <linux/slab.h>  #include <linux/mm.h>  #include <linux/interrupt.h>  #include <linux/seq_file.h>  #include <linux/debugfs.h>  #include <linux/pfn.h>  #include <linux/percpu.h> +#include <linux/gfp.h>  #include <asm/e820.h>  #include <asm/processor.h> @@ -291,8 +291,29 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,  	 */  	if (kernel_set_to_readonly &&  	    within(address, (unsigned long)_text, -		   (unsigned long)__end_rodata_hpage_align)) -		pgprot_val(forbidden) |= _PAGE_RW; +		   (unsigned long)__end_rodata_hpage_align)) { +		unsigned int level; + +		/* +		 * Don't enforce the !RW mapping for the kernel text mapping, +		 * if the current mapping is already using small page mapping. +		 * No need to work hard to preserve large page mappings in this +		 * case. +		 * +		 * This also fixes the Linux Xen paravirt guest boot failure +		 * (because of unexpected read-only mappings for kernel identity +		 * mappings). In this paravirt guest case, the kernel text +		 * mapping and the kernel identity mapping share the same +		 * page-table pages. Thus we can't really use different +		 * protections for the kernel text and identity mappings. Also, +		 * these shared mappings are made of small page mappings. +		 * Thus this don't enforce !RW mapping for small page kernel +		 * text mapping logic will help Linux Xen parvirt guest boot +		 * aswell. +		 */ +		if (lookup_address(address, &level) && (level != PG_LEVEL_4K)) +			pgprot_val(forbidden) |= _PAGE_RW; +	}  #endif  	prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));  |