diff options
| -rw-r--r-- | arch/x86/mm/pageattr.c | 66 |
1 files changed, 23 insertions, 43 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 85cf12219dea..4d369d5c04c5 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
| @@ -512,6 +512,23 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) | |||
| 512 | #endif | 512 | #endif |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | static pgprot_t pgprot_clear_protnone_bits(pgprot_t prot) | ||
| 516 | { | ||
| 517 | /* | ||
| 518 | * _PAGE_GLOBAL means "global page" for present PTEs. | ||
| 519 | * But, it is also used to indicate _PAGE_PROTNONE | ||
| 520 | * for non-present PTEs. | ||
| 521 | * | ||
| 522 | * This ensures that a _PAGE_GLOBAL PTE going from | ||
| 523 | * present to non-present is not confused as | ||
| 524 | * _PAGE_PROTNONE. | ||
| 525 | */ | ||
| 526 | if (!(pgprot_val(prot) & _PAGE_PRESENT)) | ||
| 527 | pgprot_val(prot) &= ~_PAGE_GLOBAL; | ||
| 528 | |||
| 529 | return prot; | ||
| 530 | } | ||
| 531 | |||
| 515 | static int | 532 | static int |
| 516 | try_preserve_large_page(pte_t *kpte, unsigned long address, | 533 | try_preserve_large_page(pte_t *kpte, unsigned long address, |
| 517 | struct cpa_data *cpa) | 534 | struct cpa_data *cpa) |
| @@ -577,18 +594,11 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 577 | * different bit positions in the two formats. | 594 | * different bit positions in the two formats. |
| 578 | */ | 595 | */ |
| 579 | req_prot = pgprot_4k_2_large(req_prot); | 596 | req_prot = pgprot_4k_2_large(req_prot); |
| 580 | 597 | req_prot = pgprot_clear_protnone_bits(req_prot); | |
| 581 | /* | ||
| 582 | * Set the PSE and GLOBAL flags only if the PRESENT flag is | ||
| 583 | * set otherwise pmd_present/pmd_huge will return true even on | ||
| 584 | * a non present pmd. The canon_pgprot will clear _PAGE_GLOBAL | ||
| 585 | * for the ancient hardware that doesn't support it. | ||
| 586 | */ | ||
| 587 | if (pgprot_val(req_prot) & _PAGE_PRESENT) | 598 | if (pgprot_val(req_prot) & _PAGE_PRESENT) |
| 588 | pgprot_val(req_prot) |= _PAGE_PSE | _PAGE_GLOBAL; | 599 | pgprot_val(req_prot) |= _PAGE_PSE; |
| 589 | else | 600 | else |
| 590 | pgprot_val(req_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL); | 601 | pgprot_val(req_prot) &= ~_PAGE_PSE; |
| 591 | |||
| 592 | req_prot = canon_pgprot(req_prot); | 602 | req_prot = canon_pgprot(req_prot); |
| 593 | 603 | ||
| 594 | /* | 604 | /* |
| @@ -698,16 +708,7 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, | |||
| 698 | return 1; | 708 | return 1; |
| 699 | } | 709 | } |
| 700 | 710 | ||
| 701 | /* | 711 | ref_prot = pgprot_clear_protnone_bits(ref_prot); |
| 702 | * Set the GLOBAL flags only if the PRESENT flag is set | ||
| 703 | * otherwise pmd/pte_present will return true even on a non | ||
| 704 | * present pmd/pte. The canon_pgprot will clear _PAGE_GLOBAL | ||
| 705 | * for the ancient hardware that doesn't support it. | ||
| 706 | */ | ||
| 707 | if (pgprot_val(ref_prot) & _PAGE_PRESENT) | ||
| 708 | pgprot_val(ref_prot) |= _PAGE_GLOBAL; | ||
| 709 | else | ||
| 710 | pgprot_val(ref_prot) &= ~_PAGE_GLOBAL; | ||
| 711 | 712 | ||
| 712 | /* | 713 | /* |
| 713 | * Get the target pfn from the original entry: | 714 | * Get the target pfn from the original entry: |
| @@ -930,18 +931,7 @@ static void populate_pte(struct cpa_data *cpa, | |||
| 930 | 931 | ||
| 931 | pte = pte_offset_kernel(pmd, start); | 932 | pte = pte_offset_kernel(pmd, start); |
| 932 | 933 | ||
| 933 | /* | 934 | pgprot = pgprot_clear_protnone_bits(pgprot); |
| 934 | * Set the GLOBAL flags only if the PRESENT flag is | ||
| 935 | * set otherwise pte_present will return true even on | ||
| 936 | * a non present pte. The canon_pgprot will clear | ||
| 937 | * _PAGE_GLOBAL for the ancient hardware that doesn't | ||
| 938 | * support it. | ||
| 939 | */ | ||
| 940 | if (pgprot_val(pgprot) & _PAGE_PRESENT) | ||
| 941 | pgprot_val(pgprot) |= _PAGE_GLOBAL; | ||
| 942 | else | ||
| 943 | pgprot_val(pgprot) &= ~_PAGE_GLOBAL; | ||
| 944 | |||
| 945 | pgprot = canon_pgprot(pgprot); | 935 | pgprot = canon_pgprot(pgprot); |
| 946 | 936 | ||
| 947 | while (num_pages-- && start < end) { | 937 | while (num_pages-- && start < end) { |
| @@ -1234,17 +1224,7 @@ repeat: | |||
| 1234 | 1224 | ||
| 1235 | new_prot = static_protections(new_prot, address, pfn); | 1225 | new_prot = static_protections(new_prot, address, pfn); |
| 1236 | 1226 | ||
| 1237 | /* | 1227 | new_prot = pgprot_clear_protnone_bits(new_prot); |
| 1238 | * Set the GLOBAL flags only if the PRESENT flag is | ||
| 1239 | * set otherwise pte_present will return true even on | ||
| 1240 | * a non present pte. The canon_pgprot will clear | ||
| 1241 | * _PAGE_GLOBAL for the ancient hardware that doesn't | ||
| 1242 | * support it. | ||
| 1243 | */ | ||
| 1244 | if (pgprot_val(new_prot) & _PAGE_PRESENT) | ||
| 1245 | pgprot_val(new_prot) |= _PAGE_GLOBAL; | ||
| 1246 | else | ||
| 1247 | pgprot_val(new_prot) &= ~_PAGE_GLOBAL; | ||
| 1248 | 1228 | ||
| 1249 | /* | 1229 | /* |
| 1250 | * We need to keep the pfn from the existing PTE, | 1230 | * We need to keep the pfn from the existing PTE, |
