aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/pageattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r--arch/x86/mm/pageattr.c96
1 files changed, 54 insertions, 42 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index a2d747c06147..23f0aa3d01c1 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -228,7 +228,6 @@ repeat:
228/** 228/**
229 * change_page_attr_addr - Change page table attributes in linear mapping 229 * change_page_attr_addr - Change page table attributes in linear mapping
230 * @address: Virtual address in linear mapping. 230 * @address: Virtual address in linear mapping.
231 * @numpages: Number of pages to change
232 * @prot: New page table attribute (PAGE_*) 231 * @prot: New page table attribute (PAGE_*)
233 * 232 *
234 * Change page attributes of a page in the direct mapping. This is a variant 233 * Change page attributes of a page in the direct mapping. This is a variant
@@ -240,10 +239,10 @@ repeat:
240 * Modules and drivers should use the set_memory_* APIs instead. 239 * Modules and drivers should use the set_memory_* APIs instead.
241 */ 240 */
242 241
243static int change_page_attr_addr(unsigned long address, int numpages, 242static int change_page_attr_addr(unsigned long address, pgprot_t prot)
244 pgprot_t prot)
245{ 243{
246 int err = 0, kernel_map = 0, i; 244 int err = 0, kernel_map = 0;
245 unsigned long pfn = __pa(address) >> PAGE_SHIFT;
247 246
248#ifdef CONFIG_X86_64 247#ifdef CONFIG_X86_64
249 if (address >= __START_KERNEL_map && 248 if (address >= __START_KERNEL_map &&
@@ -254,30 +253,27 @@ static int change_page_attr_addr(unsigned long address, int numpages,
254 } 253 }
255#endif 254#endif
256 255
257 for (i = 0; i < numpages; i++, address += PAGE_SIZE) { 256 if (!kernel_map || pte_present(pfn_pte(0, prot))) {
258 unsigned long pfn = __pa(address) >> PAGE_SHIFT; 257 err = __change_page_attr(address, pfn, prot);
258 if (err)
259 return err;
260 }
259 261
260 if (!kernel_map || pte_present(pfn_pte(0, prot))) {
261 err = __change_page_attr(address, pfn, prot);
262 if (err)
263 break;
264 }
265#ifdef CONFIG_X86_64 262#ifdef CONFIG_X86_64
266 /* 263 /*
267 * Handle kernel mapping too which aliases part of 264 * Handle kernel mapping too which aliases part of
268 * lowmem: 265 * lowmem:
269 */ 266 */
270 if (__pa(address) < KERNEL_TEXT_SIZE) { 267 if (__pa(address) < KERNEL_TEXT_SIZE) {
271 unsigned long addr2; 268 unsigned long addr2;
272 pgprot_t prot2; 269 pgprot_t prot2;
273 270
274 addr2 = __START_KERNEL_map + __pa(address); 271 addr2 = __START_KERNEL_map + __pa(address);
275 /* Make sure the kernel mappings stay executable */ 272 /* Make sure the kernel mappings stay executable */
276 prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot))); 273 prot2 = pte_pgprot(pte_mkexec(pfn_pte(0, prot)));
277 err = __change_page_attr(addr2, pfn, prot2); 274 err = __change_page_attr(addr2, pfn, prot2);
278 }
279#endif
280 } 275 }
276#endif
281 277
282 return err; 278 return err;
283} 279}
@@ -307,16 +303,24 @@ static int change_page_attr_set(unsigned long addr, int numpages,
307 pgprot_t current_prot; 303 pgprot_t current_prot;
308 int level; 304 int level;
309 pte_t *pte; 305 pte_t *pte;
306 int i, ret;
310 307
311 pte = lookup_address(addr, &level); 308 for (i = 0; i < numpages ; i++) {
312 if (pte)
313 current_prot = pte_pgprot(*pte);
314 else
315 pgprot_val(current_prot) = 0;
316 309
317 pgprot_val(prot) = pgprot_val(current_prot) | pgprot_val(prot); 310 pte = lookup_address(addr, &level);
311 if (pte)
312 current_prot = pte_pgprot(*pte);
313 else
314 pgprot_val(current_prot) = 0;
318 315
319 return change_page_attr_addr(addr, numpages, prot); 316 pgprot_val(prot) = pgprot_val(current_prot) | pgprot_val(prot);
317
318 ret = change_page_attr_addr(addr, prot);
319 if (ret)
320 return ret;
321 addr += PAGE_SIZE;
322 }
323 return 0;
320} 324}
321 325
322/** 326/**
@@ -344,16 +348,24 @@ static int change_page_attr_clear(unsigned long addr, int numpages,
344 pgprot_t current_prot; 348 pgprot_t current_prot;
345 int level; 349 int level;
346 pte_t *pte; 350 pte_t *pte;
347 351 int i, ret;
348 pte = lookup_address(addr, &level); 352
349 if (pte) 353 for (i = 0; i < numpages; i++) {
350 current_prot = pte_pgprot(*pte); 354 pte = lookup_address(addr, &level);
351 else 355 if (pte)
352 pgprot_val(current_prot) = 0; 356 current_prot = pte_pgprot(*pte);
353 357 else
354 pgprot_val(prot) = pgprot_val(current_prot) & ~pgprot_val(prot); 358 pgprot_val(current_prot) = 0;
355 359
356 return change_page_attr_addr(addr, numpages, prot); 360 pgprot_val(prot) =
361 pgprot_val(current_prot) & ~pgprot_val(prot);
362
363 ret = change_page_attr_addr(addr, prot);
364 if (ret)
365 return ret;
366 addr += PAGE_SIZE;
367 }
368 return 0;
357} 369}
358 370
359int set_memory_uc(unsigned long addr, int numpages) 371int set_memory_uc(unsigned long addr, int numpages)