|
@@ -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));
|