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.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 532e7933d606..6f2a6b6deb6b 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -255,6 +255,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
255 unsigned long pfn) 255 unsigned long pfn)
256{ 256{
257 pgprot_t forbidden = __pgprot(0); 257 pgprot_t forbidden = __pgprot(0);
258 pgprot_t required = __pgprot(0);
258 259
259 /* 260 /*
260 * The BIOS area between 640k and 1Mb needs to be executable for 261 * The BIOS area between 640k and 1Mb needs to be executable for
@@ -278,6 +279,12 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
278 if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT, 279 if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,
279 __pa((unsigned long)__end_rodata) >> PAGE_SHIFT)) 280 __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
280 pgprot_val(forbidden) |= _PAGE_RW; 281 pgprot_val(forbidden) |= _PAGE_RW;
282 /*
283 * .data and .bss should always be writable.
284 */
285 if (within(address, (unsigned long)_sdata, (unsigned long)_edata) ||
286 within(address, (unsigned long)__bss_start, (unsigned long)__bss_stop))
287 pgprot_val(required) |= _PAGE_RW;
281 288
282#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) 289#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
283 /* 290 /*
@@ -317,6 +324,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
317#endif 324#endif
318 325
319 prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); 326 prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
327 prot = __pgprot(pgprot_val(prot) | pgprot_val(required));
320 328
321 return prot; 329 return prot;
322} 330}
@@ -393,7 +401,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
393{ 401{
394 unsigned long nextpage_addr, numpages, pmask, psize, flags, addr, pfn; 402 unsigned long nextpage_addr, numpages, pmask, psize, flags, addr, pfn;
395 pte_t new_pte, old_pte, *tmp; 403 pte_t new_pte, old_pte, *tmp;
396 pgprot_t old_prot, new_prot; 404 pgprot_t old_prot, new_prot, req_prot;
397 int i, do_split = 1; 405 int i, do_split = 1;
398 unsigned int level; 406 unsigned int level;
399 407
@@ -438,10 +446,10 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
438 * We are safe now. Check whether the new pgprot is the same: 446 * We are safe now. Check whether the new pgprot is the same:
439 */ 447 */
440 old_pte = *kpte; 448 old_pte = *kpte;
441 old_prot = new_prot = pte_pgprot(old_pte); 449 old_prot = new_prot = req_prot = pte_pgprot(old_pte);
442 450
443 pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); 451 pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr);
444 pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); 452 pgprot_val(req_prot) |= pgprot_val(cpa->mask_set);
445 453
446 /* 454 /*
447 * old_pte points to the large page base address. So we need 455 * old_pte points to the large page base address. So we need
@@ -450,17 +458,17 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
450 pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT); 458 pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT);
451 cpa->pfn = pfn; 459 cpa->pfn = pfn;
452 460
453 new_prot = static_protections(new_prot, address, pfn); 461 new_prot = static_protections(req_prot, address, pfn);
454 462
455 /* 463 /*
456 * We need to check the full range, whether 464 * We need to check the full range, whether
457 * static_protection() requires a different pgprot for one of 465 * static_protection() requires a different pgprot for one of
458 * the pages in the range we try to preserve: 466 * the pages in the range we try to preserve:
459 */ 467 */
460 addr = address + PAGE_SIZE; 468 addr = address & pmask;
461 pfn++; 469 pfn = pte_pfn(old_pte);
462 for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE, pfn++) { 470 for (i = 0; i < (psize >> PAGE_SHIFT); i++, addr += PAGE_SIZE, pfn++) {
463 pgprot_t chk_prot = static_protections(new_prot, addr, pfn); 471 pgprot_t chk_prot = static_protections(req_prot, addr, pfn);
464 472
465 if (pgprot_val(chk_prot) != pgprot_val(new_prot)) 473 if (pgprot_val(chk_prot) != pgprot_val(new_prot))
466 goto out_unlock; 474 goto out_unlock;
@@ -483,7 +491,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
483 * that we limited the number of possible pages already to 491 * that we limited the number of possible pages already to
484 * the number of pages in the large page. 492 * the number of pages in the large page.
485 */ 493 */
486 if (address == (nextpage_addr - psize) && cpa->numpages == numpages) { 494 if (address == (address & pmask) && cpa->numpages == (psize >> PAGE_SHIFT)) {
487 /* 495 /*
488 * The address is aligned and the number of pages 496 * The address is aligned and the number of pages
489 * covers the full page. 497 * covers the full page.