diff options
-rw-r--r-- | arch/x86/mm/pageattr.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 1d4eb93d333c..cf07c26d9a4a 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -291,8 +291,29 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, | |||
291 | */ | 291 | */ |
292 | if (kernel_set_to_readonly && | 292 | if (kernel_set_to_readonly && |
293 | within(address, (unsigned long)_text, | 293 | within(address, (unsigned long)_text, |
294 | (unsigned long)__end_rodata_hpage_align)) | 294 | (unsigned long)__end_rodata_hpage_align)) { |
295 | pgprot_val(forbidden) |= _PAGE_RW; | 295 | unsigned int level; |
296 | |||
297 | /* | ||
298 | * Don't enforce the !RW mapping for the kernel text mapping, | ||
299 | * if the current mapping is already using small page mapping. | ||
300 | * No need to work hard to preserve large page mappings in this | ||
301 | * case. | ||
302 | * | ||
303 | * This also fixes the Linux Xen paravirt guest boot failure | ||
304 | * (because of unexpected read-only mappings for kernel identity | ||
305 | * mappings). In this paravirt guest case, the kernel text | ||
306 | * mapping and the kernel identity mapping share the same | ||
307 | * page-table pages. Thus we can't really use different | ||
308 | * protections for the kernel text and identity mappings. Also, | ||
309 | * these shared mappings are made of small page mappings. | ||
310 | * Thus this don't enforce !RW mapping for small page kernel | ||
311 | * text mapping logic will help Linux Xen parvirt guest boot | ||
312 | * aswell. | ||
313 | */ | ||
314 | if (lookup_address(address, &level) && (level != PG_LEVEL_4K)) | ||
315 | pgprot_val(forbidden) |= _PAGE_RW; | ||
316 | } | ||
296 | #endif | 317 | #endif |
297 | 318 | ||
298 | prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); | 319 | prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); |