diff options
-rw-r--r-- | arch/x86/mm/pageattr.c | 33 |
1 files changed, 23 insertions, 10 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index de807c9daad1..6c8e3fdaf077 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -485,14 +485,23 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
485 | 485 | ||
486 | /* | 486 | /* |
487 | * We are safe now. Check whether the new pgprot is the same: | 487 | * We are safe now. Check whether the new pgprot is the same: |
488 | * Convert protection attributes to 4k-format, as cpa->mask* are set | ||
489 | * up accordingly. | ||
488 | */ | 490 | */ |
489 | old_pte = *kpte; | 491 | old_pte = *kpte; |
490 | old_prot = req_prot = pte_pgprot(old_pte); | 492 | old_prot = req_prot = pgprot_large_2_4k(pte_pgprot(old_pte)); |
491 | 493 | ||
492 | pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr); | 494 | pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr); |
493 | pgprot_val(req_prot) |= pgprot_val(cpa->mask_set); | 495 | pgprot_val(req_prot) |= pgprot_val(cpa->mask_set); |
494 | 496 | ||
495 | /* | 497 | /* |
498 | * req_prot is in format of 4k pages. It must be converted to large | ||
499 | * page format: the caching mode includes the PAT bit located at | ||
500 | * different bit positions in the two formats. | ||
501 | */ | ||
502 | req_prot = pgprot_4k_2_large(req_prot); | ||
503 | |||
504 | /* | ||
496 | * Set the PSE and GLOBAL flags only if the PRESENT flag is | 505 | * Set the PSE and GLOBAL flags only if the PRESENT flag is |
497 | * set otherwise pmd_present/pmd_huge will return true even on | 506 | * set otherwise pmd_present/pmd_huge will return true even on |
498 | * a non present pmd. The canon_pgprot will clear _PAGE_GLOBAL | 507 | * a non present pmd. The canon_pgprot will clear _PAGE_GLOBAL |
@@ -585,13 +594,10 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, | |||
585 | 594 | ||
586 | paravirt_alloc_pte(&init_mm, page_to_pfn(base)); | 595 | paravirt_alloc_pte(&init_mm, page_to_pfn(base)); |
587 | ref_prot = pte_pgprot(pte_clrhuge(*kpte)); | 596 | ref_prot = pte_pgprot(pte_clrhuge(*kpte)); |
588 | /* | 597 | |
589 | * If we ever want to utilize the PAT bit, we need to | 598 | /* promote PAT bit to correct position */ |
590 | * update this function to make sure it's converted from | 599 | if (level == PG_LEVEL_2M) |
591 | * bit 12 to bit 7 when we cross from the 2MB level to | 600 | ref_prot = pgprot_large_2_4k(ref_prot); |
592 | * the 4K level: | ||
593 | */ | ||
594 | WARN_ON_ONCE(pgprot_val(ref_prot) & _PAGE_PAT_LARGE); | ||
595 | 601 | ||
596 | #ifdef CONFIG_X86_64 | 602 | #ifdef CONFIG_X86_64 |
597 | if (level == PG_LEVEL_1G) { | 603 | if (level == PG_LEVEL_1G) { |
@@ -879,6 +885,7 @@ static int populate_pmd(struct cpa_data *cpa, | |||
879 | { | 885 | { |
880 | unsigned int cur_pages = 0; | 886 | unsigned int cur_pages = 0; |
881 | pmd_t *pmd; | 887 | pmd_t *pmd; |
888 | pgprot_t pmd_pgprot; | ||
882 | 889 | ||
883 | /* | 890 | /* |
884 | * Not on a 2M boundary? | 891 | * Not on a 2M boundary? |
@@ -910,6 +917,8 @@ static int populate_pmd(struct cpa_data *cpa, | |||
910 | if (num_pages == cur_pages) | 917 | if (num_pages == cur_pages) |
911 | return cur_pages; | 918 | return cur_pages; |
912 | 919 | ||
920 | pmd_pgprot = pgprot_4k_2_large(pgprot); | ||
921 | |||
913 | while (end - start >= PMD_SIZE) { | 922 | while (end - start >= PMD_SIZE) { |
914 | 923 | ||
915 | /* | 924 | /* |
@@ -921,7 +930,8 @@ static int populate_pmd(struct cpa_data *cpa, | |||
921 | 930 | ||
922 | pmd = pmd_offset(pud, start); | 931 | pmd = pmd_offset(pud, start); |
923 | 932 | ||
924 | set_pmd(pmd, __pmd(cpa->pfn | _PAGE_PSE | massage_pgprot(pgprot))); | 933 | set_pmd(pmd, __pmd(cpa->pfn | _PAGE_PSE | |
934 | massage_pgprot(pmd_pgprot))); | ||
925 | 935 | ||
926 | start += PMD_SIZE; | 936 | start += PMD_SIZE; |
927 | cpa->pfn += PMD_SIZE; | 937 | cpa->pfn += PMD_SIZE; |
@@ -949,6 +959,7 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd, | |||
949 | pud_t *pud; | 959 | pud_t *pud; |
950 | unsigned long end; | 960 | unsigned long end; |
951 | int cur_pages = 0; | 961 | int cur_pages = 0; |
962 | pgprot_t pud_pgprot; | ||
952 | 963 | ||
953 | end = start + (cpa->numpages << PAGE_SHIFT); | 964 | end = start + (cpa->numpages << PAGE_SHIFT); |
954 | 965 | ||
@@ -986,12 +997,14 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd, | |||
986 | return cur_pages; | 997 | return cur_pages; |
987 | 998 | ||
988 | pud = pud_offset(pgd, start); | 999 | pud = pud_offset(pgd, start); |
1000 | pud_pgprot = pgprot_4k_2_large(pgprot); | ||
989 | 1001 | ||
990 | /* | 1002 | /* |
991 | * Map everything starting from the Gb boundary, possibly with 1G pages | 1003 | * Map everything starting from the Gb boundary, possibly with 1G pages |
992 | */ | 1004 | */ |
993 | while (end - start >= PUD_SIZE) { | 1005 | while (end - start >= PUD_SIZE) { |
994 | set_pud(pud, __pud(cpa->pfn | _PAGE_PSE | massage_pgprot(pgprot))); | 1006 | set_pud(pud, __pud(cpa->pfn | _PAGE_PSE | |
1007 | massage_pgprot(pud_pgprot))); | ||
995 | 1008 | ||
996 | start += PUD_SIZE; | 1009 | start += PUD_SIZE; |
997 | cpa->pfn += PUD_SIZE; | 1010 | cpa->pfn += PUD_SIZE; |