aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-18 18:51:40 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-18 18:51:40 -0500
commit0165d7f476b99eb637027c2f69c365f00260f188 (patch)
tree2369b69095695d1b974a8a2ffa2941d54de5075e
parent20ef0f1ad0035cd7acc6cbcbc018b2dcd891e274 (diff)
parentf6c540cdd65d4bc4eaf4dcbf652580f09f3b0c38 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86
* git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86: x86: fix lguest build failure x86: reenable support for system without on node0 x86: CPA: avoid double checking of alias ranges x86: CPA no alias checking for _NX x86: zap invalid and unused pmds in early boot x86: CPA, fix alias checks
-rw-r--r--arch/x86/kernel/asm-offsets_32.c6
-rw-r--r--arch/x86/kernel/head64.c3
-rw-r--r--arch/x86/kernel/head_64.S7
-rw-r--r--arch/x86/mm/init_64.c27
-rw-r--r--arch/x86/mm/numa_64.c5
-rw-r--r--arch/x86/mm/pageattr.c208
-rw-r--r--include/asm-x86/pgtable_64.h1
7 files changed, 154 insertions, 103 deletions
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index afd84463b712..a33d53017997 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -20,10 +20,8 @@
20 20
21#include <xen/interface/xen.h> 21#include <xen/interface/xen.h>
22 22
23#ifdef CONFIG_LGUEST_GUEST
24#include <linux/lguest.h> 23#include <linux/lguest.h>
25#include "../../../drivers/lguest/lg.h" 24#include "../../../drivers/lguest/lg.h"
26#endif
27 25
28#define DEFINE(sym, val) \ 26#define DEFINE(sym, val) \
29 asm volatile("\n->" #sym " %0 " #val : : "i" (val)) 27 asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -134,6 +132,10 @@ void foo(void)
134 BLANK(); 132 BLANK();
135 OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled); 133 OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
136 OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir); 134 OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir);
135#endif
136
137#ifdef CONFIG_LGUEST
138 BLANK();
137 OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc); 139 OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc);
138 OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc); 140 OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc);
139 OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3); 141 OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3);
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 24dbf56928d7..ad2440832de0 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -88,6 +88,9 @@ void __init x86_64_start_kernel(char * real_mode_data)
88 /* Make NULL pointers segfault */ 88 /* Make NULL pointers segfault */
89 zap_identity_mappings(); 89 zap_identity_mappings();
90 90
91 /* Cleanup the over mapped high alias */
92 cleanup_highmap();
93
91 for (i = 0; i < IDT_ENTRIES; i++) { 94 for (i = 0; i < IDT_ENTRIES; i++) {
92#ifdef CONFIG_EARLY_PRINTK 95#ifdef CONFIG_EARLY_PRINTK
93 set_intr_gate(i, &early_idt_handlers[i]); 96 set_intr_gate(i, &early_idt_handlers[i]);
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 09b38d539b09..53e5820d6054 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -107,8 +107,13 @@ startup_64:
107 movq %rdx, 0(%rbx, %rax, 8) 107 movq %rdx, 0(%rbx, %rax, 8)
108ident_complete: 108ident_complete:
109 109
110 /* Fixup the kernel text+data virtual addresses 110 /*
111 * Fixup the kernel text+data virtual addresses. Note that
112 * we might write invalid pmds, when the kernel is relocated
113 * cleanup_highmap() fixes this up along with the mappings
114 * beyond _end.
111 */ 115 */
116
112 leaq level2_kernel_pgt(%rip), %rdi 117 leaq level2_kernel_pgt(%rip), %rdi
113 leaq 4096(%rdi), %r8 118 leaq 4096(%rdi), %r8
114 /* See if it is a valid page table entry */ 119 /* See if it is a valid page table entry */
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index a4a9cccdd4f2..bb652f5a93fb 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -171,6 +171,33 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
171 __flush_tlb_one(vaddr); 171 __flush_tlb_one(vaddr);
172} 172}
173 173
174/*
175 * The head.S code sets up the kernel high mapping from:
176 * __START_KERNEL_map to __START_KERNEL_map + KERNEL_TEXT_SIZE
177 *
178 * phys_addr holds the negative offset to the kernel, which is added
179 * to the compile time generated pmds. This results in invalid pmds up
180 * to the point where we hit the physaddr 0 mapping.
181 *
182 * We limit the mappings to the region from _text to _end. _end is
183 * rounded up to the 2MB boundary. This catches the invalid pmds as
184 * well, as they are located before _text:
185 */
186void __init cleanup_highmap(void)
187{
188 unsigned long vaddr = __START_KERNEL_map;
189 unsigned long end = round_up((unsigned long)_end, PMD_SIZE) - 1;
190 pmd_t *pmd = level2_kernel_pgt;
191 pmd_t *last_pmd = pmd + PTRS_PER_PMD;
192
193 for (; pmd < last_pmd; pmd++, vaddr += PMD_SIZE) {
194 if (!pmd_present(*pmd))
195 continue;
196 if (vaddr < (unsigned long) _text || vaddr > end)
197 set_pmd(pmd, __pmd(0));
198 }
199}
200
174/* NOTE: this is meant to be run only at boot */ 201/* NOTE: this is meant to be run only at boot */
175void __init 202void __init
176__set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) 203__set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 1aecc658cd7d..59898fb0a4aa 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -494,11 +494,13 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
494 int i; 494 int i;
495 495
496 nodes_clear(node_possible_map); 496 nodes_clear(node_possible_map);
497 nodes_clear(node_online_map);
497 498
498#ifdef CONFIG_NUMA_EMU 499#ifdef CONFIG_NUMA_EMU
499 if (cmdline && !numa_emulation(start_pfn, end_pfn)) 500 if (cmdline && !numa_emulation(start_pfn, end_pfn))
500 return; 501 return;
501 nodes_clear(node_possible_map); 502 nodes_clear(node_possible_map);
503 nodes_clear(node_online_map);
502#endif 504#endif
503 505
504#ifdef CONFIG_ACPI_NUMA 506#ifdef CONFIG_ACPI_NUMA
@@ -506,6 +508,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
506 end_pfn << PAGE_SHIFT)) 508 end_pfn << PAGE_SHIFT))
507 return; 509 return;
508 nodes_clear(node_possible_map); 510 nodes_clear(node_possible_map);
511 nodes_clear(node_online_map);
509#endif 512#endif
510 513
511#ifdef CONFIG_K8_NUMA 514#ifdef CONFIG_K8_NUMA
@@ -513,6 +516,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
513 end_pfn<<PAGE_SHIFT)) 516 end_pfn<<PAGE_SHIFT))
514 return; 517 return;
515 nodes_clear(node_possible_map); 518 nodes_clear(node_possible_map);
519 nodes_clear(node_online_map);
516#endif 520#endif
517 printk(KERN_INFO "%s\n", 521 printk(KERN_INFO "%s\n",
518 numa_off ? "NUMA turned off" : "No NUMA configuration found"); 522 numa_off ? "NUMA turned off" : "No NUMA configuration found");
@@ -524,7 +528,6 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
524 memnode_shift = 63; 528 memnode_shift = 63;
525 memnodemap = memnode.embedded_map; 529 memnodemap = memnode.embedded_map;
526 memnodemap[0] = 0; 530 memnodemap[0] = 0;
527 nodes_clear(node_online_map);
528 node_set_online(0); 531 node_set_online(0);
529 node_set(0, node_possible_map); 532 node_set(0, node_possible_map);
530 for (i = 0; i < NR_CPUS; i++) 533 for (i = 0; i < NR_CPUS; i++)
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 4119379f80ff..3ee14996c829 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -16,6 +16,7 @@
16#include <asm/sections.h> 16#include <asm/sections.h>
17#include <asm/uaccess.h> 17#include <asm/uaccess.h>
18#include <asm/pgalloc.h> 18#include <asm/pgalloc.h>
19#include <asm/proto.h>
19 20
20/* 21/*
21 * The current flushing context - we pass it instead of 5 arguments: 22 * The current flushing context - we pass it instead of 5 arguments:
@@ -26,8 +27,23 @@ struct cpa_data {
26 pgprot_t mask_clr; 27 pgprot_t mask_clr;
27 int numpages; 28 int numpages;
28 int flushtlb; 29 int flushtlb;
30 unsigned long pfn;
29}; 31};
30 32
33#ifdef CONFIG_X86_64
34
35static inline unsigned long highmap_start_pfn(void)
36{
37 return __pa(_text) >> PAGE_SHIFT;
38}
39
40static inline unsigned long highmap_end_pfn(void)
41{
42 return __pa(round_up((unsigned long)_end, PMD_SIZE)) >> PAGE_SHIFT;
43}
44
45#endif
46
31static inline int 47static inline int
32within(unsigned long addr, unsigned long start, unsigned long end) 48within(unsigned long addr, unsigned long start, unsigned long end)
33{ 49{
@@ -123,29 +139,14 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache)
123 } 139 }
124} 140}
125 141
126#define HIGH_MAP_START __START_KERNEL_map
127#define HIGH_MAP_END (__START_KERNEL_map + KERNEL_TEXT_SIZE)
128
129
130/*
131 * Converts a virtual address to a X86-64 highmap address
132 */
133static unsigned long virt_to_highmap(void *address)
134{
135#ifdef CONFIG_X86_64
136 return __pa((unsigned long)address) + HIGH_MAP_START - phys_base;
137#else
138 return (unsigned long)address;
139#endif
140}
141
142/* 142/*
143 * Certain areas of memory on x86 require very specific protection flags, 143 * Certain areas of memory on x86 require very specific protection flags,
144 * for example the BIOS area or kernel text. Callers don't always get this 144 * for example the BIOS area or kernel text. Callers don't always get this
145 * right (again, ioremap() on BIOS memory is not uncommon) so this function 145 * right (again, ioremap() on BIOS memory is not uncommon) so this function
146 * checks and fixes these known static required protection bits. 146 * checks and fixes these known static required protection bits.
147 */ 147 */
148static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) 148static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
149 unsigned long pfn)
149{ 150{
150 pgprot_t forbidden = __pgprot(0); 151 pgprot_t forbidden = __pgprot(0);
151 152
@@ -153,30 +154,23 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
153 * The BIOS area between 640k and 1Mb needs to be executable for 154 * The BIOS area between 640k and 1Mb needs to be executable for
154 * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support. 155 * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support.
155 */ 156 */
156 if (within(__pa(address), BIOS_BEGIN, BIOS_END)) 157 if (within(pfn, BIOS_BEGIN >> PAGE_SHIFT, BIOS_END >> PAGE_SHIFT))
157 pgprot_val(forbidden) |= _PAGE_NX; 158 pgprot_val(forbidden) |= _PAGE_NX;
158 159
159 /* 160 /*
160 * The kernel text needs to be executable for obvious reasons 161 * The kernel text needs to be executable for obvious reasons
161 * Does not cover __inittext since that is gone later on 162 * Does not cover __inittext since that is gone later on. On
163 * 64bit we do not enforce !NX on the low mapping
162 */ 164 */
163 if (within(address, (unsigned long)_text, (unsigned long)_etext)) 165 if (within(address, (unsigned long)_text, (unsigned long)_etext))
164 pgprot_val(forbidden) |= _PAGE_NX; 166 pgprot_val(forbidden) |= _PAGE_NX;
165 /*
166 * Do the same for the x86-64 high kernel mapping
167 */
168 if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext)))
169 pgprot_val(forbidden) |= _PAGE_NX;
170 167
171 /* The .rodata section needs to be read-only */
172 if (within(address, (unsigned long)__start_rodata,
173 (unsigned long)__end_rodata))
174 pgprot_val(forbidden) |= _PAGE_RW;
175 /* 168 /*
176 * Do the same for the x86-64 high kernel mapping 169 * The .rodata section needs to be read-only. Using the pfn
170 * catches all aliases.
177 */ 171 */
178 if (within(address, virt_to_highmap(__start_rodata), 172 if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,
179 virt_to_highmap(__end_rodata))) 173 __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
180 pgprot_val(forbidden) |= _PAGE_RW; 174 pgprot_val(forbidden) |= _PAGE_RW;
181 175
182 prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); 176 prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
@@ -253,7 +247,7 @@ static int
253try_preserve_large_page(pte_t *kpte, unsigned long address, 247try_preserve_large_page(pte_t *kpte, unsigned long address,
254 struct cpa_data *cpa) 248 struct cpa_data *cpa)
255{ 249{
256 unsigned long nextpage_addr, numpages, pmask, psize, flags, addr; 250 unsigned long nextpage_addr, numpages, pmask, psize, flags, addr, pfn;
257 pte_t new_pte, old_pte, *tmp; 251 pte_t new_pte, old_pte, *tmp;
258 pgprot_t old_prot, new_prot; 252 pgprot_t old_prot, new_prot;
259 int i, do_split = 1; 253 int i, do_split = 1;
@@ -301,7 +295,15 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
301 295
302 pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); 296 pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
303 pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); 297 pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
304 new_prot = static_protections(new_prot, address); 298
299 /*
300 * old_pte points to the large page base address. So we need
301 * to add the offset of the virtual address:
302 */
303 pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT);
304 cpa->pfn = pfn;
305
306 new_prot = static_protections(new_prot, address, pfn);
305 307
306 /* 308 /*
307 * We need to check the full range, whether 309 * We need to check the full range, whether
@@ -309,8 +311,9 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
309 * the pages in the range we try to preserve: 311 * the pages in the range we try to preserve:
310 */ 312 */
311 addr = address + PAGE_SIZE; 313 addr = address + PAGE_SIZE;
312 for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE) { 314 pfn++;
313 pgprot_t chk_prot = static_protections(new_prot, addr); 315 for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE, pfn++) {
316 pgprot_t chk_prot = static_protections(new_prot, addr, pfn);
314 317
315 if (pgprot_val(chk_prot) != pgprot_val(new_prot)) 318 if (pgprot_val(chk_prot) != pgprot_val(new_prot))
316 goto out_unlock; 319 goto out_unlock;
@@ -505,46 +508,51 @@ out_unlock:
505 return 0; 508 return 0;
506} 509}
507 510
508static int __change_page_attr(unsigned long address, struct cpa_data *cpa) 511static int __change_page_attr(struct cpa_data *cpa, int primary)
509{ 512{
513 unsigned long address = cpa->vaddr;
510 int do_split, err; 514 int do_split, err;
511 unsigned int level; 515 unsigned int level;
512 struct page *kpte_page; 516 struct page *kpte_page;
513 pte_t *kpte; 517 pte_t *kpte, old_pte;
514 518
515repeat: 519repeat:
516 kpte = lookup_address(address, &level); 520 kpte = lookup_address(address, &level);
517 if (!kpte) 521 if (!kpte)
522 return primary ? -EINVAL : 0;
523
524 old_pte = *kpte;
525 if (!pte_val(old_pte)) {
526 if (!primary)
527 return 0;
528 printk(KERN_WARNING "CPA: called for zero pte. "
529 "vaddr = %lx cpa->vaddr = %lx\n", address,
530 cpa->vaddr);
531 WARN_ON(1);
518 return -EINVAL; 532 return -EINVAL;
533 }
519 534
520 kpte_page = virt_to_page(kpte); 535 kpte_page = virt_to_page(kpte);
521 BUG_ON(PageLRU(kpte_page)); 536 BUG_ON(PageLRU(kpte_page));
522 BUG_ON(PageCompound(kpte_page)); 537 BUG_ON(PageCompound(kpte_page));
523 538
524 if (level == PG_LEVEL_4K) { 539 if (level == PG_LEVEL_4K) {
525 pte_t new_pte, old_pte = *kpte; 540 pte_t new_pte;
526 pgprot_t new_prot = pte_pgprot(old_pte); 541 pgprot_t new_prot = pte_pgprot(old_pte);
527 542 unsigned long pfn = pte_pfn(old_pte);
528 if(!pte_val(old_pte)) {
529 printk(KERN_WARNING "CPA: called for zero pte. "
530 "vaddr = %lx cpa->vaddr = %lx\n", address,
531 cpa->vaddr);
532 WARN_ON(1);
533 return -EINVAL;
534 }
535 543
536 pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); 544 pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
537 pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); 545 pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
538 546
539 new_prot = static_protections(new_prot, address); 547 new_prot = static_protections(new_prot, address, pfn);
540 548
541 /* 549 /*
542 * We need to keep the pfn from the existing PTE, 550 * We need to keep the pfn from the existing PTE,
543 * after all we're only going to change it's attributes 551 * after all we're only going to change it's attributes
544 * not the memory it points to 552 * not the memory it points to
545 */ 553 */
546 new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot)); 554 new_pte = pfn_pte(pfn, canon_pgprot(new_prot));
547 555 cpa->pfn = pfn;
548 /* 556 /*
549 * Do we really change anything ? 557 * Do we really change anything ?
550 */ 558 */
@@ -581,67 +589,59 @@ repeat:
581 return err; 589 return err;
582} 590}
583 591
584/** 592static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias);
585 * change_page_attr_addr - Change page table attributes in linear mapping 593
586 * @address: Virtual address in linear mapping. 594static int cpa_process_alias(struct cpa_data *cpa)
587 * @prot: New page table attribute (PAGE_*)
588 *
589 * Change page attributes of a page in the direct mapping. This is a variant
590 * of change_page_attr() that also works on memory holes that do not have
591 * mem_map entry (pfn_valid() is false).
592 *
593 * See change_page_attr() documentation for more details.
594 *
595 * Modules and drivers should use the set_memory_* APIs instead.
596 */
597static int change_page_attr_addr(struct cpa_data *cpa)
598{ 595{
599 int err; 596 struct cpa_data alias_cpa;
600 unsigned long address = cpa->vaddr; 597 int ret = 0;
601 598
602#ifdef CONFIG_X86_64 599 if (cpa->pfn > max_pfn_mapped)
603 unsigned long phys_addr = __pa(address); 600 return 0;
604 601
605 /* 602 /*
606 * If we are inside the high mapped kernel range, then we 603 * No need to redo, when the primary call touched the direct
607 * fixup the low mapping first. __va() returns the virtual 604 * mapping already:
608 * address in the linear mapping:
609 */ 605 */
610 if (within(address, HIGH_MAP_START, HIGH_MAP_END)) 606 if (!within(cpa->vaddr, PAGE_OFFSET,
611 address = (unsigned long) __va(phys_addr); 607 PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT))) {
612#endif 608
609 alias_cpa = *cpa;
610 alias_cpa.vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT);
613 611
614 err = __change_page_attr(address, cpa); 612 ret = __change_page_attr_set_clr(&alias_cpa, 0);
615 if (err) 613 }
616 return err;
617 614
618#ifdef CONFIG_X86_64 615#ifdef CONFIG_X86_64
616 if (ret)
617 return ret;
618 /*
619 * No need to redo, when the primary call touched the high
620 * mapping already:
621 */
622 if (within(cpa->vaddr, (unsigned long) _text, (unsigned long) _end))
623 return 0;
624
619 /* 625 /*
620 * If the physical address is inside the kernel map, we need 626 * If the physical address is inside the kernel map, we need
621 * to touch the high mapped kernel as well: 627 * to touch the high mapped kernel as well:
622 */ 628 */
623 if (within(phys_addr, 0, KERNEL_TEXT_SIZE)) { 629 if (!within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn()))
624 /* 630 return 0;
625 * Calc the high mapping address. See __phys_addr()
626 * for the non obvious details.
627 *
628 * Note that NX and other required permissions are
629 * checked in static_protections().
630 */
631 address = phys_addr + HIGH_MAP_START - phys_base;
632 631
633 /* 632 alias_cpa = *cpa;
634 * Our high aliases are imprecise, because we check 633 alias_cpa.vaddr =
635 * everything between 0 and KERNEL_TEXT_SIZE, so do 634 (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base;
636 * not propagate lookup failures back to users: 635
637 */ 636 /*
638 __change_page_attr(address, cpa); 637 * The high mapping range is imprecise, so ignore the return value.
639 } 638 */
639 __change_page_attr_set_clr(&alias_cpa, 0);
640#endif 640#endif
641 return err; 641 return ret;
642} 642}
643 643
644static int __change_page_attr_set_clr(struct cpa_data *cpa) 644static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
645{ 645{
646 int ret, numpages = cpa->numpages; 646 int ret, numpages = cpa->numpages;
647 647
@@ -651,10 +651,17 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa)
651 * preservation check. 651 * preservation check.
652 */ 652 */
653 cpa->numpages = numpages; 653 cpa->numpages = numpages;
654 ret = change_page_attr_addr(cpa); 654
655 ret = __change_page_attr(cpa, checkalias);
655 if (ret) 656 if (ret)
656 return ret; 657 return ret;
657 658
659 if (checkalias) {
660 ret = cpa_process_alias(cpa);
661 if (ret)
662 return ret;
663 }
664
658 /* 665 /*
659 * Adjust the number of pages with the result of the 666 * Adjust the number of pages with the result of the
660 * CPA operation. Either a large page has been 667 * CPA operation. Either a large page has been
@@ -677,7 +684,7 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
677 pgprot_t mask_set, pgprot_t mask_clr) 684 pgprot_t mask_set, pgprot_t mask_clr)
678{ 685{
679 struct cpa_data cpa; 686 struct cpa_data cpa;
680 int ret, cache; 687 int ret, cache, checkalias;
681 688
682 /* 689 /*
683 * Check, if we are requested to change a not supported 690 * Check, if we are requested to change a not supported
@@ -703,7 +710,10 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
703 cpa.mask_clr = mask_clr; 710 cpa.mask_clr = mask_clr;
704 cpa.flushtlb = 0; 711 cpa.flushtlb = 0;
705 712
706 ret = __change_page_attr_set_clr(&cpa); 713 /* No alias checking for _NX bit modifications */
714 checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX;
715
716 ret = __change_page_attr_set_clr(&cpa, checkalias);
707 717
708 /* 718 /*
709 * Check whether we really changed something: 719 * Check whether we really changed something:
@@ -841,7 +851,7 @@ static int __set_pages_p(struct page *page, int numpages)
841 .mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW), 851 .mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
842 .mask_clr = __pgprot(0)}; 852 .mask_clr = __pgprot(0)};
843 853
844 return __change_page_attr_set_clr(&cpa); 854 return __change_page_attr_set_clr(&cpa, 1);
845} 855}
846 856
847static int __set_pages_np(struct page *page, int numpages) 857static int __set_pages_np(struct page *page, int numpages)
@@ -851,7 +861,7 @@ static int __set_pages_np(struct page *page, int numpages)
851 .mask_set = __pgprot(0), 861 .mask_set = __pgprot(0),
852 .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)}; 862 .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)};
853 863
854 return __change_page_attr_set_clr(&cpa); 864 return __change_page_attr_set_clr(&cpa, 1);
855} 865}
856 866
857void kernel_map_pages(struct page *page, int numpages, int enable) 867void kernel_map_pages(struct page *page, int numpages, int enable)
diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h
index bd4740a60f29..7fd5e0e2361e 100644
--- a/include/asm-x86/pgtable_64.h
+++ b/include/asm-x86/pgtable_64.h
@@ -246,6 +246,7 @@ static inline int pud_large(pud_t pte)
246#define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) 246#define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val })
247 247
248extern int kern_addr_valid(unsigned long addr); 248extern int kern_addr_valid(unsigned long addr);
249extern void cleanup_highmap(void);
249 250
250#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ 251#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
251 remap_pfn_range(vma, vaddr, pfn, size, prot) 252 remap_pfn_range(vma, vaddr, pfn, size, prot)