diff options
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r-- | arch/x86/mm/pageattr.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 4fadfd2b7017..3bded76e8d5c 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -93,6 +93,18 @@ void arch_report_meminfo(struct seq_file *m) | |||
93 | static inline void split_page_count(int level) { } | 93 | static inline void split_page_count(int level) { } |
94 | #endif | 94 | #endif |
95 | 95 | ||
96 | static inline int | ||
97 | within(unsigned long addr, unsigned long start, unsigned long end) | ||
98 | { | ||
99 | return addr >= start && addr < end; | ||
100 | } | ||
101 | |||
102 | static inline int | ||
103 | within_inclusive(unsigned long addr, unsigned long start, unsigned long end) | ||
104 | { | ||
105 | return addr >= start && addr <= end; | ||
106 | } | ||
107 | |||
96 | #ifdef CONFIG_X86_64 | 108 | #ifdef CONFIG_X86_64 |
97 | 109 | ||
98 | static inline unsigned long highmap_start_pfn(void) | 110 | static inline unsigned long highmap_start_pfn(void) |
@@ -106,20 +118,25 @@ static inline unsigned long highmap_end_pfn(void) | |||
106 | return __pa_symbol(roundup(_brk_end, PMD_SIZE) - 1) >> PAGE_SHIFT; | 118 | return __pa_symbol(roundup(_brk_end, PMD_SIZE) - 1) >> PAGE_SHIFT; |
107 | } | 119 | } |
108 | 120 | ||
109 | #endif | 121 | static bool __cpa_pfn_in_highmap(unsigned long pfn) |
110 | |||
111 | static inline int | ||
112 | within(unsigned long addr, unsigned long start, unsigned long end) | ||
113 | { | 122 | { |
114 | return addr >= start && addr < end; | 123 | /* |
124 | * Kernel text has an alias mapping at a high address, known | ||
125 | * here as "highmap". | ||
126 | */ | ||
127 | return within_inclusive(pfn, highmap_start_pfn(), highmap_end_pfn()); | ||
115 | } | 128 | } |
116 | 129 | ||
117 | static inline int | 130 | #else |
118 | within_inclusive(unsigned long addr, unsigned long start, unsigned long end) | 131 | |
132 | static bool __cpa_pfn_in_highmap(unsigned long pfn) | ||
119 | { | 133 | { |
120 | return addr >= start && addr <= end; | 134 | /* There is no highmap on 32-bit */ |
135 | return false; | ||
121 | } | 136 | } |
122 | 137 | ||
138 | #endif | ||
139 | |||
123 | /* | 140 | /* |
124 | * Flushing functions | 141 | * Flushing functions |
125 | */ | 142 | */ |
@@ -1183,6 +1200,10 @@ static int __cpa_process_fault(struct cpa_data *cpa, unsigned long vaddr, | |||
1183 | cpa->numpages = 1; | 1200 | cpa->numpages = 1; |
1184 | cpa->pfn = __pa(vaddr) >> PAGE_SHIFT; | 1201 | cpa->pfn = __pa(vaddr) >> PAGE_SHIFT; |
1185 | return 0; | 1202 | return 0; |
1203 | |||
1204 | } else if (__cpa_pfn_in_highmap(cpa->pfn)) { | ||
1205 | /* Faults in the highmap are OK, so do not warn: */ | ||
1206 | return -EFAULT; | ||
1186 | } else { | 1207 | } else { |
1187 | WARN(1, KERN_WARNING "CPA: called for zero pte. " | 1208 | WARN(1, KERN_WARNING "CPA: called for zero pte. " |
1188 | "vaddr = %lx cpa->vaddr = %lx\n", vaddr, | 1209 | "vaddr = %lx cpa->vaddr = %lx\n", vaddr, |
@@ -1335,8 +1356,7 @@ static int cpa_process_alias(struct cpa_data *cpa) | |||
1335 | * to touch the high mapped kernel as well: | 1356 | * to touch the high mapped kernel as well: |
1336 | */ | 1357 | */ |
1337 | if (!within(vaddr, (unsigned long)_text, _brk_end) && | 1358 | if (!within(vaddr, (unsigned long)_text, _brk_end) && |
1338 | within_inclusive(cpa->pfn, highmap_start_pfn(), | 1359 | __cpa_pfn_in_highmap(cpa->pfn)) { |
1339 | highmap_end_pfn())) { | ||
1340 | unsigned long temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + | 1360 | unsigned long temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) + |
1341 | __START_KERNEL_map - phys_base; | 1361 | __START_KERNEL_map - phys_base; |
1342 | alias_cpa = *cpa; | 1362 | alias_cpa = *cpa; |