diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /arch/x86/mm/pageattr.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r-- | arch/x86/mm/pageattr.c | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index dd38bfbefd1f..28195c350b97 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -6,13 +6,13 @@ | |||
6 | #include <linux/bootmem.h> | 6 | #include <linux/bootmem.h> |
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
9 | #include <linux/slab.h> | ||
10 | #include <linux/mm.h> | 9 | #include <linux/mm.h> |
11 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
12 | #include <linux/seq_file.h> | 11 | #include <linux/seq_file.h> |
13 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
14 | #include <linux/pfn.h> | 13 | #include <linux/pfn.h> |
15 | #include <linux/percpu.h> | 14 | #include <linux/percpu.h> |
15 | #include <linux/gfp.h> | ||
16 | 16 | ||
17 | #include <asm/e820.h> | 17 | #include <asm/e820.h> |
18 | #include <asm/processor.h> | 18 | #include <asm/processor.h> |
@@ -279,6 +279,43 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, | |||
279 | __pa((unsigned long)__end_rodata) >> PAGE_SHIFT)) | 279 | __pa((unsigned long)__end_rodata) >> PAGE_SHIFT)) |
280 | pgprot_val(forbidden) |= _PAGE_RW; | 280 | pgprot_val(forbidden) |= _PAGE_RW; |
281 | 281 | ||
282 | #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) | ||
283 | /* | ||
284 | * Once the kernel maps the text as RO (kernel_set_to_readonly is set), | ||
285 | * kernel text mappings for the large page aligned text, rodata sections | ||
286 | * will be always read-only. For the kernel identity mappings covering | ||
287 | * the holes caused by this alignment can be anything that user asks. | ||
288 | * | ||
289 | * This will preserve the large page mappings for kernel text/data | ||
290 | * at no extra cost. | ||
291 | */ | ||
292 | if (kernel_set_to_readonly && | ||
293 | within(address, (unsigned long)_text, | ||
294 | (unsigned long)__end_rodata_hpage_align)) { | ||
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 | } | ||
317 | #endif | ||
318 | |||
282 | prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); | 319 | prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); |
283 | 320 | ||
284 | return prot; | 321 | return prot; |
@@ -1069,12 +1106,18 @@ EXPORT_SYMBOL(set_memory_array_wb); | |||
1069 | 1106 | ||
1070 | int set_memory_x(unsigned long addr, int numpages) | 1107 | int set_memory_x(unsigned long addr, int numpages) |
1071 | { | 1108 | { |
1109 | if (!(__supported_pte_mask & _PAGE_NX)) | ||
1110 | return 0; | ||
1111 | |||
1072 | return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_NX), 0); | 1112 | return change_page_attr_clear(&addr, numpages, __pgprot(_PAGE_NX), 0); |
1073 | } | 1113 | } |
1074 | EXPORT_SYMBOL(set_memory_x); | 1114 | EXPORT_SYMBOL(set_memory_x); |
1075 | 1115 | ||
1076 | int set_memory_nx(unsigned long addr, int numpages) | 1116 | int set_memory_nx(unsigned long addr, int numpages) |
1077 | { | 1117 | { |
1118 | if (!(__supported_pte_mask & _PAGE_NX)) | ||
1119 | return 0; | ||
1120 | |||
1078 | return change_page_attr_set(&addr, numpages, __pgprot(_PAGE_NX), 0); | 1121 | return change_page_attr_set(&addr, numpages, __pgprot(_PAGE_NX), 0); |
1079 | } | 1122 | } |
1080 | EXPORT_SYMBOL(set_memory_nx); | 1123 | EXPORT_SYMBOL(set_memory_nx); |