diff options
-rw-r--r-- | arch/x86/mm/pageattr.c | 26 |
1 files changed, 18 insertions, 8 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 6a9a77a403c9..e14e95ea7338 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -516,7 +516,7 @@ static inline void check_conflict(int warnlvl, pgprot_t prot, pgprotval_t val, | |||
516 | */ | 516 | */ |
517 | static inline pgprot_t static_protections(pgprot_t prot, unsigned long start, | 517 | static inline pgprot_t static_protections(pgprot_t prot, unsigned long start, |
518 | unsigned long pfn, unsigned long npg, | 518 | unsigned long pfn, unsigned long npg, |
519 | int warnlvl) | 519 | unsigned long lpsize, int warnlvl) |
520 | { | 520 | { |
521 | pgprotval_t forbidden, res; | 521 | pgprotval_t forbidden, res; |
522 | unsigned long end; | 522 | unsigned long end; |
@@ -535,9 +535,17 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long start, | |||
535 | check_conflict(warnlvl, prot, res, start, end, pfn, "Text NX"); | 535 | check_conflict(warnlvl, prot, res, start, end, pfn, "Text NX"); |
536 | forbidden = res; | 536 | forbidden = res; |
537 | 537 | ||
538 | res = protect_kernel_text_ro(start, end); | 538 | /* |
539 | check_conflict(warnlvl, prot, res, start, end, pfn, "Text RO"); | 539 | * Special case to preserve a large page. If the change spawns the |
540 | forbidden |= res; | 540 | * full large page mapping then there is no point to split it |
541 | * up. Happens with ftrace and is going to be removed once ftrace | ||
542 | * switched to text_poke(). | ||
543 | */ | ||
544 | if (lpsize != (npg * PAGE_SIZE) || (start & (lpsize - 1))) { | ||
545 | res = protect_kernel_text_ro(start, end); | ||
546 | check_conflict(warnlvl, prot, res, start, end, pfn, "Text RO"); | ||
547 | forbidden |= res; | ||
548 | } | ||
541 | 549 | ||
542 | /* Check the PFN directly */ | 550 | /* Check the PFN directly */ |
543 | res = protect_pci_bios(pfn, pfn + npg - 1); | 551 | res = protect_pci_bios(pfn, pfn + npg - 1); |
@@ -819,7 +827,7 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address, | |||
819 | * extra conditional required here. | 827 | * extra conditional required here. |
820 | */ | 828 | */ |
821 | chk_prot = static_protections(old_prot, lpaddr, old_pfn, numpages, | 829 | chk_prot = static_protections(old_prot, lpaddr, old_pfn, numpages, |
822 | CPA_CONFLICT); | 830 | psize, CPA_CONFLICT); |
823 | 831 | ||
824 | if (WARN_ON_ONCE(pgprot_val(chk_prot) != pgprot_val(old_prot))) { | 832 | if (WARN_ON_ONCE(pgprot_val(chk_prot) != pgprot_val(old_prot))) { |
825 | /* | 833 | /* |
@@ -855,7 +863,7 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address, | |||
855 | * protection requirement in the large page. | 863 | * protection requirement in the large page. |
856 | */ | 864 | */ |
857 | new_prot = static_protections(req_prot, lpaddr, old_pfn, numpages, | 865 | new_prot = static_protections(req_prot, lpaddr, old_pfn, numpages, |
858 | CPA_DETECT); | 866 | psize, CPA_DETECT); |
859 | 867 | ||
860 | /* | 868 | /* |
861 | * If there is a conflict, split the large page. | 869 | * If there is a conflict, split the large page. |
@@ -906,7 +914,8 @@ static void split_set_pte(struct cpa_data *cpa, pte_t *pte, unsigned long pfn, | |||
906 | if (!cpa->force_static_prot) | 914 | if (!cpa->force_static_prot) |
907 | goto set; | 915 | goto set; |
908 | 916 | ||
909 | prot = static_protections(ref_prot, address, pfn, npg, CPA_PROTECT); | 917 | /* Hand in lpsize = 0 to enforce the protection mechanism */ |
918 | prot = static_protections(ref_prot, address, pfn, npg, 0, CPA_PROTECT); | ||
910 | 919 | ||
911 | if (pgprot_val(prot) == pgprot_val(ref_prot)) | 920 | if (pgprot_val(prot) == pgprot_val(ref_prot)) |
912 | goto set; | 921 | goto set; |
@@ -1503,7 +1512,8 @@ repeat: | |||
1503 | pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); | 1512 | pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); |
1504 | 1513 | ||
1505 | cpa_inc_4k_install(); | 1514 | cpa_inc_4k_install(); |
1506 | new_prot = static_protections(new_prot, address, pfn, 1, | 1515 | /* Hand in lpsize = 0 to enforce the protection mechanism */ |
1516 | new_prot = static_protections(new_prot, address, pfn, 1, 0, | ||
1507 | CPA_PROTECT); | 1517 | CPA_PROTECT); |
1508 | 1518 | ||
1509 | new_prot = pgprot_clear_protnone_bits(new_prot); | 1519 | new_prot = pgprot_clear_protnone_bits(new_prot); |