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, |